Document reserved keys
[emacs.git] / lisp / progmodes / prolog.el
bloba895a777968d06cce0ab90a2eb0dadcdce25a507
1 ;;; prolog.el --- major mode for Prolog (and Mercury) -*- lexical-binding:t -*-
3 ;; Copyright (C) 1986-1987, 1997-1999, 2002-2003, 2011-2018 Free
4 ;; Software Foundation, Inc.
6 ;; Authors: Emil Åström <emil_astrom(at)hotmail(dot)com>
7 ;; Milan Zamazal <pdm(at)freesoft(dot)cz>
8 ;; Stefan Bruda <stefan(at)bruda(dot)ca>
9 ;; * See below for more details
10 ;; Maintainer: Stefan Bruda <stefan(at)bruda(dot)ca>
11 ;; Keywords: prolog major mode sicstus swi mercury
13 (defvar prolog-mode-version "1.22"
14 "Prolog mode version number.")
16 ;; This file is part of GNU Emacs.
18 ;; GNU Emacs is free software: you can redistribute it and/or modify
19 ;; it under the terms of the GNU General Public License as published by
20 ;; the Free Software Foundation, either version 3 of the License, or
21 ;; (at your option) any later version.
23 ;; GNU Emacs is distributed in the hope that it will be useful,
24 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
25 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 ;; GNU General Public License for more details.
28 ;; You should have received a copy of the GNU General Public License
29 ;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
31 ;; Original author: Masanobu UMEDA <umerin(at)mse(dot)kyutech(dot)ac(dot)jp>
32 ;; Parts of this file was taken from a modified version of the original
33 ;; by Johan Andersson, Peter Olin, Mats Carlsson, Johan Bevemyr, Stefan
34 ;; Andersson, and Per Danielsson (all SICS people), and Henrik Båkman
35 ;; at Uppsala University, Sweden.
37 ;; Some ideas and also a few lines of code have been borrowed (not stolen ;-)
38 ;; from Oz.el, the Emacs major mode for the Oz programming language,
39 ;; Copyright (C) 1993 DFKI GmbH, Germany, with permission.
40 ;; Authored by Ralf Scheidhauer and Michael Mehl
41 ;; ([scheidhr|mehl](at)dfki(dot)uni-sb(dot)de)
43 ;; More ideas and code have been taken from the SICStus debugger mode
44 ;; (http://www.csd.uu.se/~perm/source_debug/index.shtml -- broken link
45 ;; as of Mon May 5 08:23:48 EDT 2003) by Per Mildner.
47 ;; Additions for ECLiPSe and other helpful suggestions: Stephan Heuel
48 ;; <heuel(at)ipb(dot)uni-bonn(dot)de>
50 ;;; Commentary:
52 ;; This package provides a major mode for editing Prolog code, with
53 ;; all the bells and whistles one would expect, including syntax
54 ;; highlighting and auto indentation. It can also send regions to an
55 ;; inferior Prolog process.
57 ;; Some settings you may wish to use:
59 ;; (setq prolog-system 'swi) ; optional, the system you are using;
60 ;; ; see `prolog-system' below for possible values
61 ;; (setq auto-mode-alist (append '(("\\.pl\\'" . prolog-mode)
62 ;; ("\\.m\\'" . mercury-mode))
63 ;; auto-mode-alist))
65 ;; The last expression above makes sure that files ending with .pl
66 ;; are assumed to be Prolog files and not Perl, which is the default
67 ;; Emacs setting. If this is not wanted, remove this line. It is then
68 ;; necessary to either
70 ;; o insert in your Prolog files the following comment as the first line:
72 ;; % -*- Mode: Prolog -*-
74 ;; and then the file will be open in Prolog mode no matter its
75 ;; extension, or
77 ;; o manually switch to prolog mode after opening a Prolog file, by typing
78 ;; M-x prolog-mode.
80 ;; If the command to start the prolog process ('sicstus', 'pl' or
81 ;; 'swipl' for SWI prolog, etc.) is not available in the default path,
82 ;; then it is necessary to set the value of the environment variable
83 ;; EPROLOG to a shell command to invoke the prolog process.
84 ;; You can also customize the variable
85 ;; `prolog-program-name' (in the group `prolog-inferior') and provide
86 ;; a full path for your Prolog system (swi, scitus, etc.).
88 ;; Note: I (Stefan, the current maintainer) work under XEmacs. Future
89 ;; developments will thus be biased towards XEmacs (OK, I admit it,
90 ;; I am biased towards XEmacs in general), though I will do my best
91 ;; to keep the GNU Emacs compatibility. So if you work under Emacs
92 ;; and see something that does not work do drop me a line, as I have
93 ;; a smaller chance to notice this kind of bugs otherwise.
94 ; [The above comment dates from 2011.]
96 ;; Changelog:
98 ;; Version 1.22:
99 ;; o Allowed both 'swipl' and 'pl' as names for the SWI Prolog
100 ;; interpreter.
101 ;; o Atoms that start a line are not blindly colored as
102 ;; predicates. Instead we check that they are followed by ( or
103 ;; :- first. Patch suggested by Guy Wiener.
104 ;; Version 1.21:
105 ;; o Cleaned up the code that defines faces. The missing face
106 ;; warnings on some Emacsen should disappear.
107 ;; Version 1.20:
108 ;; o Improved the handling of clause start detection and multi-line
109 ;; comments: `prolog-clause-start' no longer finds non-predicate
110 ;; (e.g., capitalized strings) beginning of clauses.
111 ;; `prolog-tokenize' recognizes when the end point is within a
112 ;; multi-line comment.
113 ;; Version 1.19:
114 ;; o Minimal changes for Aquamacs inclusion and in general for
115 ;; better coping with finding the Prolog executable. Patch
116 ;; provided by David Reitter
117 ;; Version 1.18:
118 ;; o Fixed syntax highlighting for clause heads that do not begin at
119 ;; the beginning of the line.
120 ;; o Fixed compilation warnings under Emacs.
121 ;; o Updated the email address of the current maintainer.
122 ;; Version 1.17:
123 ;; o Minor indentation fix (patch by Markus Triska)
124 ;; o `prolog-underscore-wordchar-flag' defaults now to nil (more
125 ;; consistent to other Emacs modes)
126 ;; Version 1.16:
127 ;; o Eliminated a possible compilation warning.
128 ;; Version 1.15:
129 ;; o Introduced three new customizable variables: electric colon
130 ;; (`prolog-electric-colon-flag', default nil), electric dash
131 ;; (`prolog-electric-dash-flag', default nil), and a possibility
132 ;; to prevent the predicate template insertion from adding commas
133 ;; (`prolog-electric-dot-full-predicate-template', defaults to t
134 ;; since it seems quicker to me to just type those commas). A
135 ;; trivial adaptation of a patch by Markus Triska.
136 ;; o Improved the behavior of electric if-then-else to only skip
137 ;; forward if the parenthesis/semicolon is preceded by
138 ;; whitespace. Once more a trivial adaptation of a patch by
139 ;; Markus Triska.
140 ;; Version 1.14:
141 ;; o Cleaned up align code. `prolog-align-flag' is eliminated (since
142 ;; on a second thought it does not do anything useful). Added key
143 ;; binding (C-c C-a) and menu entry for alignment.
144 ;; o Condensed regular expressions for lower and upper case
145 ;; characters (GNU Emacs seems to go over the regexp length limit
146 ;; with the original form). My code on the matter was improved
147 ;; considerably by Markus Triska.
148 ;; o Fixed `prolog-insert-spaces-after-paren' (which used an
149 ;; uninitialized variable).
150 ;; o Minor changes to clean up the code and avoid some implicit
151 ;; package requirements.
152 ;; Version 1.13:
153 ;; o Removed the use of `map-char-table' in `prolog-build-case-strings'
154 ;; which appears to cause problems in (at least) Emacs 23.0.0.1.
155 ;; o Added if-then-else indentation + corresponding electric
156 ;; characters. New customization: `prolog-electric-if-then-else-flag'
157 ;; o Align support (requires `align'). New customization:
158 ;; `prolog-align-flag'.
159 ;; o Temporary consult files have now the same name throughout the
160 ;; session. This prevents issues with reconsulting a buffer
161 ;; (this event is no longer passed to Prolog as a request to
162 ;; consult a new file).
163 ;; o Adaptive fill mode is now turned on. Comment indentation is
164 ;; still worse than it could be though, I am working on it.
165 ;; o Improved filling and auto-filling capabilities. Now block
166 ;; comments should be [auto-]filled correctly most of the time;
167 ;; the following pattern in particular is worth noting as being
168 ;; filled correctly:
169 ;; <some code here> % some comment here that goes beyond the
170 ;; % rightmost column, possibly combined with
171 ;; % subsequent comment lines
172 ;; o `prolog-char-quote-workaround' now defaults to nil.
173 ;; o Note: Many of the above improvements have been suggested by
174 ;; Markus Triska, who also provided useful patches on the matter
175 ;; when he realized that I was slow in responding. Many thanks.
176 ;; Version 1.11 / 1.12
177 ;; o GNU Emacs compatibility fix for paragraph filling (fixed
178 ;; incorrectly in 1.11, fix fixed in 1.12).
179 ;; Version 1.10
180 ;; o Added paragraph filling in comment blocks and also correct auto
181 ;; filling for comments.
182 ;; o Fixed the possible "Regular expression too big" error in
183 ;; `prolog-electric-dot'.
184 ;; Version 1.9
185 ;; o Parenthesis expressions are now indented by default so that
186 ;; components go one underneath the other, just as for compound
187 ;; terms. You can use the old style (the second and subsequent
188 ;; lines being indented to the right in a parenthesis expression)
189 ;; by setting the customizable variable `prolog-paren-indent-p'
190 ;; (group "Prolog Indentation") to t.
191 ;; o (Somehow awkward) handling of the 0' character escape
192 ;; sequence. I am looking into a better way of doing it but
193 ;; prospects look bleak. If this breaks things for you please let
194 ;; me know and also set the `prolog-char-quote-workaround' (group
195 ;; "Prolog Other") to nil.
196 ;; Version 1.8
197 ;; o Key binding fix.
198 ;; Version 1.7
199 ;; o Fixed a number of issues with the syntax of single quotes,
200 ;; including Debian bug #324520.
201 ;; Version 1.6
202 ;; o Fixed mercury mode menu initialization (Debian bug #226121).
203 ;; o Fixed (i.e., eliminated) Delete remapping (Debian bug #229636).
204 ;; o Corrected indentation for clauses defining quoted atoms.
205 ;; Version 1.5:
206 ;; o Keywords fontifying should work in console mode so this is
207 ;; enabled everywhere.
208 ;; Version 1.4:
209 ;; o Now supports GNU Prolog--minor adaptation of a patch by Stefan
210 ;; Moeding.
211 ;; Version 1.3:
212 ;; o Info-follow-nearest-node now called correctly under Emacs too
213 ;; (thanks to Nicolas Pelletier). Should be implemented more
214 ;; elegantly (i.e., without compilation warnings) in the future.
215 ;; Version 1.2:
216 ;; o Another prompt fix, still in SWI mode (people seem to have
217 ;; changed the prompt of SWI Prolog).
218 ;; Version 1.1:
219 ;; o Fixed dots in the end of line comments causing indentation
220 ;; problems. The following code is now correctly indented (note
221 ;; the dot terminating the comment):
222 ;; a(X) :- b(X),
223 ;; c(X). % comment here.
224 ;; a(X).
225 ;; and so is this (and variants):
226 ;; a(X) :- b(X),
227 ;; c(X). /* comment here. */
228 ;; a(X).
229 ;; Version 1.0:
230 ;; o Revamped the menu system.
231 ;; o Yet another prompt recognition fix (SWI mode).
232 ;; o This is more of a renumbering than a new edition. I promoted
233 ;; the mode to version 1.0 to emphasize the fact that it is now
234 ;; mature and stable enough to be considered production (in my
235 ;; opinion anyway).
236 ;; Version 0.1.41:
237 ;; o GNU Emacs compatibility fixes.
238 ;; Version 0.1.40:
239 ;; o prolog-get-predspec is now suitable to be called as
240 ;; imenu-extract-index-name-function. The predicate index works.
241 ;; o Since imenu works now as advertised, prolog-imenu-flag is t
242 ;; by default.
243 ;; o Eliminated prolog-create-predicate-index since the imenu
244 ;; utilities now work well. Actually, this function is also
245 ;; buggy, and I see no reason to fix it since we do not need it
246 ;; anyway.
247 ;; o Fixed prolog-pred-start, prolog-clause-start, prolog-clause-info.
248 ;; o Fix for prolog-build-case-strings; now prolog-upper-case-string
249 ;; and prolog-lower-case-string are correctly initialized,
250 ;; o Various font-lock changes; most importantly, block comments (/*
251 ;; ... */) are now correctly fontified in XEmacs even when they
252 ;; extend on multiple lines.
253 ;; Version 0.1.36:
254 ;; o The debug prompt of SWI Prolog is now correctly recognized.
255 ;; Version 0.1.35:
256 ;; o Minor font-lock bug fixes.
259 ;;; Code:
261 (require 'comint)
263 (eval-when-compile
264 (require 'font-lock)
265 ;; We need imenu everywhere because of the predicate index!
266 (require 'imenu)
268 (require 'shell)
271 (require 'easymenu)
272 (require 'align)
274 (eval-when-compile
275 (or (fboundp 'use-region-p)
276 (defsubst use-region-p () (region-exists-p))))
278 (defgroup prolog nil
279 "Editing and running Prolog and Mercury files."
280 :group 'languages)
282 (defgroup prolog-faces nil
283 "Prolog mode specific faces."
284 :group 'font-lock)
286 (defgroup prolog-indentation nil
287 "Prolog mode indentation configuration."
288 :group 'prolog)
290 (defgroup prolog-font-lock nil
291 "Prolog mode font locking patterns."
292 :group 'prolog)
294 (defgroup prolog-keyboard nil
295 "Prolog mode keyboard flags."
296 :group 'prolog)
298 (defgroup prolog-inferior nil
299 "Inferior Prolog mode options."
300 :group 'prolog)
302 (defgroup prolog-other nil
303 "Other Prolog mode options."
304 :group 'prolog)
307 ;;-------------------------------------------------------------------
308 ;; User configurable variables
309 ;;-------------------------------------------------------------------
311 ;; General configuration
313 (defcustom prolog-system nil
314 "Prolog interpreter/compiler used.
315 The value of this variable is nil or a symbol.
316 If it is a symbol, it determines default values of other configuration
317 variables with respect to properties of the specified Prolog
318 interpreter/compiler.
320 Currently recognized symbol values are:
321 eclipse - Eclipse Prolog
322 mercury - Mercury
323 sicstus - SICStus Prolog
324 swi - SWI Prolog
325 gnu - GNU Prolog"
326 :version "24.1"
327 :group 'prolog
328 :type '(choice (const :tag "SICStus" :value sicstus)
329 (const :tag "SWI Prolog" :value swi)
330 (const :tag "GNU Prolog" :value gnu)
331 (const :tag "ECLiPSe Prolog" :value eclipse)
332 ;; Mercury shouldn't be needed since we have a separate
333 ;; major mode for it.
334 (const :tag "Default" :value nil)))
335 (make-variable-buffer-local 'prolog-system)
337 ;; NB: This alist can not be processed in prolog-mode-variables to
338 ;; create a prolog-system-version-i variable since it is needed
339 ;; prior to the call to prolog-mode-variables.
340 (defcustom prolog-system-version
341 '((sicstus (3 . 6))
342 (swi (0 . 0))
343 (mercury (0 . 0))
344 (eclipse (3 . 7))
345 (gnu (0 . 0)))
346 ;; FIXME: This should be auto-detected instead of user-provided.
347 "Alist of Prolog system versions.
348 The version numbers are of the format (Major . Minor)."
349 :version "24.1"
350 :type '(repeat (list (symbol :tag "System")
351 (cons :tag "Version numbers" (integer :tag "Major")
352 (integer :tag "Minor"))))
353 :risky t
354 :group 'prolog)
356 ;; Indentation
358 (defcustom prolog-indent-width 4
359 "The indentation width used by the editing buffer."
360 :group 'prolog-indentation
361 :type 'integer
362 :safe 'integerp)
364 (defcustom prolog-left-indent-regexp "\\(;\\|\\*?->\\)"
365 "Regexp for `prolog-electric-if-then-else-flag'."
366 :version "24.1"
367 :group 'prolog-indentation
368 :type 'regexp
369 :safe 'stringp)
371 (defcustom prolog-paren-indent-p nil
372 "If non-nil, increase indentation for parenthesis expressions.
373 The second and subsequent line in a parenthesis expression other than
374 a compound term can either be indented `prolog-paren-indent' to the
375 right (if this variable is non-nil) or in the same way as for compound
376 terms (if this variable is nil, default)."
377 :version "24.1"
378 :group 'prolog-indentation
379 :type 'boolean
380 :safe 'booleanp)
382 (defcustom prolog-paren-indent 4
383 "The indentation increase for parenthesis expressions.
384 Only used in ( If -> Then ; Else) and ( Disj1 ; Disj2 ) style expressions."
385 :version "24.1"
386 :group 'prolog-indentation
387 :type 'integer
388 :safe 'integerp)
390 (defcustom prolog-parse-mode 'beg-of-clause
391 "The parse mode used (decides from which point parsing is done).
392 Legal values:
393 `beg-of-line' - starts parsing at the beginning of a line, unless the
394 previous line ends with a backslash. Fast, but has
395 problems detecting multiline /* */ comments.
396 `beg-of-clause' - starts parsing at the beginning of the current clause.
397 Slow, but copes better with /* */ comments."
398 :version "24.1"
399 :group 'prolog-indentation
400 :type '(choice (const :value beg-of-line)
401 (const :value beg-of-clause)))
403 ;; Font locking
405 (defcustom prolog-keywords
406 '((eclipse
407 ("use_module" "begin_module" "module_interface" "dynamic"
408 "external" "export" "dbgcomp" "nodbgcomp" "compile"))
409 (mercury
410 ("all" "else" "end_module" "equality" "external" "fail" "func" "if"
411 "implementation" "import_module" "include_module" "inst" "instance"
412 "interface" "mode" "module" "not" "pragma" "pred" "some" "then" "true"
413 "type" "typeclass" "use_module" "where"))
414 (sicstus
415 ("block" "dynamic" "mode" "module" "multifile" "meta_predicate"
416 "parallel" "public" "sequential" "volatile"))
417 (swi
418 ("discontiguous" "dynamic" "ensure_loaded" "export" "export_list" "import"
419 "meta_predicate" "module" "module_transparent" "multifile" "require"
420 "use_module" "volatile"))
421 (gnu
422 ("built_in" "char_conversion" "discontiguous" "dynamic" "ensure_linked"
423 "ensure_loaded" "foreign" "include" "initialization" "multifile" "op"
424 "public" "set_prolog_flag"))
426 ;; FIXME: Shouldn't we just use the union of all the above here?
427 ("dynamic" "module")))
428 "Alist of Prolog keywords which is used for font locking of directives."
429 :version "24.1"
430 :group 'prolog-font-lock
431 ;; Note that "(repeat string)" also allows "nil" (repeat-count 0).
432 ;; This gets processed by prolog-find-value-by-system, which
433 ;; allows both the car and the cdr to be a list to eval.
434 ;; Though the latter must have the form '(eval ...)'.
435 ;; Of course, none of this is documented...
436 :type '(repeat (list (choice symbol sexp) (choice (repeat string) sexp)))
437 :risky t)
439 (defcustom prolog-types
440 '((mercury
441 ("char" "float" "int" "io__state" "string" "univ"))
442 (t nil))
443 "Alist of Prolog types used by font locking."
444 :version "24.1"
445 :group 'prolog-font-lock
446 :type '(repeat (list (choice symbol sexp) (choice (repeat string) sexp)))
447 :risky t)
449 (defcustom prolog-mode-specificators
450 '((mercury
451 ("bound" "di" "free" "ground" "in" "mdi" "mui" "muo" "out" "ui" "uo"))
452 (t nil))
453 "Alist of Prolog mode specificators used by font locking."
454 :version "24.1"
455 :group 'prolog-font-lock
456 :type '(repeat (list (choice symbol sexp) (choice (repeat string) sexp)))
457 :risky t)
459 (defcustom prolog-determinism-specificators
460 '((mercury
461 ("cc_multi" "cc_nondet" "det" "erroneous" "failure" "multi" "nondet"
462 "semidet"))
463 (t nil))
464 "Alist of Prolog determinism specificators used by font locking."
465 :version "24.1"
466 :group 'prolog-font-lock
467 :type '(repeat (list (choice symbol sexp) (choice (repeat string) sexp)))
468 :risky t)
470 (defcustom prolog-directives
471 '((mercury
472 ("^#[0-9]+"))
473 (t nil))
474 "Alist of Prolog source code directives used by font locking."
475 :version "24.1"
476 :group 'prolog-font-lock
477 :type '(repeat (list (choice symbol sexp) (choice (repeat string) sexp)))
478 :risky t)
481 ;; Keyboard
483 (defcustom prolog-hungry-delete-key-flag nil
484 "Non-nil means delete key consumes all preceding spaces."
485 :version "24.1"
486 :group 'prolog-keyboard
487 :type 'boolean)
489 (defcustom prolog-electric-dot-flag nil
490 "Non-nil means make dot key electric.
491 Electric dot appends newline or inserts head of a new clause.
492 If dot is pressed at the end of a line where at least one white space
493 precedes the point, it inserts a recursive call to the current predicate.
494 If dot is pressed at the beginning of an empty line, it inserts the head
495 of a new clause for the current predicate. It does not apply in strings
496 and comments.
497 It does not apply in strings and comments."
498 :version "24.1"
499 :group 'prolog-keyboard
500 :type 'boolean)
502 (defcustom prolog-electric-dot-full-predicate-template nil
503 "If nil, electric dot inserts only the current predicate's name and `('
504 for recursive calls or new clause heads. Non-nil means to also
505 insert enough commas to cover the predicate's arity and `)',
506 and dot and newline for recursive calls."
507 :version "24.1"
508 :group 'prolog-keyboard
509 :type 'boolean)
511 (defcustom prolog-electric-underscore-flag nil
512 "Non-nil means make underscore key electric.
513 Electric underscore replaces the current variable with underscore.
514 If underscore is pressed not on a variable then it behaves as usual."
515 :version "24.1"
516 :group 'prolog-keyboard
517 :type 'boolean)
519 (defcustom prolog-electric-if-then-else-flag nil
520 "Non-nil makes `(', `>' and `;' electric
521 to automatically indent if-then-else constructs."
522 :version "24.1"
523 :group 'prolog-keyboard
524 :type 'boolean)
526 (defcustom prolog-electric-colon-flag nil
527 "Makes `:' electric (inserts `:-' on a new line).
528 If non-nil, pressing `:' at the end of a line that starts in
529 the first column (i.e., clause heads) inserts ` :-' and newline."
530 :version "24.1"
531 :group 'prolog-keyboard
532 :type 'boolean)
534 (defcustom prolog-electric-dash-flag nil
535 "Makes `-' electric (inserts a `-->' on a new line).
536 If non-nil, pressing `-' at the end of a line that starts in
537 the first column (i.e., DCG heads) inserts ` -->' and newline."
538 :version "24.1"
539 :group 'prolog-keyboard
540 :type 'boolean)
542 (defcustom prolog-old-sicstus-keys-flag nil
543 "Non-nil means old SICStus Prolog mode keybindings are used."
544 :version "24.1"
545 :group 'prolog-keyboard
546 :type 'boolean)
548 ;; Inferior mode
550 (defcustom prolog-program-name
551 `(((getenv "EPROLOG") (eval (getenv "EPROLOG")))
552 (eclipse "eclipse")
553 (mercury nil)
554 (sicstus "sicstus")
555 (swi ,(if (not (executable-find "swipl")) "pl" "swipl"))
556 (gnu "gprolog")
557 (t ,(let ((names '("prolog" "gprolog" "swipl" "pl")))
558 (while (and names
559 (not (executable-find (car names))))
560 (setq names (cdr names)))
561 (or (car names) "prolog"))))
562 "Alist of program names for invoking an inferior Prolog with `run-prolog'."
563 :group 'prolog-inferior
564 :type '(alist :key-type (choice symbol sexp)
565 :value-type (group (choice string (const nil) sexp)))
566 :risky t)
567 (defun prolog-program-name ()
568 (prolog-find-value-by-system prolog-program-name))
570 (defcustom prolog-program-switches
571 '((sicstus ("-i"))
572 (t nil))
573 "Alist of switches given to inferior Prolog run with `run-prolog'."
574 :version "24.1"
575 :group 'prolog-inferior
576 :type '(repeat (list (choice symbol sexp) (choice (repeat string) sexp)))
577 :risky t)
578 (defun prolog-program-switches ()
579 (prolog-find-value-by-system prolog-program-switches))
581 (defcustom prolog-consult-string
582 '((eclipse "[%f].")
583 (mercury nil)
584 (sicstus (eval (if (prolog-atleast-version '(3 . 7))
585 "prolog:zap_file(%m,%b,consult,%l)."
586 "prolog:zap_file(%m,%b,consult).")))
587 (swi "[%f].")
588 (gnu "[%f].")
589 (t "reconsult(%f)."))
590 "Alist of strings defining predicate for reconsulting.
592 Some parts of the string are replaced:
593 `%f' by the name of the consulted file (can be a temporary file)
594 `%b' by the file name of the buffer to consult
595 `%m' by the module name and name of the consulted file separated by colon
596 `%l' by the line offset into the file. This is 0 unless consulting a
597 region of a buffer, in which case it is the number of lines before
598 the region."
599 :group 'prolog-inferior
600 :type '(alist :key-type (choice symbol sexp)
601 :value-type (group (choice string (const nil) sexp)))
602 :risky t)
604 (defun prolog-consult-string ()
605 (prolog-find-value-by-system prolog-consult-string))
607 (defcustom prolog-compile-string
608 '((eclipse "[%f].")
609 (mercury "mmake ")
610 (sicstus (eval (if (prolog-atleast-version '(3 . 7))
611 "prolog:zap_file(%m,%b,compile,%l)."
612 "prolog:zap_file(%m,%b,compile).")))
613 (swi "[%f].")
614 (t "compile(%f)."))
615 "Alist of strings and lists defining predicate for recompilation.
617 Some parts of the string are replaced:
618 `%f' by the name of the compiled file (can be a temporary file)
619 `%b' by the file name of the buffer to compile
620 `%m' by the module name and name of the compiled file separated by colon
621 `%l' by the line offset into the file. This is 0 unless compiling a
622 region of a buffer, in which case it is the number of lines before
623 the region.
625 If `prolog-program-name' is non-nil, it is a string sent to a Prolog process.
626 If `prolog-program-name' is nil, it is an argument to the `compile' function."
627 :group 'prolog-inferior
628 :type '(alist :key-type (choice symbol sexp)
629 :value-type (group (choice string (const nil) sexp)))
630 :risky t)
632 (defun prolog-compile-string ()
633 (prolog-find-value-by-system prolog-compile-string))
635 (defcustom prolog-eof-string "end_of_file.\n"
636 "String or alist of strings that represent end of file for prolog.
637 If nil, send actual operating system end of file."
638 :group 'prolog-inferior
639 :type '(choice string
640 (const nil)
641 (alist :key-type (choice symbol sexp)
642 :value-type (group (choice string (const nil) sexp))))
643 :risky t)
645 (defcustom prolog-prompt-regexp
646 '((eclipse "^[a-zA-Z0-9()]* *\\?- \\|^\\[[a-zA-Z]* [0-9]*\\]:")
647 (sicstus "| [ ?][- ] *")
648 (swi "^\\(\\[[a-zA-Z]*\\] \\)?[1-9]?[0-9]*[ ]?\\?- \\|^| +")
649 (gnu "^| \\?-")
650 (t "^|? *\\?-"))
651 "Alist of prompts of the prolog system command line."
652 :version "24.1"
653 :group 'prolog-inferior
654 :type '(alist :key-type (choice symbol sexp)
655 :value-type (group (choice string (const nil) sexp)))
656 :risky t)
658 (defun prolog-prompt-regexp ()
659 (prolog-find-value-by-system prolog-prompt-regexp))
661 ;; (defcustom prolog-continued-prompt-regexp
662 ;; '((sicstus "^\\(| +\\| +\\)")
663 ;; (t "^|: +"))
664 ;; "Alist of regexps matching the prompt when consulting `user'."
665 ;; :group 'prolog-inferior
666 ;; :type '(alist :key-type (choice symbol sexp)
667 ;; :value-type (group (choice string (const nil) sexp)))
668 ;; :risky t)
670 (defcustom prolog-debug-on-string "debug.\n"
671 "Predicate for enabling debug mode."
672 :version "24.1"
673 :group 'prolog-inferior
674 :type 'string)
676 (defcustom prolog-debug-off-string "nodebug.\n"
677 "Predicate for disabling debug mode."
678 :version "24.1"
679 :group 'prolog-inferior
680 :type 'string)
682 (defcustom prolog-trace-on-string "trace.\n"
683 "Predicate for enabling tracing."
684 :version "24.1"
685 :group 'prolog-inferior
686 :type 'string)
688 (defcustom prolog-trace-off-string "notrace.\n"
689 "Predicate for disabling tracing."
690 :version "24.1"
691 :group 'prolog-inferior
692 :type 'string)
694 (defcustom prolog-zip-on-string "zip.\n"
695 "Predicate for enabling zip mode for SICStus."
696 :version "24.1"
697 :group 'prolog-inferior
698 :type 'string)
700 (defcustom prolog-zip-off-string "nozip.\n"
701 "Predicate for disabling zip mode for SICStus."
702 :version "24.1"
703 :group 'prolog-inferior
704 :type 'string)
706 (defcustom prolog-use-standard-consult-compile-method-flag t
707 "Non-nil means use the standard compilation method.
708 Otherwise the new compilation method will be used. This
709 utilizes a special compilation buffer with the associated
710 features such as parsing of error messages and automatically
711 jumping to the source code responsible for the error.
713 Warning: the new method is so far only experimental and
714 does contain bugs. The recommended setting for the novice user
715 is non-nil for this variable."
716 :version "24.1"
717 :group 'prolog-inferior
718 :type 'boolean)
721 ;; Miscellaneous
723 (defcustom prolog-imenu-flag t
724 "Non-nil means add a clause index menu for all prolog files."
725 :version "24.1"
726 :group 'prolog-other
727 :type 'boolean)
729 (defcustom prolog-imenu-max-lines 3000
730 "The maximum number of lines of the file for imenu to be enabled.
731 Relevant only when `prolog-imenu-flag' is non-nil."
732 :version "24.1"
733 :group 'prolog-other
734 :type 'integer)
736 (defcustom prolog-info-predicate-index
737 "(sicstus)Predicate Index"
738 "The info node for the SICStus predicate index."
739 :version "24.1"
740 :group 'prolog-other
741 :type 'string)
743 (defcustom prolog-underscore-wordchar-flag nil
744 "Non-nil means underscore (_) is a word-constituent character."
745 :version "24.1"
746 :group 'prolog-other
747 :type 'boolean)
748 (make-obsolete-variable 'prolog-underscore-wordchar-flag
749 'superword-mode "24.4")
751 (defcustom prolog-use-sicstus-sd nil
752 "If non-nil, use the source level debugger of SICStus 3#7 and later."
753 :version "24.1"
754 :group 'prolog-other
755 :type 'boolean)
757 (defcustom prolog-char-quote-workaround nil
758 "If non-nil, declare 0 as a quote character to handle 0'<char>.
759 This is really kludgy, and unneeded (i.e. obsolete) in Emacs>=24."
760 :version "24.1"
761 :group 'prolog-other
762 :type 'boolean)
763 (make-obsolete-variable 'prolog-char-quote-workaround nil "24.1")
766 ;;-------------------------------------------------------------------
767 ;; Internal variables
768 ;;-------------------------------------------------------------------
770 ;;(defvar prolog-temp-filename "") ; Later set by `prolog-temporary-file'
772 (defvar prolog-mode-syntax-table
773 ;; The syntax accepted varies depending on the implementation used.
774 ;; Here are some of the differences:
775 ;; - SWI-Prolog accepts nested /*..*/ comments.
776 ;; - Edinburgh-style Prologs take <radix>'<number> for non-decimal number,
777 ;; whereas ISO-style Prologs use 0[obx]<number> instead.
778 ;; - In atoms \x<hex> sometimes needs a terminating \ (ISO-style)
779 ;; and sometimes not.
780 (let ((table (make-syntax-table)))
781 (modify-syntax-entry ?_ (if prolog-underscore-wordchar-flag "w" "_") table)
782 (modify-syntax-entry ?+ "." table)
783 (modify-syntax-entry ?- "." table)
784 (modify-syntax-entry ?= "." table)
785 (modify-syntax-entry ?< "." table)
786 (modify-syntax-entry ?> "." table)
787 (modify-syntax-entry ?| "." table)
788 (modify-syntax-entry ?\' "\"" table)
790 ;; Any better way to handle the 0'<char> construct?!?
791 (when (and prolog-char-quote-workaround
792 (not (fboundp 'syntax-propertize-rules)))
793 (modify-syntax-entry ?0 "\\" table))
795 (modify-syntax-entry ?% "<" table)
796 (modify-syntax-entry ?\n ">" table)
797 (if (featurep 'xemacs)
798 (progn
799 (modify-syntax-entry ?* ". 67" table)
800 (modify-syntax-entry ?/ ". 58" table)
802 ;; Emacs wants to see this it seems:
803 (modify-syntax-entry ?* ". 23b" table)
804 (modify-syntax-entry ?/ ". 14" table)
806 table))
808 (defconst prolog-atom-char-regexp
809 "[[:alnum:]_$]"
810 "Regexp specifying characters which constitute atoms without quoting.")
811 (defconst prolog-atom-regexp
812 (format "[[:lower:]$]%s*" prolog-atom-char-regexp))
814 (defconst prolog-left-paren "[[({]" ;FIXME: Why not \\s(?
815 "The characters used as left parentheses for the indentation code.")
816 (defconst prolog-right-paren "[])}]" ;FIXME: Why not \\s)?
817 "The characters used as right parentheses for the indentation code.")
819 (defconst prolog-quoted-atom-regexp
820 "\\(^\\|[^0-9]\\)\\('\\([^\n']\\|\\\\'\\)*'\\)"
821 "Regexp matching a quoted atom.")
822 (defconst prolog-string-regexp
823 "\\(\"\\([^\n\"]\\|\\\\\"\\)*\"\\)"
824 "Regexp matching a string.")
825 (defconst prolog-head-delimiter "\\(:-\\|\\+:\\|-:\\|\\+\\?\\|-\\?\\|-->\\)"
826 "A regexp for matching on the end delimiter of a head (e.g. \":-\").")
828 (defvar prolog-compilation-buffer "*prolog-compilation*"
829 "Name of the output buffer for Prolog compilation/consulting.")
831 (defvar prolog-temporary-file-name nil)
832 (defvar prolog-keywords-i nil)
833 (defvar prolog-types-i nil)
834 (defvar prolog-mode-specificators-i nil)
835 (defvar prolog-determinism-specificators-i nil)
836 (defvar prolog-directives-i nil)
837 (defvar prolog-eof-string-i nil)
838 ;; (defvar prolog-continued-prompt-regexp-i nil)
839 (defvar prolog-help-function-i nil)
841 (defvar prolog-align-rules
842 (eval-when-compile
843 (mapcar
844 (lambda (x)
845 (let ((name (car x))
846 (sym (cdr x)))
847 `(,(intern (format "prolog-%s" name))
848 (regexp . ,(format "\\(\\s-*\\)%s\\(\\s-*\\)" sym))
849 (tab-stop . nil)
850 (modes . '(prolog-mode))
851 (group . (1 2)))))
852 '(("dcg" . "-->") ("rule" . ":-") ("simplification" . "<=>")
853 ("propagation" . "==>")))))
855 ;; SMIE support
857 (require 'smie)
859 (defconst prolog-operator-chars "-\\\\#&*+./:<=>?@\\^`~")
861 (defun prolog-smie-forward-token ()
862 ;; FIXME: Add support for 0'<char>, if needed after adding it to
863 ;; syntax-propertize-functions.
864 (forward-comment (point-max))
865 (buffer-substring-no-properties
866 (point)
867 (progn (cond
868 ((looking-at "[!;]") (forward-char 1))
869 ((not (zerop (skip-chars-forward prolog-operator-chars))))
870 ((not (zerop (skip-syntax-forward "w_'"))))
871 ;; In case of non-ASCII punctuation.
872 ((not (zerop (skip-syntax-forward ".")))))
873 (point))))
875 (defun prolog-smie-backward-token ()
876 ;; FIXME: Add support for 0'<char>, if needed after adding it to
877 ;; syntax-propertize-functions.
878 (forward-comment (- (point-max)))
879 (buffer-substring-no-properties
880 (point)
881 (progn (cond
882 ((memq (char-before) '(?! ?\; ?\,)) (forward-char -1))
883 ((not (zerop (skip-chars-backward prolog-operator-chars))))
884 ((not (zerop (skip-syntax-backward "w_'"))))
885 ;; In case of non-ASCII punctuation.
886 ((not (zerop (skip-syntax-backward ".")))))
887 (point))))
889 (defconst prolog-smie-grammar
890 ;; Rather than construct the operator levels table from the BNF,
891 ;; we directly provide the operator precedences from GNU Prolog's
892 ;; manual (7.14.10 op/3). The only problem is that GNU Prolog's
893 ;; manual uses precedence levels in the opposite sense (higher
894 ;; numbers bind less tightly) than SMIE, so we use negative numbers.
895 '(("." -10000 -10000)
896 ("?-" nil -1200)
897 (":-" -1200 -1200)
898 ("-->" -1200 -1200)
899 ("discontiguous" nil -1150)
900 ("dynamic" nil -1150)
901 ("meta_predicate" nil -1150)
902 ("module_transparent" nil -1150)
903 ("multifile" nil -1150)
904 ("public" nil -1150)
905 ("|" -1105 -1105)
906 (";" -1100 -1100)
907 ("*->" -1050 -1050)
908 ("->" -1050 -1050)
909 ("," -1000 -1000)
910 ("\\+" nil -900)
911 ("=" -700 -700)
912 ("\\=" -700 -700)
913 ("=.." -700 -700)
914 ("==" -700 -700)
915 ("\\==" -700 -700)
916 ("@<" -700 -700)
917 ("@=<" -700 -700)
918 ("@>" -700 -700)
919 ("@>=" -700 -700)
920 ("is" -700 -700)
921 ("=:=" -700 -700)
922 ("=\\=" -700 -700)
923 ("<" -700 -700)
924 ("=<" -700 -700)
925 (">" -700 -700)
926 (">=" -700 -700)
927 (":" -600 -600)
928 ("+" -500 -500)
929 ("-" -500 -500)
930 ("/\\" -500 -500)
931 ("\\/" -500 -500)
932 ("*" -400 -400)
933 ("/" -400 -400)
934 ("//" -400 -400)
935 ("rem" -400 -400)
936 ("mod" -400 -400)
937 ("<<" -400 -400)
938 (">>" -400 -400)
939 ("**" -200 -200)
940 ("^" -200 -200)
941 ;; Prefix
942 ;; ("+" 200 200)
943 ;; ("-" 200 200)
944 ;; ("\\" 200 200)
945 (:smie-closer-alist (t . "."))
947 "Precedence levels of infix operators.")
949 (defun prolog-smie-rules (kind token)
950 (pcase (cons kind token)
951 (`(:elem . basic) prolog-indent-width)
952 ;; The list of arguments can never be on a separate line!
953 (`(:list-intro . ,_) t)
954 ;; When we don't know how to indent an empty line, assume the most
955 ;; likely token will be ";".
956 (`(:elem . empty-line-token) ";")
957 (`(:after . ".") '(column . 0)) ;; To work around smie-closer-alist.
958 ;; Allow indentation of if-then-else as:
959 ;; ( test
960 ;; -> thenrule
961 ;; ; elserule
962 ;; )
963 (`(:before . ,(or `"->" `";"))
964 (and (smie-rule-bolp) (smie-rule-parent-p "(") (smie-rule-parent 0)))
965 (`(:after . ,(or `"->" `"*->"))
966 ;; We distinguish
968 ;; (a ->
969 ;; b;
970 ;; c)
971 ;; and
972 ;; ( a ->
973 ;; b
974 ;; ; c)
976 ;; based on the space between the open paren and the "a".
977 (unless (and (smie-rule-parent-p "(" ";")
978 (save-excursion
979 (smie-indent-forward-token)
980 (smie-backward-sexp 'halfsexp)
981 (if (smie-rule-parent-p "(")
982 (not (eq (char-before) ?\())
983 (smie-indent-backward-token)
984 (smie-rule-bolp))))
985 prolog-indent-width))
986 (`(:after . ";")
987 ;; Align with same-line comment as in:
988 ;; ; %% Toto
989 ;; foo
990 (and (smie-rule-bolp)
991 (looking-at ";[ \t]*\\(%\\)")
992 (let ((offset (- (save-excursion (goto-char (match-beginning 1))
993 (current-column))
994 (current-column))))
995 ;; Only do it for small offsets, since the comment may actually be
996 ;; an "end-of-line" comment at comment-column!
997 (if (<= offset prolog-indent-width) offset))))
998 (`(:after . ",")
999 ;; Special indent for:
1000 ;; foopredicate(x) :- !,
1001 ;; toto.
1002 (and (eq (char-before) ?!)
1003 (save-excursion
1004 (smie-indent-backward-token) ;Skip !
1005 (equal ":-" (car (smie-indent-backward-token))))
1006 (smie-rule-parent prolog-indent-width)))
1007 (`(:after . ":-")
1008 (if (bolp)
1009 (save-excursion
1010 (smie-indent-forward-token)
1011 (skip-chars-forward " \t")
1012 (if (eolp)
1013 prolog-indent-width
1014 (min prolog-indent-width (current-column))))
1015 prolog-indent-width))
1016 (`(:after . "-->") prolog-indent-width)))
1019 ;;-------------------------------------------------------------------
1020 ;; Prolog mode
1021 ;;-------------------------------------------------------------------
1023 ;; Example: (prolog-atleast-version '(3 . 6))
1024 (defun prolog-atleast-version (version)
1025 "Return t if the version of the current prolog system is VERSION or later.
1026 VERSION is of the format (Major . Minor)"
1027 ;; Version.major < major or
1028 ;; Version.major = major and Version.minor <= minor
1029 (let* ((thisversion (prolog-find-value-by-system prolog-system-version))
1030 (thismajor (car thisversion))
1031 (thisminor (cdr thisversion)))
1032 (or (< (car version) thismajor)
1033 (and (= (car version) thismajor)
1034 (<= (cdr version) thisminor)))
1037 (define-abbrev-table 'prolog-mode-abbrev-table ())
1039 ;; Because this can `eval' its arguments, any variable that gets
1040 ;; processed by it should be marked as :risky.
1041 (defun prolog-find-value-by-system (alist)
1042 "Get value from ALIST according to `prolog-system'."
1043 (let ((system (or prolog-system
1044 (let ((infbuf (prolog-inferior-buffer 'dont-run)))
1045 (when infbuf
1046 (buffer-local-value 'prolog-system infbuf))))))
1047 (if (listp alist)
1048 (let (result
1050 (while alist
1051 (setq id (car (car alist)))
1052 (if (or (eq id system)
1053 (eq id t)
1054 (and (listp id)
1055 (eval id)))
1056 (progn
1057 (setq result (car (cdr (car alist))))
1058 (if (and (listp result)
1059 (eq (car result) 'eval))
1060 (setq result (eval (car (cdr result)))))
1061 (setq alist nil))
1062 (setq alist (cdr alist))))
1063 result)
1064 alist)))
1066 (defconst prolog-syntax-propertize-function
1067 (when (fboundp 'syntax-propertize-rules)
1068 (syntax-propertize-rules
1069 ;; GNU Prolog only accepts 0'\' rather than 0'', but the only
1070 ;; possible meaning of 0'' is rather clear.
1071 ("\\<0\\(''?\\)"
1072 (1 (unless (save-excursion (nth 8 (syntax-ppss (match-beginning 0))))
1073 (string-to-syntax "_"))))
1074 ;; We could check that we're not inside an atom, but I don't think
1075 ;; that 'foo 8'z could be a valid syntax anyway, so why bother?
1076 ("\\<[1-9][0-9]*\\('\\)[0-9a-zA-Z]" (1 "_"))
1077 ;; Supposedly, ISO-Prolog wants \NNN\ for octal and \xNNN\ for hexadecimal
1078 ;; escape sequences in atoms, so be careful not to let the terminating \
1079 ;; escape a subsequent quote.
1080 ("\\\\[x0-7][0-9a-fA-F]*\\(\\\\\\)" (1 "_"))
1083 (defun prolog-mode-variables ()
1084 "Set some common variables to Prolog code specific values."
1085 (setq-local local-abbrev-table prolog-mode-abbrev-table)
1086 (setq-local paragraph-start (concat "[ \t]*$\\|" page-delimiter)) ;'%%..'
1087 (setq-local paragraph-separate paragraph-start)
1088 (setq-local paragraph-ignore-fill-prefix t)
1089 (setq-local normal-auto-fill-function 'prolog-do-auto-fill)
1090 (setq-local comment-start "%")
1091 (setq-local comment-end "")
1092 (setq-local comment-add 1)
1093 (setq-local comment-start-skip "\\(?:/\\*+ *\\|%+ *\\)")
1094 (setq-local parens-require-spaces nil)
1095 ;; Initialize Prolog system specific variables
1096 (dolist (var '(prolog-keywords prolog-types prolog-mode-specificators
1097 prolog-determinism-specificators prolog-directives
1098 prolog-eof-string
1099 ;; prolog-continued-prompt-regexp
1100 prolog-help-function))
1101 (set (intern (concat (symbol-name var) "-i"))
1102 (prolog-find-value-by-system (symbol-value var))))
1103 (when (null (prolog-program-name))
1104 (setq-local compile-command (prolog-compile-string)))
1105 (setq-local font-lock-defaults
1106 '(prolog-font-lock-keywords nil nil ((?_ . "w"))))
1107 (setq-local syntax-propertize-function prolog-syntax-propertize-function)
1109 (smie-setup prolog-smie-grammar #'prolog-smie-rules
1110 :forward-token #'prolog-smie-forward-token
1111 :backward-token #'prolog-smie-backward-token))
1113 (defun prolog-mode-keybindings-common (map)
1114 "Define keybindings common to both Prolog modes in MAP."
1115 (define-key map "\C-c?" 'prolog-help-on-predicate)
1116 (define-key map "\C-c/" 'prolog-help-apropos)
1117 (define-key map "\C-c\C-d" 'prolog-debug-on)
1118 (define-key map "\C-c\C-t" 'prolog-trace-on)
1119 (define-key map "\C-c\C-z" 'prolog-zip-on)
1120 (define-key map "\C-c\r" 'run-prolog))
1122 (defun prolog-mode-keybindings-edit (map)
1123 "Define keybindings for Prolog mode in MAP."
1124 (define-key map "\M-a" 'prolog-beginning-of-clause)
1125 (define-key map "\M-e" 'prolog-end-of-clause)
1126 (define-key map "\M-q" 'prolog-fill-paragraph)
1127 (define-key map "\C-c\C-a" 'align)
1128 (define-key map "\C-\M-a" 'prolog-beginning-of-predicate)
1129 (define-key map "\C-\M-e" 'prolog-end-of-predicate)
1130 (define-key map "\M-\C-c" 'prolog-mark-clause)
1131 (define-key map "\M-\C-h" 'prolog-mark-predicate)
1132 (define-key map "\C-c\C-n" 'prolog-insert-predicate-template)
1133 (define-key map "\C-c\C-s" 'prolog-insert-predspec)
1134 (define-key map "\M-\r" 'prolog-insert-next-clause)
1135 (define-key map "\C-c\C-va" 'prolog-variables-to-anonymous)
1136 (define-key map "\C-c\C-v\C-s" 'prolog-view-predspec)
1138 ;; If we're running SICStus, then map C-c C-c e/d to enabling
1139 ;; and disabling of the source-level debugging facilities.
1140 ;(if (and (eq prolog-system 'sicstus)
1141 ; (prolog-atleast-version '(3 . 7)))
1142 ; (progn
1143 ; (define-key map "\C-c\C-ce" 'prolog-enable-sicstus-sd)
1144 ; (define-key map "\C-c\C-cd" 'prolog-disable-sicstus-sd)
1145 ; ))
1147 (if prolog-old-sicstus-keys-flag
1148 (progn
1149 (define-key map "\C-c\C-c" 'prolog-consult-predicate)
1150 (define-key map "\C-cc" 'prolog-consult-region)
1151 (define-key map "\C-cC" 'prolog-consult-buffer)
1152 (define-key map "\C-c\C-k" 'prolog-compile-predicate)
1153 (define-key map "\C-ck" 'prolog-compile-region)
1154 (define-key map "\C-cK" 'prolog-compile-buffer))
1155 (define-key map "\C-c\C-p" 'prolog-consult-predicate)
1156 (define-key map "\C-c\C-r" 'prolog-consult-region)
1157 (define-key map "\C-c\C-b" 'prolog-consult-buffer)
1158 (define-key map "\C-c\C-f" 'prolog-consult-file)
1159 (define-key map "\C-c\C-cp" 'prolog-compile-predicate)
1160 (define-key map "\C-c\C-cr" 'prolog-compile-region)
1161 (define-key map "\C-c\C-cb" 'prolog-compile-buffer)
1162 (define-key map "\C-c\C-cf" 'prolog-compile-file))
1164 ;; Inherited from the old prolog.el.
1165 (define-key map "\e\C-x" 'prolog-consult-region)
1166 (define-key map "\C-c\C-l" 'prolog-consult-file)
1167 (define-key map "\C-c\C-z" 'run-prolog))
1169 (defun prolog-mode-keybindings-inferior (_map)
1170 "Define keybindings for inferior Prolog mode in MAP."
1171 ;; No inferior mode specific keybindings now.
1174 (defvar prolog-mode-map
1175 (let ((map (make-sparse-keymap)))
1176 (prolog-mode-keybindings-common map)
1177 (prolog-mode-keybindings-edit map)
1178 map))
1181 (defvar prolog-mode-hook nil
1182 "List of functions to call after the prolog mode has initialized.")
1184 ;;;###autoload
1185 (define-derived-mode prolog-mode prog-mode "Prolog"
1186 "Major mode for editing Prolog code.
1188 Blank lines and `%%...' separate paragraphs. `%'s starts a comment
1189 line and comments can also be enclosed in /* ... */.
1191 If an optional argument SYSTEM is non-nil, set up mode for the given system.
1193 To find out what version of Prolog mode you are running, enter
1194 `\\[prolog-mode-version]'.
1196 Commands:
1197 \\{prolog-mode-map}"
1198 (setq mode-name (concat "Prolog"
1199 (cond
1200 ((eq prolog-system 'eclipse) "[ECLiPSe]")
1201 ((eq prolog-system 'sicstus) "[SICStus]")
1202 ((eq prolog-system 'swi) "[SWI]")
1203 ((eq prolog-system 'gnu) "[GNU]")
1204 (t ""))))
1205 (prolog-mode-variables)
1206 (dolist (ar prolog-align-rules) (add-to-list 'align-rules-list ar))
1207 (add-hook 'post-self-insert-hook #'prolog-post-self-insert nil t)
1208 ;; `imenu' entry moved to the appropriate hook for consistency.
1209 (when prolog-electric-dot-flag
1210 (setq-local electric-indent-chars
1211 (cons ?\. electric-indent-chars)))
1213 ;; Load SICStus debugger if suitable
1214 (if (and (eq prolog-system 'sicstus)
1215 (prolog-atleast-version '(3 . 7))
1216 prolog-use-sicstus-sd)
1217 (prolog-enable-sicstus-sd))
1219 (prolog-menu))
1221 (defvar mercury-mode-map
1222 (let ((map (make-sparse-keymap)))
1223 (set-keymap-parent map prolog-mode-map)
1224 map))
1226 ;;;###autoload
1227 (define-derived-mode mercury-mode prolog-mode "Prolog[Mercury]"
1228 "Major mode for editing Mercury programs.
1229 Actually this is just customized `prolog-mode'."
1230 (setq-local prolog-system 'mercury))
1233 ;;-------------------------------------------------------------------
1234 ;; Inferior prolog mode
1235 ;;-------------------------------------------------------------------
1237 (defvar prolog-inferior-mode-map
1238 (let ((map (make-sparse-keymap)))
1239 (prolog-mode-keybindings-common map)
1240 (prolog-mode-keybindings-inferior map)
1241 (define-key map [remap self-insert-command]
1242 'prolog-inferior-self-insert-command)
1243 map))
1245 (defvar prolog-inferior-mode-hook nil
1246 "List of functions to call after the inferior prolog mode has initialized.")
1248 (defvar prolog-inferior-error-regexp-alist
1249 '(;; GNU Prolog used to not follow the GNU standard format.
1250 ;; ("^\\(.*?\\):\\([0-9]+\\) error: .*(char:\\([0-9]+\\)" 1 2 3)
1251 ;; SWI-Prolog.
1252 ("^\\(?:\\?- *\\)?\\(\\(?:ERROR\\|\\(W\\)arning\\): *\\(.*?\\):\\([1-9][0-9]*\\):\\(?:\\([0-9]*\\):\\)?\\)\\(?:$\\| \\)"
1253 3 4 5 (2 . nil) 1)
1254 ;; GNU-Prolog now uses the GNU standard format.
1255 gnu))
1257 (defun prolog-inferior-self-insert-command ()
1258 "Insert the char in the buffer or pass it directly to the process."
1259 (interactive)
1260 (let* ((proc (get-buffer-process (current-buffer)))
1261 (pmark (and proc (marker-position (process-mark proc)))))
1262 ;; FIXME: the same treatment would be needed for SWI-Prolog, but I can't
1263 ;; seem to find any way for Emacs to figure out when to use it because
1264 ;; SWI doesn't include a " ? " or some such recognizable marker.
1265 (if (and (eq prolog-system 'gnu)
1266 pmark
1267 (null current-prefix-arg)
1268 (eobp)
1269 (eq (point) pmark)
1270 (save-excursion
1271 (goto-char (- pmark 3))
1272 ;; FIXME: check this comes from the process's output, maybe?
1273 (looking-at " \\? ")))
1274 ;; This is GNU prolog waiting to know whether you want more answers
1275 ;; or not (or abort, etc...). The answer is a single char, not
1276 ;; a line, so pass this char directly rather than wait for RET to
1277 ;; send a whole line.
1278 (comint-send-string proc (string last-command-event))
1279 (call-interactively 'self-insert-command))))
1281 (declare-function compilation-shell-minor-mode "compile" (&optional arg))
1282 (defvar compilation-error-regexp-alist)
1284 (define-derived-mode prolog-inferior-mode comint-mode "Inferior Prolog"
1285 "Major mode for interacting with an inferior Prolog process.
1287 The following commands are available:
1288 \\{prolog-inferior-mode-map}
1290 Entry to this mode calls the value of `prolog-mode-hook' with no arguments,
1291 if that value is non-nil. Likewise with the value of `comint-mode-hook'.
1292 `prolog-mode-hook' is called after `comint-mode-hook'.
1294 You can send text to the inferior Prolog from other buffers
1295 using the commands `send-region', `send-string' and \\[prolog-consult-region].
1297 Commands:
1298 Tab indents for Prolog; with argument, shifts rest
1299 of expression rigidly with the current line.
1300 Paragraphs are separated only by blank lines and `%%'. `%'s start comments.
1302 Return at end of buffer sends line as input.
1303 Return not at end copies rest of line to end and sends it.
1304 \\[comint-delchar-or-maybe-eof] sends end-of-file as input.
1305 \\[comint-kill-input] and \\[backward-kill-word] are kill commands,
1306 imitating normal Unix input editing.
1307 \\[comint-interrupt-subjob] interrupts the shell or its current subjob if any.
1308 \\[comint-stop-subjob] stops, likewise.
1309 \\[comint-quit-subjob] sends quit signal, likewise.
1311 To find out what version of Prolog mode you are running, enter
1312 `\\[prolog-mode-version]'."
1313 (require 'compile)
1314 (setq comint-input-filter 'prolog-input-filter)
1315 (setq mode-line-process '(": %s"))
1316 (prolog-mode-variables)
1317 (setq comint-prompt-regexp (prolog-prompt-regexp))
1318 (setq-local shell-dirstack-query "pwd.")
1319 (setq-local compilation-error-regexp-alist
1320 prolog-inferior-error-regexp-alist)
1321 (compilation-shell-minor-mode)
1322 (prolog-inferior-menu))
1324 (defun prolog-input-filter (str)
1325 (cond ((string-match "\\`\\s *\\'" str) nil) ;whitespace
1326 ((not (derived-mode-p 'prolog-inferior-mode)) t)
1327 ((= (length str) 1) nil) ;one character
1328 ((string-match "\\`[rf] *[0-9]*\\'" str) nil) ;r(edo) or f(ail)
1329 (t t)))
1331 ;; This statement was missing in Emacs 24.1, 24.2, 24.3.
1332 (define-obsolete-function-alias 'switch-to-prolog 'run-prolog "24.1")
1333 ;;;###autoload
1334 (defun run-prolog (arg)
1335 "Run an inferior Prolog process, input and output via buffer *prolog*.
1336 With prefix argument ARG, restart the Prolog process if running before."
1337 (interactive "P")
1338 ;; FIXME: It should be possible to interactively specify the command to use
1339 ;; to run prolog.
1340 (if (and arg (get-process "prolog"))
1341 (progn
1342 (process-send-string "prolog" "halt.\n")
1343 (while (get-process "prolog") (sit-for 0.1))))
1344 (let ((buff (buffer-name)))
1345 (if (not (string= buff "*prolog*"))
1346 (prolog-goto-prolog-process-buffer))
1347 ;; Load SICStus debugger if suitable
1348 (if (and (eq prolog-system 'sicstus)
1349 (prolog-atleast-version '(3 . 7))
1350 prolog-use-sicstus-sd)
1351 (prolog-enable-sicstus-sd))
1352 (prolog-mode-variables)
1353 (prolog-ensure-process)
1356 (defun prolog-inferior-guess-flavor (&optional ignored)
1357 (setq-local prolog-system
1358 (when (or (numberp prolog-system) (markerp prolog-system))
1359 (save-excursion
1360 (goto-char (1+ prolog-system))
1361 (cond
1362 ((looking-at "GNU Prolog") 'gnu)
1363 ((looking-at "Welcome to SWI-Prolog\\|%.*\\<swi_") 'swi)
1364 ((looking-at ".*\n") nil) ;There's at least one line.
1365 (t prolog-system)))))
1366 (when (symbolp prolog-system)
1367 (remove-hook 'comint-output-filter-functions
1368 'prolog-inferior-guess-flavor t)
1369 (when prolog-system
1370 (setq comint-prompt-regexp (prolog-prompt-regexp))
1371 (if (eq prolog-system 'gnu)
1372 (setq-local comint-process-echoes t)))))
1374 (defun prolog-ensure-process (&optional wait)
1375 "If Prolog process is not running, run it.
1376 If the optional argument WAIT is non-nil, wait for Prolog prompt specified by
1377 the variable `prolog-prompt-regexp'."
1378 (if (null (prolog-program-name))
1379 (error "This Prolog system has defined no interpreter."))
1380 (if (comint-check-proc "*prolog*")
1382 (with-current-buffer (get-buffer-create "*prolog*")
1383 (prolog-inferior-mode)
1385 ;; The "INFERIOR=yes" hack is for SWI-Prolog 7.2.3 and earlier,
1386 ;; which assumes it is running under Emacs if either INFERIOR=yes or
1387 ;; if EMACS is set to a nonempty value. The EMACS setting is
1388 ;; obsolescent, so set INFERIOR. Newer versions of SWI-Prolog should
1389 ;; know about INSIDE_EMACS (which replaced EMACS) and should not need
1390 ;; this hack.
1391 (let ((process-environment
1392 (if (getenv "INFERIOR")
1393 process-environment
1394 (cons "INFERIOR=yes" process-environment))))
1395 (apply 'make-comint-in-buffer "prolog" (current-buffer)
1396 (prolog-program-name) nil (prolog-program-switches)))
1398 (unless prolog-system
1399 ;; Setup auto-detection.
1400 (setq-local
1401 prolog-system
1402 ;; Force re-detection.
1403 (let* ((proc (get-buffer-process (current-buffer)))
1404 (pmark (and proc (marker-position (process-mark proc)))))
1405 (cond
1406 ((null pmark) (1- (point-min)))
1407 ;; The use of insert-before-markers in comint.el together with
1408 ;; the potential use of comint-truncate-buffer in the output
1409 ;; filter, means that it's difficult to reliably keep track of
1410 ;; the buffer position where the process's output started.
1411 ;; If possible we use a marker at "start - 1", so that
1412 ;; insert-before-marker at `start' won't shift it. And if not,
1413 ;; we fall back on using a plain integer.
1414 ((> pmark (point-min)) (copy-marker (1- pmark)))
1415 (t (1- pmark)))))
1416 (add-hook 'comint-output-filter-functions
1417 'prolog-inferior-guess-flavor nil t))
1418 (if wait
1419 (progn
1420 (goto-char (point-max))
1421 (while
1422 (save-excursion
1423 (not
1424 (re-search-backward
1425 (concat "\\(" (prolog-prompt-regexp) "\\)" "\\=")
1426 nil t)))
1427 (sit-for 0.1)))))))
1429 (defun prolog-inferior-buffer (&optional dont-run)
1430 (or (get-buffer "*prolog*")
1431 (unless dont-run
1432 (prolog-ensure-process)
1433 (get-buffer "*prolog*"))))
1435 (defun prolog-process-insert-string (process string)
1436 "Insert STRING into inferior Prolog buffer running PROCESS."
1437 ;; Copied from elisp manual, greek to me
1438 (with-current-buffer (process-buffer process)
1439 ;; FIXME: Use window-point-insertion-type instead.
1440 (let ((moving (= (point) (process-mark process))))
1441 (save-excursion
1442 ;; Insert the text, moving the process-marker.
1443 (goto-char (process-mark process))
1444 (insert string)
1445 (set-marker (process-mark process) (point)))
1446 (if moving (goto-char (process-mark process))))))
1448 ;;------------------------------------------------------------
1449 ;; Old consulting and compiling functions
1450 ;;------------------------------------------------------------
1452 (declare-function compilation-forget-errors "compile" ())
1453 (declare-function compilation-fake-loc "compile"
1454 (marker file &optional line col))
1456 (defun prolog-old-process-region (compilep start end)
1457 "Process the region limited by START and END positions.
1458 If COMPILEP is non-nil then use compilation, otherwise consulting."
1459 (prolog-ensure-process)
1460 ;(let ((tmpfile prolog-temp-filename)
1461 (let ((tmpfile (prolog-temporary-file))
1462 ;(process (get-process "prolog"))
1463 (first-line (1+ (count-lines
1464 (point-min)
1465 (save-excursion
1466 (goto-char start)
1467 (point))))))
1468 (write-region start end tmpfile)
1469 (setq start (copy-marker start))
1470 (with-current-buffer (prolog-inferior-buffer)
1471 (compilation-forget-errors)
1472 (compilation-fake-loc start tmpfile))
1473 (process-send-string
1474 "prolog" (prolog-build-prolog-command
1475 compilep tmpfile (prolog-bsts buffer-file-name)
1476 first-line))
1477 (prolog-goto-prolog-process-buffer)))
1479 (defun prolog-old-process-predicate (compilep)
1480 "Process the predicate around point.
1481 If COMPILEP is non-nil then use compilation, otherwise consulting."
1482 (prolog-old-process-region
1483 compilep (prolog-pred-start) (prolog-pred-end)))
1485 (defun prolog-old-process-buffer (compilep)
1486 "Process the entire buffer.
1487 If COMPILEP is non-nil then use compilation, otherwise consulting."
1488 (prolog-old-process-region compilep (point-min) (point-max)))
1490 (defun prolog-old-process-file (compilep)
1491 "Process the file of the current buffer.
1492 If COMPILEP is non-nil then use compilation, otherwise consulting."
1493 (save-some-buffers)
1494 (prolog-ensure-process)
1495 (with-current-buffer (prolog-inferior-buffer)
1496 (compilation-forget-errors))
1497 (process-send-string
1498 "prolog" (prolog-build-prolog-command
1499 compilep buffer-file-name
1500 (prolog-bsts buffer-file-name)))
1501 (prolog-goto-prolog-process-buffer))
1504 ;;------------------------------------------------------------
1505 ;; Consulting and compiling
1506 ;;------------------------------------------------------------
1508 ;; Interactive interface functions, used by both the standard
1509 ;; and the experimental consultation and compilation functions
1510 (defun prolog-consult-file ()
1511 "Consult file of current buffer."
1512 (interactive)
1513 (if prolog-use-standard-consult-compile-method-flag
1514 (prolog-old-process-file nil)
1515 (prolog-consult-compile-file nil)))
1517 (defun prolog-consult-buffer ()
1518 "Consult buffer."
1519 (interactive)
1520 (if prolog-use-standard-consult-compile-method-flag
1521 (prolog-old-process-buffer nil)
1522 (prolog-consult-compile-buffer nil)))
1524 (defun prolog-consult-region (beg end)
1525 "Consult region between BEG and END."
1526 (interactive "r")
1527 (if prolog-use-standard-consult-compile-method-flag
1528 (prolog-old-process-region nil beg end)
1529 (prolog-consult-compile-region nil beg end)))
1531 (defun prolog-consult-predicate ()
1532 "Consult the predicate around current point."
1533 (interactive)
1534 (if prolog-use-standard-consult-compile-method-flag
1535 (prolog-old-process-predicate nil)
1536 (prolog-consult-compile-predicate nil)))
1538 (defun prolog-compile-file ()
1539 "Compile file of current buffer."
1540 (interactive)
1541 (if prolog-use-standard-consult-compile-method-flag
1542 (prolog-old-process-file t)
1543 (prolog-consult-compile-file t)))
1545 (defun prolog-compile-buffer ()
1546 "Compile buffer."
1547 (interactive)
1548 (if prolog-use-standard-consult-compile-method-flag
1549 (prolog-old-process-buffer t)
1550 (prolog-consult-compile-buffer t)))
1552 (defun prolog-compile-region (beg end)
1553 "Compile region between BEG and END."
1554 (interactive "r")
1555 (if prolog-use-standard-consult-compile-method-flag
1556 (prolog-old-process-region t beg end)
1557 (prolog-consult-compile-region t beg end)))
1559 (defun prolog-compile-predicate ()
1560 "Compile the predicate around current point."
1561 (interactive)
1562 (if prolog-use-standard-consult-compile-method-flag
1563 (prolog-old-process-predicate t)
1564 (prolog-consult-compile-predicate t)))
1566 (defun prolog-buffer-module ()
1567 "Select Prolog module name appropriate for current buffer.
1568 Bases decision on buffer contents (-*- line)."
1569 ;; Look for -*- ... module: MODULENAME; ... -*-
1570 (let (beg end)
1571 (save-excursion
1572 (goto-char (point-min))
1573 (skip-chars-forward " \t")
1574 (and (search-forward "-*-" (line-end-position) t)
1575 (progn
1576 (skip-chars-forward " \t")
1577 (setq beg (point))
1578 (search-forward "-*-" (line-end-position) t))
1579 (progn
1580 (forward-char -3)
1581 (skip-chars-backward " \t")
1582 (setq end (point))
1583 (goto-char beg)
1584 (and (let ((case-fold-search t))
1585 (search-forward "module:" end t))
1586 (progn
1587 (skip-chars-forward " \t")
1588 (setq beg (point))
1589 (if (search-forward ";" end t)
1590 (forward-char -1)
1591 (goto-char end))
1592 (skip-chars-backward " \t")
1593 (buffer-substring beg (point)))))))))
1595 (defun prolog-build-prolog-command (compilep file buffername
1596 &optional first-line)
1597 "Make Prolog command for FILE compilation/consulting.
1598 If COMPILEP is non-nil, consider compilation, otherwise consulting."
1599 (let* ((compile-string
1600 ;; FIXME: If the process is not running yet, the auto-detection of
1601 ;; prolog-system won't help here, so we should make sure
1602 ;; we first run Prolog and then build the command.
1603 (if compilep (prolog-compile-string) (prolog-consult-string)))
1604 (module (prolog-buffer-module))
1605 (file-name (concat "'" (prolog-bsts file) "'"))
1606 (module-name (if module (concat "'" module "'")))
1607 (module-file (if module
1608 (concat module-name ":" file-name)
1609 file-name))
1610 strbeg strend
1611 (lineoffset (if first-line
1612 (- first-line 1)
1613 0)))
1615 ;; Assure that there is a buffer name
1616 (if (not buffername)
1617 (error "The buffer is not saved"))
1619 (if (not (string-match "\\`'.*'\\'" buffername)) ; Add quotes
1620 (setq buffername (concat "'" buffername "'")))
1621 (while (string-match "%m" compile-string)
1622 (setq strbeg (substring compile-string 0 (match-beginning 0)))
1623 (setq strend (substring compile-string (match-end 0)))
1624 (setq compile-string (concat strbeg module-file strend)))
1625 ;; FIXME: The code below will %-expand any %[fbl] that appears in
1626 ;; module-file.
1627 (while (string-match "%f" compile-string)
1628 (setq strbeg (substring compile-string 0 (match-beginning 0)))
1629 (setq strend (substring compile-string (match-end 0)))
1630 (setq compile-string (concat strbeg file-name strend)))
1631 (while (string-match "%b" compile-string)
1632 (setq strbeg (substring compile-string 0 (match-beginning 0)))
1633 (setq strend (substring compile-string (match-end 0)))
1634 (setq compile-string (concat strbeg buffername strend)))
1635 (while (string-match "%l" compile-string)
1636 (setq strbeg (substring compile-string 0 (match-beginning 0)))
1637 (setq strend (substring compile-string (match-end 0)))
1638 (setq compile-string (concat strbeg (format "%d" lineoffset) strend)))
1639 (concat compile-string "\n")))
1641 ;; The rest of this page is experimental code!
1643 ;; Global variables for process filter function
1644 (defvar prolog-process-flag nil
1645 "Non-nil means that a prolog task (i.e. a consultation or compilation job)
1646 is running.")
1647 (defvar prolog-consult-compile-output ""
1648 "Hold the unprocessed output from the current prolog task.")
1649 (defvar prolog-consult-compile-first-line 1
1650 "The number of the first line of the file to consult/compile.
1651 Used for temporary files.")
1652 (defvar prolog-consult-compile-file nil
1653 "The file to compile/consult (can be a temporary file).")
1654 (defvar prolog-consult-compile-real-file nil
1655 "The file name of the buffer to compile/consult.")
1657 (defvar compilation-parse-errors-function)
1659 (defun prolog-consult-compile (compilep file &optional first-line)
1660 "Consult/compile FILE.
1661 If COMPILEP is non-nil, perform compilation, otherwise perform CONSULTING.
1662 COMMAND is a string described by the variables `prolog-consult-string'
1663 and `prolog-compile-string'.
1664 Optional argument FIRST-LINE is the number of the first line in the compiled
1665 region.
1667 This function must be called from the source code buffer."
1668 (if prolog-process-flag
1669 (error "Another Prolog task is running."))
1670 (prolog-ensure-process t)
1671 (let* ((buffer (get-buffer-create prolog-compilation-buffer))
1672 (real-file buffer-file-name)
1673 (command-string (prolog-build-prolog-command compilep file
1674 real-file first-line))
1675 (process (get-process "prolog")))
1676 (with-current-buffer buffer
1677 (delete-region (point-min) (point-max))
1678 ;; FIXME: Wasn't this supposed to use prolog-inferior-mode?
1679 (compilation-mode)
1680 ;; FIXME: This doesn't seem to cooperate well with new(ish) compile.el.
1681 ;; Setting up font-locking for this buffer
1682 (setq-local font-lock-defaults
1683 '(prolog-font-lock-keywords nil nil ((?_ . "w"))))
1684 (if (eq prolog-system 'sicstus)
1685 ;; FIXME: This looks really problematic: not only is this using
1686 ;; the old compilation-parse-errors-function, but
1687 ;; prolog-parse-sicstus-compilation-errors only accepts one argument
1688 ;; whereas compile.el calls it with 2 (and did so at least since
1689 ;; Emacs-20).
1690 (setq-local compilation-parse-errors-function
1691 'prolog-parse-sicstus-compilation-errors))
1692 (setq buffer-read-only nil)
1693 (insert command-string "\n"))
1694 (display-buffer buffer)
1695 (setq prolog-process-flag t
1696 prolog-consult-compile-output ""
1697 prolog-consult-compile-first-line (if first-line (1- first-line) 0)
1698 prolog-consult-compile-file file
1699 prolog-consult-compile-real-file (if (string=
1700 file buffer-file-name)
1702 real-file))
1703 (with-current-buffer buffer
1704 (goto-char (point-max))
1705 (add-function :override (process-filter process)
1706 #'prolog-consult-compile-filter)
1707 (process-send-string "prolog" command-string)
1708 ;; (prolog-build-prolog-command compilep file real-file first-line))
1709 (while (and prolog-process-flag
1710 (accept-process-output process 10)) ; 10 secs is ok?
1711 (sit-for 0.1)
1712 (unless (get-process "prolog")
1713 (setq prolog-process-flag nil)))
1714 (insert (if compilep
1715 "\nCompilation finished.\n"
1716 "\nConsulted.\n"))
1717 (remove-function (process-filter process)
1718 #'prolog-consult-compile-filter))))
1720 (defvar compilation-error-list)
1722 (defun prolog-parse-sicstus-compilation-errors (limit)
1723 "Parse the prolog compilation buffer for errors.
1724 Argument LIMIT is a buffer position limiting searching.
1725 For use with the `compilation-parse-errors-function' variable."
1726 (setq compilation-error-list nil)
1727 (message "Parsing SICStus error messages...")
1728 (let (filepath dir file errorline)
1729 (while
1730 (re-search-backward
1731 "{\\([a-zA-Z ]* ERROR\\|Warning\\):.* in line[s ]*\\([0-9]+\\)"
1732 limit t)
1733 (setq errorline (string-to-number (match-string 2)))
1734 (save-excursion
1735 (re-search-backward
1736 "{\\(consulting\\|compiling\\|processing\\) \\(.*\\)\\.\\.\\.}"
1737 limit t)
1738 (setq filepath (match-string 2)))
1740 ;; ###### Does this work with SICStus under Windows
1741 ;; (i.e. backslashes and stuff?)
1742 (if (string-match "\\(.*/\\)\\([^/]*\\)$" filepath)
1743 (progn
1744 (setq dir (match-string 1 filepath))
1745 (setq file (match-string 2 filepath))))
1747 (setq compilation-error-list
1748 (cons
1749 (cons (save-excursion
1750 (beginning-of-line)
1751 (point-marker))
1752 (list (list file dir) errorline))
1753 compilation-error-list)
1757 (defun prolog-consult-compile-filter (process output)
1758 "Filter function for Prolog compilation PROCESS.
1759 Argument OUTPUT is a name of the output file."
1760 ;;(message "start")
1761 (setq prolog-consult-compile-output
1762 (concat prolog-consult-compile-output output))
1763 ;;(message "pccf1: %s" prolog-consult-compile-output)
1764 ;; Iterate through the lines of prolog-consult-compile-output
1765 (let (outputtype)
1766 (while (and prolog-process-flag
1768 ;; Trace question
1769 (progn
1770 (setq outputtype 'trace)
1771 (and (eq prolog-system 'sicstus)
1772 (string-match
1773 "^[ \t]*[0-9]+[ \t]*[0-9]+[ \t]*Call:.*? "
1774 prolog-consult-compile-output)))
1776 ;; Match anything
1777 (progn
1778 (setq outputtype 'normal)
1779 (string-match "^.*\n" prolog-consult-compile-output))
1781 ;;(message "outputtype: %s" outputtype)
1783 (setq output (match-string 0 prolog-consult-compile-output))
1784 ;; remove the text in output from prolog-consult-compile-output
1785 (setq prolog-consult-compile-output
1786 (substring prolog-consult-compile-output (length output)))
1787 ;;(message "pccf2: %s" prolog-consult-compile-output)
1789 ;; If temporary files were used, then we change the error
1790 ;; messages to point to the original source file.
1791 ;; FIXME: Use compilation-fake-loc instead.
1792 (cond
1794 ;; If the prolog process was in trace mode then it requires
1795 ;; user input
1796 ((and (eq prolog-system 'sicstus)
1797 (eq outputtype 'trace))
1798 (let ((input (concat (read-string output) "\n")))
1799 (process-send-string process input)
1800 (setq output (concat output input))))
1802 ((eq prolog-system 'sicstus)
1803 (if (and prolog-consult-compile-real-file
1804 (string-match
1805 "\\({.*:.* in line[s ]*\\)\\([0-9]+\\)-\\([0-9]+\\)" output))
1806 (setq output (replace-match
1807 ;; Adds a {processing ...} line so that
1808 ;; `prolog-parse-sicstus-compilation-errors'
1809 ;; finds the real file instead of the temporary one.
1810 ;; Also fixes the line numbers.
1811 (format "Added by Emacs: {processing %s...}\n%s%d-%d"
1812 prolog-consult-compile-real-file
1813 (match-string 1 output)
1814 (+ prolog-consult-compile-first-line
1815 (string-to-number
1816 (match-string 2 output)))
1817 (+ prolog-consult-compile-first-line
1818 (string-to-number
1819 (match-string 3 output))))
1820 t t output)))
1823 ((eq prolog-system 'swi)
1824 (if (and prolog-consult-compile-real-file
1825 (string-match (format
1826 "%s\\([ \t]*:[ \t]*\\)\\([0-9]+\\)"
1827 prolog-consult-compile-file)
1828 output))
1829 (setq output (replace-match
1830 ;; Real filename + text + fixed linenum
1831 (format "%s%s%d"
1832 prolog-consult-compile-real-file
1833 (match-string 1 output)
1834 (+ prolog-consult-compile-first-line
1835 (string-to-number
1836 (match-string 2 output))))
1837 t t output)))
1840 (t ())
1842 ;; Write the output in the *prolog-compilation* buffer
1843 (insert output)))
1845 ;; If the prompt is visible, then the task is finished
1846 (if (string-match (prolog-prompt-regexp) prolog-consult-compile-output)
1847 (setq prolog-process-flag nil)))
1849 (defun prolog-consult-compile-file (compilep)
1850 "Consult/compile file of current buffer.
1851 If COMPILEP is non-nil, compile, otherwise consult."
1852 (let ((file buffer-file-name))
1853 (if file
1854 (progn
1855 (save-some-buffers)
1856 (prolog-consult-compile compilep file))
1857 (prolog-consult-compile-region compilep (point-min) (point-max)))))
1859 (defun prolog-consult-compile-buffer (compilep)
1860 "Consult/compile current buffer.
1861 If COMPILEP is non-nil, compile, otherwise consult."
1862 (prolog-consult-compile-region compilep (point-min) (point-max)))
1864 (defun prolog-consult-compile-region (compilep beg end)
1865 "Consult/compile region between BEG and END.
1866 If COMPILEP is non-nil, compile, otherwise consult."
1867 ;(let ((file prolog-temp-filename)
1868 (let ((file (prolog-bsts (prolog-temporary-file)))
1869 (lines (count-lines 1 beg)))
1870 (write-region beg end file nil 'no-message)
1871 (write-region "\n" nil file t 'no-message)
1872 (prolog-consult-compile compilep file
1873 (if (bolp) (1+ lines) lines))
1874 (delete-file file)))
1876 (defun prolog-consult-compile-predicate (compilep)
1877 "Consult/compile the predicate around current point.
1878 If COMPILEP is non-nil, compile, otherwise consult."
1879 (prolog-consult-compile-region
1880 compilep (prolog-pred-start) (prolog-pred-end)))
1883 ;;-------------------------------------------------------------------
1884 ;; Font-lock stuff
1885 ;;-------------------------------------------------------------------
1887 ;; Auxiliary functions
1889 (defun prolog-font-lock-object-matcher (bound)
1890 "Find SICStus objects method name for font lock.
1891 Argument BOUND is a buffer position limiting searching."
1892 (let (point
1893 (case-fold-search nil))
1894 (while (and (not point)
1895 (re-search-forward "\\(::[ \t\n]*{\\|&\\)[ \t]*"
1896 bound t))
1897 (while (or (re-search-forward "\\=\n[ \t]*" bound t)
1898 (re-search-forward "\\=%.*" bound t)
1899 (and (re-search-forward "\\=/\\*" bound t)
1900 (re-search-forward "\\*/[ \t]*" bound t))))
1901 (setq point (re-search-forward
1902 (format "\\=\\(%s\\)" prolog-atom-regexp)
1903 bound t)))
1904 point))
1906 (defsubst prolog-face-name-p (facename)
1907 ;; Return t if FACENAME is the name of a face. This method is
1908 ;; necessary since facep in XEmacs only returns t for the actual
1909 ;; face objects (while it's only their names that are used just
1910 ;; about anywhere else) without providing a predicate that tests
1911 ;; face names. This function (including the above commentary) is
1912 ;; borrowed from cc-mode.
1913 (memq facename (face-list)))
1915 ;; Set everything up
1916 (defun prolog-font-lock-keywords ()
1917 "Set up font lock keywords for the current Prolog system."
1918 ;;(when window-system
1919 (require 'font-lock)
1921 ;; Define Prolog faces
1922 (defface prolog-redo-face
1923 '((((class grayscale)) (:italic t))
1924 (((class color)) (:foreground "darkorchid"))
1925 (t (:italic t)))
1926 "Prolog mode face for highlighting redo trace lines."
1927 :group 'prolog-faces)
1928 (defface prolog-exit-face
1929 '((((class grayscale)) (:underline t))
1930 (((class color) (background dark)) (:foreground "green"))
1931 (((class color) (background light)) (:foreground "ForestGreen"))
1932 (t (:underline t)))
1933 "Prolog mode face for highlighting exit trace lines."
1934 :group 'prolog-faces)
1935 (defface prolog-exception-face
1936 '((((class grayscale)) (:bold t :italic t :underline t))
1937 (((class color)) (:bold t :foreground "black" :background "Khaki"))
1938 (t (:bold t :italic t :underline t)))
1939 "Prolog mode face for highlighting exception trace lines."
1940 :group 'prolog-faces)
1941 (defface prolog-warning-face
1942 '((((class grayscale)) (:underline t))
1943 (((class color) (background dark)) (:foreground "blue"))
1944 (((class color) (background light)) (:foreground "MidnightBlue"))
1945 (t (:underline t)))
1946 "Face name to use for compiler warnings."
1947 :group 'prolog-faces)
1948 (defface prolog-builtin-face
1949 '((((class color) (background light)) (:foreground "Purple"))
1950 (((class color) (background dark)) (:foreground "Cyan"))
1951 (((class grayscale) (background light))
1952 :foreground "LightGray" :bold t)
1953 (((class grayscale) (background dark)) (:foreground "DimGray" :bold t))
1954 (t (:bold t)))
1955 "Face name to use for compiler warnings."
1956 :group 'prolog-faces)
1957 (defvar prolog-warning-face
1958 (if (prolog-face-name-p 'font-lock-warning-face)
1959 'font-lock-warning-face
1960 'prolog-warning-face)
1961 "Face name to use for built in predicates.")
1962 (defvar prolog-builtin-face
1963 (if (prolog-face-name-p 'font-lock-builtin-face)
1964 'font-lock-builtin-face
1965 'prolog-builtin-face)
1966 "Face name to use for built in predicates.")
1967 (defvar prolog-redo-face 'prolog-redo-face
1968 "Face name to use for redo trace lines.")
1969 (defvar prolog-exit-face 'prolog-exit-face
1970 "Face name to use for exit trace lines.")
1971 (defvar prolog-exception-face 'prolog-exception-face
1972 "Face name to use for exception trace lines.")
1974 ;; Font Lock Patterns
1975 (let (
1976 ;; "Native" Prolog patterns
1977 (head-predicates
1978 (list (format "^\\(%s\\)\\((\\|[ \t]*:-\\)" prolog-atom-regexp)
1979 1 font-lock-function-name-face))
1980 ;(list (format "^%s" prolog-atom-regexp)
1981 ; 0 font-lock-function-name-face))
1982 (head-predicates-1
1983 (list (format "\\.[ \t]*\\(%s\\)" prolog-atom-regexp)
1984 1 font-lock-function-name-face) )
1985 (variables
1986 '("\\<\\([_A-Z][a-zA-Z0-9_]*\\)"
1987 1 font-lock-variable-name-face))
1988 (important-elements
1989 (list (if (eq prolog-system 'mercury)
1990 "[][}{;|]\\|\\\\[+=]\\|<?=>?"
1991 "[][}{!;|]\\|\\*->")
1992 0 'font-lock-keyword-face))
1993 (important-elements-1
1994 '("[^-*]\\(->\\)" 1 font-lock-keyword-face))
1995 (predspecs ; module:predicate/cardinality
1996 (list (format "\\<\\(%s:\\|\\)%s/[0-9]+"
1997 prolog-atom-regexp prolog-atom-regexp)
1998 0 font-lock-function-name-face 'prepend))
1999 (keywords ; directives (queries)
2000 (list
2001 (if (eq prolog-system 'mercury)
2002 (concat
2003 "\\<\\("
2004 (regexp-opt prolog-keywords-i)
2005 "\\|"
2006 (regexp-opt
2007 prolog-determinism-specificators-i)
2008 "\\)\\>")
2009 (concat
2010 "^[?:]- *\\("
2011 (regexp-opt prolog-keywords-i)
2012 "\\)\\>"))
2013 1 prolog-builtin-face))
2014 ;; SICStus specific patterns
2015 (sicstus-object-methods
2016 (if (eq prolog-system 'sicstus)
2017 '(prolog-font-lock-object-matcher
2018 1 font-lock-function-name-face)))
2019 ;; Mercury specific patterns
2020 (types
2021 (if (eq prolog-system 'mercury)
2022 (list
2023 (regexp-opt prolog-types-i 'words)
2024 0 'font-lock-type-face)))
2025 (modes
2026 (if (eq prolog-system 'mercury)
2027 (list
2028 (regexp-opt prolog-mode-specificators-i 'words)
2029 0 'font-lock-constant-face)))
2030 (directives
2031 (if (eq prolog-system 'mercury)
2032 (list
2033 (regexp-opt prolog-directives-i 'words)
2034 0 'prolog-warning-face)))
2035 ;; Inferior mode specific patterns
2036 (prompt
2037 ;; FIXME: Should be handled by comint already.
2038 (list (prolog-prompt-regexp) 0 'font-lock-keyword-face))
2039 (trace-exit
2040 ;; FIXME: Add to compilation-error-regexp-alist instead.
2041 (cond
2042 ((eq prolog-system 'sicstus)
2043 '("[ \t]*[0-9]+[ \t]+[0-9]+[ \t]*\\(Exit\\):"
2044 1 prolog-exit-face))
2045 ((eq prolog-system 'swi)
2046 '("[ \t]*\\(Exit\\):[ \t]*([ \t0-9]*)" 1 prolog-exit-face))
2047 (t nil)))
2048 (trace-fail
2049 ;; FIXME: Add to compilation-error-regexp-alist instead.
2050 (cond
2051 ((eq prolog-system 'sicstus)
2052 '("[ \t]*[0-9]+[ \t]+[0-9]+[ \t]*\\(Fail\\):"
2053 1 prolog-warning-face))
2054 ((eq prolog-system 'swi)
2055 '("[ \t]*\\(Fail\\):[ \t]*([ \t0-9]*)" 1 prolog-warning-face))
2056 (t nil)))
2057 (trace-redo
2058 ;; FIXME: Add to compilation-error-regexp-alist instead.
2059 (cond
2060 ((eq prolog-system 'sicstus)
2061 '("[ \t]*[0-9]+[ \t]+[0-9]+[ \t]*\\(Redo\\):"
2062 1 prolog-redo-face))
2063 ((eq prolog-system 'swi)
2064 '("[ \t]*\\(Redo\\):[ \t]*([ \t0-9]*)" 1 prolog-redo-face))
2065 (t nil)))
2066 (trace-call
2067 ;; FIXME: Add to compilation-error-regexp-alist instead.
2068 (cond
2069 ((eq prolog-system 'sicstus)
2070 '("[ \t]*[0-9]+[ \t]+[0-9]+[ \t]*\\(Call\\):"
2071 1 font-lock-function-name-face))
2072 ((eq prolog-system 'swi)
2073 '("[ \t]*\\(Call\\):[ \t]*([ \t0-9]*)"
2074 1 font-lock-function-name-face))
2075 (t nil)))
2076 (trace-exception
2077 ;; FIXME: Add to compilation-error-regexp-alist instead.
2078 (cond
2079 ((eq prolog-system 'sicstus)
2080 '("[ \t]*[0-9]+[ \t]+[0-9]+[ \t]*\\(Exception\\):"
2081 1 prolog-exception-face))
2082 ((eq prolog-system 'swi)
2083 '("[ \t]*\\(Exception\\):[ \t]*([ \t0-9]*)"
2084 1 prolog-exception-face))
2085 (t nil)))
2086 (error-message-identifier
2087 ;; FIXME: Add to compilation-error-regexp-alist instead.
2088 (cond
2089 ((eq prolog-system 'sicstus)
2090 '("{\\([A-Z]* ?ERROR:\\)" 1 prolog-exception-face prepend))
2091 ((eq prolog-system 'swi)
2092 '("^[[]\\(WARNING:\\)" 1 prolog-builtin-face prepend))
2093 (t nil)))
2094 (error-whole-messages
2095 ;; FIXME: Add to compilation-error-regexp-alist instead.
2096 (cond
2097 ((eq prolog-system 'sicstus)
2098 '("{\\([A-Z]* ?ERROR:.*\\)}[ \t]*$"
2099 1 font-lock-comment-face append))
2100 ((eq prolog-system 'swi)
2101 '("^[[]WARNING:[^]]*[]]$" 0 font-lock-comment-face append))
2102 (t nil)))
2103 (error-warning-messages
2104 ;; FIXME: Add to compilation-error-regexp-alist instead.
2105 ;; Mostly errors that SICStus asks the user about how to solve,
2106 ;; such as "NAME CLASH:" for example.
2107 (cond
2108 ((eq prolog-system 'sicstus)
2109 '("^[A-Z ]*[A-Z]+:" 0 prolog-warning-face))
2110 (t nil)))
2111 (warning-messages
2112 ;; FIXME: Add to compilation-error-regexp-alist instead.
2113 (cond
2114 ((eq prolog-system 'sicstus)
2115 '("\\({ ?\\(Warning\\|WARNING\\) ?:.*}\\)[ \t]*$"
2116 2 prolog-warning-face prepend))
2117 (t nil))))
2119 ;; Make font lock list
2120 (delq
2122 (cond
2123 ((eq major-mode 'prolog-mode)
2124 (list
2125 head-predicates
2126 head-predicates-1
2127 variables
2128 important-elements
2129 important-elements-1
2130 predspecs
2131 keywords
2132 sicstus-object-methods
2133 types
2134 modes
2135 directives))
2136 ((eq major-mode 'prolog-inferior-mode)
2137 (list
2138 prompt
2139 error-message-identifier
2140 error-whole-messages
2141 error-warning-messages
2142 warning-messages
2143 predspecs
2144 trace-exit
2145 trace-fail
2146 trace-redo
2147 trace-call
2148 trace-exception))
2149 ((eq major-mode 'compilation-mode)
2150 (list
2151 error-message-identifier
2152 error-whole-messages
2153 error-warning-messages
2154 warning-messages
2155 predspecs))))
2160 (defun prolog-find-unmatched-paren ()
2161 "Return the column of the last unmatched left parenthesis."
2162 (save-excursion
2163 (goto-char (or (nth 1 (syntax-ppss)) (point-min)))
2164 (current-column)))
2167 (defun prolog-paren-balance ()
2168 "Return the parenthesis balance of the current line.
2169 A return value of N means N more left parentheses than right ones."
2170 (save-excursion
2171 (car (parse-partial-sexp (line-beginning-position)
2172 (line-end-position)))))
2174 (defun prolog-electric--if-then-else ()
2175 "Insert spaces after the opening parenthesis, \"then\" (->) and \"else\" (;) branches.
2176 Spaces are inserted if all preceding objects on the line are
2177 whitespace characters, parentheses, or then/else branches."
2178 (when prolog-electric-if-then-else-flag
2179 (save-excursion
2180 (let ((regexp (concat "(\\|" prolog-left-indent-regexp))
2181 (pos (point))
2182 level)
2183 (beginning-of-line)
2184 (skip-chars-forward " \t")
2185 ;; Treat "( If -> " lines specially.
2186 ;;(setq incr (if (looking-at "(.*->")
2187 ;; 2
2188 ;; prolog-paren-indent))
2190 ;; work on all subsequent "->", "(", ";"
2191 (and (looking-at regexp)
2192 (= pos (match-end 0))
2193 (indent-according-to-mode))
2194 (while (looking-at regexp)
2195 (goto-char (match-end 0))
2196 (setq level (+ (prolog-find-unmatched-paren) prolog-paren-indent))
2198 ;; Remove old white space
2199 (let ((start (point)))
2200 (skip-chars-forward " \t")
2201 (delete-region start (point)))
2202 (indent-to level)
2203 (skip-chars-forward " \t"))
2205 (when (save-excursion
2206 (backward-char 2)
2207 (looking-at "\\s ;\\|\\s (\\|->")) ; (looking-at "\\s \\((\\|;\\)"))
2208 (skip-chars-forward " \t"))
2211 ;;;; Comment filling
2213 (defun prolog-comment-limits ()
2214 "Return the current comment limits plus the comment type (block or line).
2215 The comment limits are the range of a block comment or the range that
2216 contains all adjacent line comments (i.e. all comments that starts in
2217 the same column with no empty lines or non-whitespace characters
2218 between them)."
2219 (let ((here (point))
2220 lit-limits-b lit-limits-e lit-type beg end
2222 (save-restriction
2223 ;; Widen to catch comment limits correctly.
2224 (widen)
2225 (setq end (line-end-position)
2226 beg (line-beginning-position))
2227 (save-excursion
2228 (beginning-of-line)
2229 (setq lit-type (if (search-forward-regexp "%" end t) 'line 'block))
2230 ; (setq lit-type 'line)
2231 ;(if (search-forward-regexp "^[ \t]*%" end t)
2232 ; (setq lit-type 'line)
2233 ; (if (not (search-forward-regexp "%" end t))
2234 ; (setq lit-type 'block)
2235 ; (if (not (= (forward-line 1) 0))
2236 ; (setq lit-type 'block)
2237 ; (setq done t
2238 ; ret (prolog-comment-limits)))
2239 ; ))
2240 (if (eq lit-type 'block)
2241 (progn
2242 (goto-char here)
2243 (when (looking-at "/\\*") (forward-char 2))
2244 (when (and (looking-at "\\*") (> (point) (point-min))
2245 (forward-char -1) (looking-at "/"))
2246 (forward-char 1))
2247 (when (save-excursion (search-backward "/*" nil t))
2248 (list (save-excursion (search-backward "/*") (point))
2249 (or (search-forward "*/" nil t) (point-max)) lit-type)))
2250 ;; line comment
2251 (setq lit-limits-b (- (point) 1)
2252 lit-limits-e end)
2253 (condition-case nil
2254 (if (progn (goto-char lit-limits-b)
2255 (looking-at "%"))
2256 (let ((col (current-column)) done)
2257 (setq beg (point)
2258 end lit-limits-e)
2259 ;; Always at the beginning of the comment
2260 ;; Go backward now
2261 (beginning-of-line)
2262 (while (and (zerop (setq done (forward-line -1)))
2263 (search-forward-regexp "^[ \t]*%"
2264 (line-end-position) t)
2265 (= (+ 1 col) (current-column)))
2266 (setq beg (- (point) 1)))
2267 (when (= done 0)
2268 (forward-line 1))
2269 ;; We may have a line with code above...
2270 (when (and (zerop (setq done (forward-line -1)))
2271 (search-forward "%" (line-end-position) t)
2272 (= (+ 1 col) (current-column)))
2273 (setq beg (- (point) 1)))
2274 (when (= done 0)
2275 (forward-line 1))
2276 ;; Go forward
2277 (goto-char lit-limits-b)
2278 (beginning-of-line)
2279 (while (and (zerop (forward-line 1))
2280 (search-forward-regexp "^[ \t]*%"
2281 (line-end-position) t)
2282 (= (+ 1 col) (current-column)))
2283 (setq end (line-end-position)))
2284 (list beg end lit-type))
2285 (list lit-limits-b lit-limits-e lit-type)
2287 (error (list lit-limits-b lit-limits-e lit-type))))
2288 ))))
2290 (defun prolog-guess-fill-prefix ()
2291 ;; fill 'txt entities?
2292 (when (save-excursion
2293 (end-of-line)
2294 (nth 4 (syntax-ppss)))
2295 (let* ((bounds (prolog-comment-limits))
2296 (cbeg (car bounds))
2297 (type (nth 2 bounds))
2298 beg end)
2299 (save-excursion
2300 (end-of-line)
2301 (setq end (point))
2302 (beginning-of-line)
2303 (setq beg (point))
2304 (if (and (eq type 'line)
2305 (> cbeg beg)
2306 (save-excursion (not (search-forward-regexp "^[ \t]*%"
2307 cbeg t))))
2308 (progn
2309 (goto-char cbeg)
2310 (search-forward-regexp "%+[ \t]*" end t)
2311 (prolog-replace-in-string (buffer-substring beg (point))
2312 "[^ \t%]" " "))
2313 ;(goto-char beg)
2314 (if (search-forward-regexp "^[ \t]*\\(%+\\|\\*+\\|/\\*+\\)[ \t]*"
2315 end t)
2316 (prolog-replace-in-string (buffer-substring beg (point)) "/" " ")
2317 (beginning-of-line)
2318 (when (search-forward-regexp "^[ \t]+" end t)
2319 (buffer-substring beg (point)))))))))
2321 (defun prolog-fill-paragraph ()
2322 "Fill paragraph comment at or after point."
2323 (interactive)
2324 (let* ((bounds (prolog-comment-limits))
2325 (type (nth 2 bounds)))
2326 (if (eq type 'line)
2327 (let ((fill-prefix (prolog-guess-fill-prefix)))
2328 (fill-paragraph nil))
2329 (save-excursion
2330 (save-restriction
2331 ;; exclude surrounding lines that delimit a multiline comment
2332 ;; and don't contain alphabetic characters, like "/*******",
2333 ;; "- - - */" etc.
2334 (save-excursion
2335 (backward-paragraph)
2336 (unless (bobp) (forward-line))
2337 (if (string-match "^/\\*[^a-zA-Z]*$" (thing-at-point 'line))
2338 (narrow-to-region (point-at-eol) (point-max))))
2339 (save-excursion
2340 (forward-paragraph)
2341 (forward-line -1)
2342 (if (string-match "^[^a-zA-Z]*\\*/$" (thing-at-point 'line))
2343 (narrow-to-region (point-min) (point-at-bol))))
2344 (let ((fill-prefix (prolog-guess-fill-prefix)))
2345 (fill-paragraph nil))))
2348 (defun prolog-do-auto-fill ()
2349 "Carry out Auto Fill for Prolog mode.
2350 In effect it sets the `fill-prefix' when inside comments and then calls
2351 `do-auto-fill'."
2352 (let ((fill-prefix (prolog-guess-fill-prefix)))
2353 (do-auto-fill)
2356 (defalias 'prolog-replace-in-string
2357 (if (fboundp 'replace-in-string)
2358 #'replace-in-string
2359 (lambda (str regexp newtext &optional literal)
2360 (replace-regexp-in-string regexp newtext str nil literal))))
2362 ;;-------------------------------------------------------------------
2363 ;; Online help
2364 ;;-------------------------------------------------------------------
2366 (defvar prolog-help-function
2367 '((mercury nil)
2368 (eclipse prolog-help-online)
2369 ;; (sicstus prolog-help-info)
2370 (sicstus prolog-find-documentation)
2371 (swi prolog-help-online)
2372 (t prolog-help-online))
2373 "Alist for the name of the function for finding help on a predicate.")
2374 (put 'prolog-help-function 'risky-local-variable t)
2376 (defun prolog-help-on-predicate ()
2377 "Invoke online help on the atom under cursor."
2378 (interactive)
2380 (cond
2381 ;; Redirect help for SICStus to `prolog-find-documentation'.
2382 ((eq prolog-help-function-i 'prolog-find-documentation)
2383 (prolog-find-documentation))
2385 ;; Otherwise, ask for the predicate name and then call the function
2386 ;; in prolog-help-function-i
2388 (let* ((word (prolog-atom-under-point))
2389 (predicate (read-string
2390 (format "Help on predicate%s: "
2391 (if word
2392 (concat " (default " word ")")
2393 ""))
2394 nil nil word))
2395 ;;point
2397 (if prolog-help-function-i
2398 (funcall prolog-help-function-i predicate)
2399 (error "Sorry, no help method defined for this Prolog system."))))
2403 (autoload 'Info-goto-node "info" nil t)
2404 (declare-function Info-follow-nearest-node "info" (&optional FORK))
2406 (defun prolog-help-info (predicate)
2407 (let ((buffer (current-buffer))
2408 oldp
2409 (str (concat "^\\* " (regexp-quote predicate) " */")))
2410 (pop-to-buffer nil)
2411 (Info-goto-node prolog-info-predicate-index)
2412 (if (not (re-search-forward str nil t))
2413 (error "Help on predicate `%s' not found." predicate))
2415 (setq oldp (point))
2416 (if (re-search-forward str nil t)
2417 ;; Multiple matches, ask user
2418 (let ((max 2)
2420 ;; Count matches
2421 (while (re-search-forward str nil t)
2422 (setq max (1+ max)))
2424 (goto-char oldp)
2425 (re-search-backward "[^ /]" nil t)
2426 (recenter 0)
2427 (setq n (read-string ;; was read-input, which is obsolete
2428 (format "Several matches, choose (1-%d): " max) "1"))
2429 (forward-line (- (string-to-number n) 1)))
2430 ;; Single match
2431 (re-search-backward "[^ /]" nil t))
2433 ;; (Info-follow-nearest-node (point))
2434 (prolog-Info-follow-nearest-node)
2435 (re-search-forward (concat "^`" (regexp-quote predicate)) nil t)
2436 (beginning-of-line)
2437 (recenter 0)
2438 (pop-to-buffer buffer)))
2440 (defun prolog-Info-follow-nearest-node ()
2441 (if (featurep 'xemacs)
2442 (Info-follow-nearest-node (point))
2443 (Info-follow-nearest-node)))
2445 (defun prolog-help-online (predicate)
2446 (prolog-ensure-process)
2447 (process-send-string "prolog" (concat "help(" predicate ").\n"))
2448 (display-buffer "*prolog*"))
2450 (defun prolog-help-apropos (string)
2451 "Find Prolog apropos on given STRING.
2452 This function is only available when `prolog-system' is set to `swi'."
2453 (interactive "sApropos: ")
2454 (cond
2455 ((eq prolog-system 'swi)
2456 (prolog-ensure-process)
2457 (process-send-string "prolog" (concat "apropos(" string ").\n"))
2458 (display-buffer "*prolog*"))
2460 (error "Sorry, no Prolog apropos available for this Prolog system."))))
2462 (defun prolog-atom-under-point ()
2463 "Return the atom under or left to the point."
2464 (save-excursion
2465 (let ((nonatom_chars "[](){},. \t\n")
2466 start)
2467 (skip-chars-forward (concat "^" nonatom_chars))
2468 (skip-chars-backward nonatom_chars)
2469 (skip-chars-backward (concat "^" nonatom_chars))
2470 (setq start (point))
2471 (skip-chars-forward (concat "^" nonatom_chars))
2472 (buffer-substring-no-properties start (point))
2476 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2477 ;; Help function with completion
2478 ;; Stolen from Per Mildner's SICStus debugger mode and modified
2480 (defun prolog-find-documentation ()
2481 "Go to the Info node for a predicate in the SICStus Info manual."
2482 (interactive)
2483 (let ((pred (prolog-read-predicate)))
2484 (prolog-goto-predicate-info pred)))
2486 (defvar prolog-info-alist nil
2487 "Alist with all builtin predicates.
2488 Only for internal use by `prolog-find-documentation'")
2490 ;; Very similar to prolog-help-info except that that function cannot
2491 ;; cope with arity and that it asks the user if there are several
2492 ;; functors with different arity. This function also uses
2493 ;; prolog-info-alist for finding the info node, rather than parsing
2494 ;; the predicate index.
2495 (defun prolog-goto-predicate-info (predicate)
2496 "Go to the info page for PREDICATE, which is a PredSpec."
2497 (interactive)
2498 (string-match "\\(.*\\)/\\([0-9]+\\).*$" predicate)
2499 (let ((buffer (current-buffer))
2500 (name (match-string 1 predicate))
2501 (arity (string-to-number (match-string 2 predicate)))
2502 ;oldp
2503 ;(str (regexp-quote predicate))
2505 (pop-to-buffer nil)
2507 (Info-goto-node
2508 prolog-info-predicate-index) ;; We must be in the SICStus pages
2509 (Info-goto-node (car (cdr (assoc predicate prolog-info-alist))))
2511 (prolog-find-term (regexp-quote name) arity "^`")
2513 (recenter 0)
2514 (pop-to-buffer buffer))
2517 (defun prolog-read-predicate ()
2518 "Read a PredSpec from the user.
2519 Returned value is a string \"FUNCTOR/ARITY\".
2520 Interaction supports completion."
2521 (let ((default (prolog-atom-under-point)))
2522 ;; If the predicate index is not yet built, do it now
2523 (if (not prolog-info-alist)
2524 (prolog-build-info-alist))
2525 ;; Test if the default string could be the base for completion.
2526 ;; Discard it if not.
2527 (if (eq (try-completion default prolog-info-alist) nil)
2528 (setq default nil))
2529 ;; Read the PredSpec from the user
2530 (completing-read
2531 (if (zerop (length default))
2532 "Help on predicate: "
2533 (concat "Help on predicate (default " default "): "))
2534 prolog-info-alist nil t nil nil default)))
2536 (defun prolog-build-info-alist (&optional verbose)
2537 "Build an alist of all builtins and library predicates.
2538 Each element is of the form (\"NAME/ARITY\" . (INFO-NODE1 INFO-NODE2 ...)).
2539 Typically there is just one Info node associated with each name
2540 If an optional argument VERBOSE is non-nil, print messages at the beginning
2541 and end of list building."
2542 (if verbose
2543 (message "Building info alist..."))
2544 (setq prolog-info-alist
2545 (let ((l ())
2546 (last-entry (cons "" ())))
2547 (save-excursion
2548 (save-window-excursion
2549 ;; select any window but the minibuffer (as we cannot switch
2550 ;; buffers in minibuffer window.
2551 ;; I am not sure this is the right/best way
2552 (if (active-minibuffer-window) ; nil if none active
2553 (select-window (next-window)))
2554 ;; Do this after going away from minibuffer window
2555 (save-window-excursion
2556 (info))
2557 (Info-goto-node prolog-info-predicate-index)
2558 (goto-char (point-min))
2559 (while (re-search-forward
2560 "^\\* \\(.+\\)/\\([0-9]+\\)\\([^\n:*]*\\):" nil t)
2561 (let* ((name (match-string 1))
2562 (arity (string-to-number (match-string 2)))
2563 (comment (match-string 3))
2564 (fa (format "%s/%d%s" name arity comment))
2565 info-node)
2566 (beginning-of-line)
2567 ;; Extract the info node name
2568 (setq info-node (progn
2569 (re-search-forward ":[ \t]*\\([^:]+\\).$")
2570 (match-string 1)
2572 ;; ###### Easier? (from Milan version 0.1.28)
2573 ;; (setq info-node (Info-extract-menu-node-name))
2574 (if (equal fa (car last-entry))
2575 (setcdr last-entry (cons info-node (cdr last-entry)))
2576 (setq last-entry (cons fa (list info-node))
2577 l (cons last-entry l)))))
2578 (nreverse l)
2579 ))))
2580 (if verbose
2581 (message "Building info alist... done.")))
2584 ;;-------------------------------------------------------------------
2585 ;; Miscellaneous functions
2586 ;;-------------------------------------------------------------------
2588 ;; For Windows. Change backslash to slash. SICStus handles either
2589 ;; path separator but backslash must be doubled, therefore use slash.
2590 (defun prolog-bsts (string)
2591 "Change backslashes to slashes in STRING."
2592 (let ((str1 (copy-sequence string))
2593 (len (length string))
2594 (i 0))
2595 (while (< i len)
2596 (if (char-equal (aref str1 i) ?\\)
2597 (aset str1 i ?/))
2598 (setq i (1+ i)))
2599 str1))
2601 ;;(defun prolog-temporary-file ()
2602 ;; "Make temporary file name for compilation."
2603 ;; (make-temp-name
2604 ;; (concat
2605 ;; (or
2606 ;; (getenv "TMPDIR")
2607 ;; (getenv "TEMP")
2608 ;; (getenv "TMP")
2609 ;; (getenv "SYSTEMP")
2610 ;; "/tmp")
2611 ;; "/prolcomp")))
2612 ;;(setq prolog-temp-filename (prolog-bsts (prolog-temporary-file)))
2614 (defun prolog-temporary-file ()
2615 "Make temporary file name for compilation."
2616 (if prolog-temporary-file-name
2617 ;; We already have a file, erase content and continue
2618 (progn
2619 (write-region "" nil prolog-temporary-file-name nil 'silent)
2620 prolog-temporary-file-name)
2621 ;; Actually create the file and set `prolog-temporary-file-name'
2622 ;; accordingly.
2623 (setq prolog-temporary-file-name
2624 (make-temp-file "prolcomp" nil ".pl"))))
2626 (defun prolog-goto-prolog-process-buffer ()
2627 "Switch to the prolog process buffer and go to its end."
2628 (switch-to-buffer-other-window "*prolog*")
2629 (goto-char (point-max))
2632 (declare-function pltrace-on "ext:pltrace" ())
2634 (defun prolog-enable-sicstus-sd ()
2635 "Enable the source level debugging facilities of SICStus 3.7 and later."
2636 (interactive)
2637 (require 'pltrace) ; Load the SICStus debugger code
2638 ;; Turn on the source level debugging by default
2639 (add-hook 'prolog-inferior-mode-hook 'pltrace-on)
2640 (if (not prolog-use-sicstus-sd)
2641 (progn
2642 ;; If there is a *prolog* buffer, then call pltrace-on
2643 (if (get-buffer "*prolog*")
2644 (pltrace-on))
2645 (setq prolog-use-sicstus-sd t)
2648 (declare-function pltrace-off "ext:pltrace" (&optional remove-process-filter))
2650 (defun prolog-disable-sicstus-sd ()
2651 "Disable the source level debugging facilities of SICStus 3.7 and later."
2652 (interactive)
2653 (require 'pltrace)
2654 (setq prolog-use-sicstus-sd nil)
2655 ;; Remove the hook
2656 (remove-hook 'prolog-inferior-mode-hook 'pltrace-on)
2657 ;; If there is a *prolog* buffer, then call pltrace-off
2658 (if (get-buffer "*prolog*")
2659 (pltrace-off)))
2661 (defun prolog-toggle-sicstus-sd ()
2662 ;; FIXME: Use define-minor-mode.
2663 "Toggle the source level debugging facilities of SICStus 3.7 and later."
2664 (interactive)
2665 (if prolog-use-sicstus-sd
2666 (prolog-disable-sicstus-sd)
2667 (prolog-enable-sicstus-sd)))
2669 (defun prolog-debug-on (&optional arg)
2670 "Enable debugging.
2671 When called with prefix argument ARG, disable debugging instead."
2672 (interactive "P")
2673 (if arg
2674 (prolog-debug-off)
2675 (prolog-process-insert-string (get-process "prolog")
2676 prolog-debug-on-string)
2677 (process-send-string "prolog" prolog-debug-on-string)))
2679 (defun prolog-debug-off ()
2680 "Disable debugging."
2681 (interactive)
2682 (prolog-process-insert-string (get-process "prolog")
2683 prolog-debug-off-string)
2684 (process-send-string "prolog" prolog-debug-off-string))
2686 (defun prolog-trace-on (&optional arg)
2687 "Enable tracing.
2688 When called with prefix argument ARG, disable tracing instead."
2689 (interactive "P")
2690 (if arg
2691 (prolog-trace-off)
2692 (prolog-process-insert-string (get-process "prolog")
2693 prolog-trace-on-string)
2694 (process-send-string "prolog" prolog-trace-on-string)))
2696 (defun prolog-trace-off ()
2697 "Disable tracing."
2698 (interactive)
2699 (prolog-process-insert-string (get-process "prolog")
2700 prolog-trace-off-string)
2701 (process-send-string "prolog" prolog-trace-off-string))
2703 (defun prolog-zip-on (&optional arg)
2704 "Enable zipping (for SICStus 3.7 and later).
2705 When called with prefix argument ARG, disable zipping instead."
2706 (interactive "P")
2707 (if (not (and (eq prolog-system 'sicstus)
2708 (prolog-atleast-version '(3 . 7))))
2709 (error "Only works for SICStus 3.7 and later"))
2710 (if arg
2711 (prolog-zip-off)
2712 (prolog-process-insert-string (get-process "prolog")
2713 prolog-zip-on-string)
2714 (process-send-string "prolog" prolog-zip-on-string)))
2716 (defun prolog-zip-off ()
2717 "Disable zipping (for SICStus 3.7 and later)."
2718 (interactive)
2719 (prolog-process-insert-string (get-process "prolog")
2720 prolog-zip-off-string)
2721 (process-send-string "prolog" prolog-zip-off-string))
2723 ;; (defun prolog-create-predicate-index ()
2724 ;; "Create an index for all predicates in the buffer."
2725 ;; (let ((predlist '())
2726 ;; clauseinfo
2727 ;; object
2728 ;; pos
2729 ;; )
2730 ;; (goto-char (point-min))
2731 ;; ;; Replace with prolog-clause-start!
2732 ;; (while (re-search-forward "^.+:-" nil t)
2733 ;; (setq pos (match-beginning 0))
2734 ;; (setq clauseinfo (prolog-clause-info))
2735 ;; (setq object (prolog-in-object))
2736 ;; (setq predlist (append
2737 ;; predlist
2738 ;; (list (cons
2739 ;; (if (and (eq prolog-system 'sicstus)
2740 ;; (prolog-in-object))
2741 ;; (format "%s::%s/%d"
2742 ;; object
2743 ;; (nth 0 clauseinfo)
2744 ;; (nth 1 clauseinfo))
2745 ;; (format "%s/%d"
2746 ;; (nth 0 clauseinfo)
2747 ;; (nth 1 clauseinfo)))
2748 ;; pos
2749 ;; ))))
2750 ;; (prolog-end-of-predicate))
2751 ;; predlist))
2753 (defun prolog-get-predspec ()
2754 (save-excursion
2755 (let ((state (prolog-clause-info))
2756 (object (prolog-in-object)))
2757 (if (or (equal (nth 0 state) "")
2758 (nth 4 (syntax-ppss)))
2760 (if (and (eq prolog-system 'sicstus)
2761 object)
2762 (format "%s::%s/%d"
2763 object
2764 (nth 0 state)
2765 (nth 1 state))
2766 (format "%s/%d"
2767 (nth 0 state)
2768 (nth 1 state)))
2769 ))))
2771 ;; For backward compatibility. Stolen from custom.el.
2772 (or (fboundp 'match-string)
2773 ;; Introduced in Emacs 19.29.
2774 (defun match-string (num &optional string)
2775 "Return string of text matched by last search.
2776 NUM specifies which parenthesized expression in the last regexp.
2777 Value is nil if NUMth pair didn't match, or there were less than NUM pairs.
2778 Zero means the entire text matched by the whole regexp or whole string.
2779 STRING should be given if the last search was by `string-match' on STRING."
2780 (if (match-beginning num)
2781 (if string
2782 (substring string (match-beginning num) (match-end num))
2783 (buffer-substring (match-beginning num) (match-end num))))))
2785 (defun prolog-pred-start ()
2786 "Return the starting point of the first clause of the current predicate."
2787 ;; FIXME: Use SMIE.
2788 (save-excursion
2789 (goto-char (prolog-clause-start))
2790 ;; Find first clause, unless it was a directive
2791 (if (and (not (looking-at "[:?]-"))
2792 (not (looking-at "[ \t]*[%/]")) ; Comment
2795 (let* ((pinfo (prolog-clause-info))
2796 (predname (nth 0 pinfo))
2797 (arity (nth 1 pinfo))
2798 (op (point)))
2799 (while (and (re-search-backward
2800 (format "^%s\\([(\\.]\\| *%s\\)"
2801 predname prolog-head-delimiter) nil t)
2802 (= arity (nth 1 (prolog-clause-info)))
2804 (setq op (point)))
2805 (if (eq prolog-system 'mercury)
2806 ;; Skip to the beginning of declarations of the predicate
2807 (progn
2808 (goto-char (prolog-beginning-of-clause))
2809 (while (and (not (eq (point) op))
2810 (looking-at
2811 (format ":-[ \t]*\\(pred\\|mode\\)[ \t]+%s"
2812 predname)))
2813 (setq op (point))
2814 (goto-char (prolog-beginning-of-clause)))))
2816 (point))))
2818 (defun prolog-pred-end ()
2819 "Return the position at the end of the last clause of the current predicate."
2820 ;; FIXME: Use SMIE.
2821 (save-excursion
2822 (goto-char (prolog-clause-end)) ; If we are before the first predicate.
2823 (goto-char (prolog-clause-start))
2824 (let* ((pinfo (prolog-clause-info))
2825 (predname (nth 0 pinfo))
2826 (arity (nth 1 pinfo))
2827 oldp
2828 (notdone t)
2829 (op (point)))
2830 (if (looking-at "[:?]-")
2831 ;; This was a directive
2832 (progn
2833 (if (and (eq prolog-system 'mercury)
2834 (looking-at
2835 (format ":-[ \t]*\\(pred\\|mode\\)[ \t]+\\(%s+\\)"
2836 prolog-atom-regexp)))
2837 ;; Skip predicate declarations
2838 (progn
2839 (setq predname (buffer-substring-no-properties
2840 (match-beginning 2) (match-end 2)))
2841 (while (re-search-forward
2842 (format
2843 "\n*\\(:-[ \t]*\\(pred\\|mode\\)[ \t]+\\)?%s[( \t]"
2844 predname)
2845 nil t))))
2846 (goto-char (prolog-clause-end))
2847 (setq op (point)))
2848 ;; It was not a directive, find the last clause
2849 (while (and notdone
2850 (re-search-forward
2851 (format "^%s\\([(\\.]\\| *%s\\)"
2852 predname prolog-head-delimiter) nil t)
2853 (= arity (nth 1 (prolog-clause-info))))
2854 (setq oldp (point))
2855 (setq op (prolog-clause-end))
2856 (if (>= oldp op)
2857 ;; End of clause not found.
2858 (setq notdone nil)
2859 ;; Continue while loop
2860 (goto-char op))))
2861 op)))
2863 (defun prolog-clause-start (&optional not-allow-methods)
2864 "Return the position at the start of the head of the current clause.
2865 If NOTALLOWMETHODS is non-nil then do not match on methods in
2866 objects (relevant only if `prolog-system' is set to `sicstus')."
2867 (save-excursion
2868 (let ((notdone t)
2869 (retval (point-min)))
2870 (end-of-line)
2872 ;; SICStus object?
2873 (if (and (not not-allow-methods)
2874 (eq prolog-system 'sicstus)
2875 (prolog-in-object))
2876 (while (and
2877 notdone
2878 ;; Search for a head or a fact
2879 (re-search-backward
2880 ;; If in object, then find method start.
2881 ;; "^[ \t]+[a-z$].*\\(:-\\|&\\|:: {\\|,\\)"
2882 "^[ \t]+[a-z$].*\\(:-\\|&\\|:: {\\)" ; The comma causes
2883 ; problems since we cannot assume
2884 ; that the line starts at column 0,
2885 ; thus we don't know if the line
2886 ; is a head or a subgoal
2887 (point-min) t))
2888 (if (>= (prolog-paren-balance) 0) ; To no match on " a) :-"
2889 ;; Start of method found
2890 (progn
2891 (setq retval (point))
2892 (setq notdone nil)))
2893 ) ; End of while
2895 ;; Not in object
2896 (while (and
2897 notdone
2898 ;; Search for a text at beginning of a line
2899 ;; ######
2900 ;; (re-search-backward "^[a-z$']" nil t))
2901 (let ((case-fold-search nil))
2902 (re-search-backward "^\\([[:lower:]$']\\|[:?]-\\)"
2903 nil t)))
2904 (let ((bal (prolog-paren-balance)))
2905 (cond
2906 ((> bal 0)
2907 ;; Start of clause found
2908 (progn
2909 (setq retval (point))
2910 (setq notdone nil)))
2911 ((and (= bal 0)
2912 (looking-at
2913 (format ".*\\(\\.\\|%s\\|!,\\)[ \t]*\\(%%.*\\|\\)$"
2914 prolog-head-delimiter)))
2915 ;; Start of clause found if the line ends with a '.' or
2916 ;; a prolog-head-delimiter
2917 (progn
2918 (setq retval (point))
2919 (setq notdone nil))
2921 (t nil) ; Do nothing
2922 ))))
2924 retval)))
2926 (defun prolog-clause-end (&optional not-allow-methods)
2927 "Return the position at the end of the current clause.
2928 If NOTALLOWMETHODS is non-nil then do not match on methods in
2929 objects (relevant only if `prolog-system' is set to `sicstus')."
2930 (save-excursion
2931 (beginning-of-line) ; Necessary since we use "^...." for the search.
2932 (if (re-search-forward
2933 (if (and (not not-allow-methods)
2934 (eq prolog-system 'sicstus)
2935 (prolog-in-object))
2936 (format
2937 "^\\(%s\\|%s\\|[^\n'\"%%]\\)*&[ \t]*\\(\\|%%.*\\)$\\|[ \t]*}"
2938 prolog-quoted-atom-regexp prolog-string-regexp)
2939 (format
2940 "^\\(%s\\|%s\\|[^\n'\"%%]\\)*\\.[ \t]*\\(\\|%%.*\\)$"
2941 prolog-quoted-atom-regexp prolog-string-regexp))
2942 nil t)
2943 (if (and (nth 8 (syntax-ppss))
2944 (not (eobp)))
2945 (progn
2946 (forward-char)
2947 (prolog-clause-end))
2948 (point))
2949 (point))))
2951 (defun prolog-clause-info ()
2952 "Return a (name arity) list for the current clause."
2953 (save-excursion
2954 (goto-char (prolog-clause-start))
2955 (let* ((op (point))
2956 (predname
2957 (if (looking-at prolog-atom-char-regexp)
2958 (progn
2959 (skip-chars-forward "^ (\\.")
2960 (buffer-substring op (point)))
2961 ""))
2962 (arity 0))
2963 ;; Retrieve the arity.
2964 (if (looking-at prolog-left-paren)
2965 (let ((endp (save-excursion
2966 (forward-list) (point))))
2967 (setq arity 1)
2968 (forward-char 1) ; Skip the opening paren.
2969 (while (progn
2970 (skip-chars-forward "^[({,'\"")
2971 (< (point) endp))
2972 (if (looking-at ",")
2973 (progn
2974 (setq arity (1+ arity))
2975 (forward-char 1) ; Skip the comma.
2977 ;; We found a string, list or something else we want
2978 ;; to skip over.
2979 (forward-sexp 1))
2981 (list predname arity))))
2983 (defun prolog-in-object ()
2984 "Return object name if the point is inside a SICStus object definition."
2985 ;; Return object name if the last line that starts with a character
2986 ;; that is neither white space nor a comment start
2987 (save-excursion
2988 (if (save-excursion
2989 (beginning-of-line)
2990 (looking-at "\\([^\n ]+\\)[ \t]*::[ \t]*{"))
2991 ;; We were in the head of the object
2992 (match-string 1)
2993 ;; We were not in the head
2994 (if (and (re-search-backward "^[a-z$'}]" nil t)
2995 (looking-at "\\([^\n ]+\\)[ \t]*::[ \t]*{"))
2996 (match-string 1)
2997 nil))))
2999 (defun prolog-beginning-of-clause ()
3000 "Move to the beginning of current clause.
3001 If already at the beginning of clause, move to previous clause."
3002 (interactive)
3003 (let ((point (point))
3004 (new-point (prolog-clause-start)))
3005 (if (and (>= new-point point)
3006 (> point 1))
3007 (progn
3008 (goto-char (1- point))
3009 (goto-char (prolog-clause-start)))
3010 (goto-char new-point)
3011 (skip-chars-forward " \t"))))
3013 ;; (defun prolog-previous-clause ()
3014 ;; "Move to the beginning of the previous clause."
3015 ;; (interactive)
3016 ;; (forward-char -1)
3017 ;; (prolog-beginning-of-clause))
3019 (defun prolog-end-of-clause ()
3020 "Move to the end of clause.
3021 If already at the end of clause, move to next clause."
3022 (interactive)
3023 (let ((point (point))
3024 (new-point (prolog-clause-end)))
3025 (if (and (<= new-point point)
3026 (not (eq new-point (point-max))))
3027 (progn
3028 (goto-char (1+ point))
3029 (goto-char (prolog-clause-end)))
3030 (goto-char new-point))))
3032 ;; (defun prolog-next-clause ()
3033 ;; "Move to the beginning of the next clause."
3034 ;; (interactive)
3035 ;; (prolog-end-of-clause)
3036 ;; (forward-char)
3037 ;; (prolog-end-of-clause)
3038 ;; (prolog-beginning-of-clause))
3040 (defun prolog-beginning-of-predicate ()
3041 "Go to the nearest beginning of predicate before current point.
3042 Return the final point or nil if no such a beginning was found."
3043 ;; FIXME: Hook into beginning-of-defun.
3044 (interactive)
3045 (let ((op (point))
3046 (pos (prolog-pred-start)))
3047 (if pos
3048 (if (= op pos)
3049 (if (not (bobp))
3050 (progn
3051 (goto-char pos)
3052 (backward-char 1)
3053 (setq pos (prolog-pred-start))
3054 (if pos
3055 (progn
3056 (goto-char pos)
3057 (point)))))
3058 (goto-char pos)
3059 (point)))))
3061 (defun prolog-end-of-predicate ()
3062 "Go to the end of the current predicate."
3063 ;; FIXME: Hook into end-of-defun.
3064 (interactive)
3065 (let ((op (point)))
3066 (goto-char (prolog-pred-end))
3067 (if (= op (point))
3068 (progn
3069 (forward-line 1)
3070 (prolog-end-of-predicate)))))
3072 (defun prolog-insert-predspec ()
3073 "Insert the predspec for the current predicate."
3074 (interactive)
3075 (let* ((pinfo (prolog-clause-info))
3076 (predname (nth 0 pinfo))
3077 (arity (nth 1 pinfo)))
3078 (insert (format "%s/%d" predname arity))))
3080 (defun prolog-view-predspec ()
3081 "Insert the predspec for the current predicate."
3082 (interactive)
3083 (let* ((pinfo (prolog-clause-info))
3084 (predname (nth 0 pinfo))
3085 (arity (nth 1 pinfo)))
3086 (message "%s/%d" predname arity)))
3088 (defun prolog-insert-predicate-template ()
3089 "Insert the template for the current clause."
3090 (interactive)
3091 (let* ((n 1)
3092 oldp
3093 (pinfo (prolog-clause-info))
3094 (predname (nth 0 pinfo))
3095 (arity (nth 1 pinfo)))
3096 (insert predname)
3097 (if (> arity 0)
3098 (progn
3099 (insert "(")
3100 (when prolog-electric-dot-full-predicate-template
3101 (setq oldp (point))
3102 (while (< n arity)
3103 (insert ",")
3104 (setq n (1+ n)))
3105 (insert ")")
3106 (goto-char oldp))
3110 (defun prolog-insert-next-clause ()
3111 "Insert newline and the name of the current clause."
3112 (interactive)
3113 (insert "\n")
3114 (prolog-insert-predicate-template))
3116 (defun prolog-insert-module-modeline ()
3117 "Insert a modeline for module specification.
3118 This line should be first in the buffer.
3119 The module name should be written manually just before the semi-colon."
3120 (interactive)
3121 (insert "%%% -*- Module: ; -*-\n")
3122 (backward-char 6))
3124 (defalias 'prolog-uncomment-region
3125 (if (fboundp 'uncomment-region) #'uncomment-region
3126 (lambda (beg end)
3127 "Uncomment the region between BEG and END."
3128 (interactive "r")
3129 (comment-region beg end -1))))
3131 (defun prolog-indent-predicate ()
3132 "Indent the current predicate."
3133 (interactive)
3134 (indent-region (prolog-pred-start) (prolog-pred-end) nil))
3136 (defun prolog-indent-buffer ()
3137 "Indent the entire buffer."
3138 (interactive)
3139 (indent-region (point-min) (point-max) nil))
3141 (defun prolog-mark-clause ()
3142 "Put mark at the end of this clause and move point to the beginning."
3143 (interactive)
3144 (let ((pos (point)))
3145 (goto-char (prolog-clause-end))
3146 (forward-line 1)
3147 (beginning-of-line)
3148 (set-mark (point))
3149 (goto-char pos)
3150 (goto-char (prolog-clause-start))))
3152 (defun prolog-mark-predicate ()
3153 "Put mark at the end of this predicate and move point to the beginning."
3154 (interactive)
3155 (goto-char (prolog-pred-end))
3156 (let ((pos (point)))
3157 (forward-line 1)
3158 (beginning-of-line)
3159 (set-mark (point))
3160 (goto-char pos)
3161 (goto-char (prolog-pred-start))))
3163 (defun prolog-electric--colon ()
3164 "If `prolog-electric-colon-flag' is non-nil, insert the electric `:' construct.
3165 That is, insert space (if appropriate), `:-' and newline if colon is pressed
3166 at the end of a line that starts in the first column (i.e., clause heads)."
3167 (when (and prolog-electric-colon-flag
3168 (eq (char-before) ?:)
3169 (not current-prefix-arg)
3170 (eolp)
3171 (not (memq (char-after (line-beginning-position))
3172 '(?\s ?\t ?\%))))
3173 (unless (memq (char-before (1- (point))) '(?\s ?\t))
3174 (save-excursion (forward-char -1) (insert " ")))
3175 (insert "-\n")
3176 (indent-according-to-mode)))
3178 (defun prolog-electric--dash ()
3179 "If `prolog-electric-dash-flag' is non-nil, insert the electric `-' construct.
3180 that is, insert space (if appropriate), `-->' and newline if dash is pressed
3181 at the end of a line that starts in the first column (i.e., DCG heads)."
3182 (when (and prolog-electric-dash-flag
3183 (eq (char-before) ?-)
3184 (not current-prefix-arg)
3185 (eolp)
3186 (not (memq (char-after (line-beginning-position))
3187 '(?\s ?\t ?\%))))
3188 (unless (memq (char-before (1- (point))) '(?\s ?\t))
3189 (save-excursion (forward-char -1) (insert " ")))
3190 (insert "->\n")
3191 (indent-according-to-mode)))
3193 (defun prolog-electric--dot ()
3194 "Make dot electric, if `prolog-electric-dot-flag' is non-nil.
3195 When invoked at the end of nonempty line, insert dot and newline.
3196 When invoked at the end of an empty line, insert a recursive call to
3197 the current predicate.
3198 When invoked at the beginning of line, insert a head of a new clause
3199 of the current predicate."
3200 ;; Check for situations when the electricity should not be active
3201 (if (or (not prolog-electric-dot-flag)
3202 (not (eq (char-before) ?\.))
3203 current-prefix-arg
3204 (nth 8 (syntax-ppss))
3205 ;; Do not be electric in a floating point number or an operator
3206 (not
3207 (save-excursion
3208 (forward-char -1)
3209 (skip-chars-backward " \t")
3210 (let ((num (> (skip-chars-backward "0-9") 0)))
3211 (or (bolp)
3212 (memq (char-syntax (char-before))
3213 (if num '(?w ?_) '(?\) ?w ?_)))))))
3214 ;; Do not be electric if inside a parenthesis pair.
3215 (not (= (car (syntax-ppss))
3218 nil ;;Not electric.
3219 (cond
3220 ;; Beginning of line
3221 ((save-excursion (forward-char -1) (bolp))
3222 (delete-region (1- (point)) (point)) ;Delete the dot that called us.
3223 (prolog-insert-predicate-template))
3224 ;; At an empty line with at least one whitespace
3225 ((save-excursion
3226 (beginning-of-line)
3227 (looking-at "[ \t]+\\.$"))
3228 (delete-region (1- (point)) (point)) ;Delete the dot that called us.
3229 (prolog-insert-predicate-template)
3230 (when prolog-electric-dot-full-predicate-template
3231 (save-excursion
3232 (end-of-line)
3233 (insert ".\n"))))
3234 ;; Default
3236 (insert "\n"))
3239 (defun prolog-electric--underscore ()
3240 "Replace variable with an underscore.
3241 If `prolog-electric-underscore-flag' is non-nil and the point is
3242 on a variable then replace the variable with underscore and skip
3243 the following comma and whitespace, if any."
3244 (when prolog-electric-underscore-flag
3245 (let ((case-fold-search nil))
3246 (when (and (not (nth 8 (syntax-ppss)))
3247 (eq (char-before) ?_)
3248 (save-excursion
3249 (skip-chars-backward "[:alpha:]_")
3250 (looking-at "\\_<[_[:upper:]][[:alnum:]_]*\\_>")))
3251 (replace-match "_")
3252 (skip-chars-forward ", \t\n")))))
3254 (defun prolog-post-self-insert ()
3255 (pcase last-command-event
3256 (`?_ (prolog-electric--underscore))
3257 (`?- (prolog-electric--dash))
3258 (`?: (prolog-electric--colon))
3259 ((or `?\( `?\; `?>) (prolog-electric--if-then-else))
3260 (`?. (prolog-electric--dot))))
3262 (defun prolog-find-term (functor arity &optional prefix)
3263 "Go to the position at the start of the next occurrence of a term.
3264 The term is specified with FUNCTOR and ARITY. The optional argument
3265 PREFIX is the prefix of the search regexp."
3266 (let* (;; If prefix is not set then use the default "\\<"
3267 (prefix (if (not prefix)
3268 "\\<"
3269 prefix))
3270 (regexp (concat prefix functor))
3271 (i 1))
3273 ;; Build regexp for the search if the arity is > 0
3274 (if (= arity 0)
3275 ;; Add that the functor must be at the end of a word. This
3276 ;; does not work if the arity is > 0 since the closing )
3277 ;; is not a word constituent.
3278 (setq regexp (concat regexp "\\>"))
3279 ;; Arity is > 0, add parens and commas
3280 (setq regexp (concat regexp "("))
3281 (while (< i arity)
3282 (setq regexp (concat regexp ".+,"))
3283 (setq i (1+ i)))
3284 (setq regexp (concat regexp ".+)")))
3286 ;; Search, and return position
3287 (if (re-search-forward regexp nil t)
3288 (goto-char (match-beginning 0))
3289 (error "Term not found"))
3292 (defun prolog-variables-to-anonymous (beg end)
3293 "Replace all variables within a region BEG to END by anonymous variables."
3294 (interactive "r")
3295 (save-excursion
3296 (let ((case-fold-search nil))
3297 (goto-char end)
3298 (while (re-search-backward "\\<[A-Z_][a-zA-Z_0-9]*\\>" beg t)
3299 (progn
3300 (replace-match "_")
3301 (backward-char)))
3304 ;;(defun prolog-regexp-dash-continuous-chars (chars)
3305 ;; (let ((ints (mapcar #'prolog-char-to-int (string-to-list chars)))
3306 ;; (beg 0)
3307 ;; (end 0))
3308 ;; (if (null ints)
3309 ;; chars
3310 ;; (while (and (< (+ beg 1) (length chars))
3311 ;; (not (or (= (+ (nth beg ints) 1) (nth (+ beg 1) ints))
3312 ;; (= (nth beg ints) (nth (+ beg 1) ints)))))
3313 ;; (setq beg (+ beg 1)))
3314 ;; (setq beg (+ beg 1)
3315 ;; end beg)
3316 ;; (while (and (< (+ end 1) (length chars))
3317 ;; (or (= (+ (nth end ints) 1) (nth (+ end 1) ints))
3318 ;; (= (nth end ints) (nth (+ end 1) ints))))
3319 ;; (setq end (+ end 1)))
3320 ;; (if (equal (substring chars end) "")
3321 ;; (substring chars 0 beg)
3322 ;; (concat (substring chars 0 beg) "-"
3323 ;; (prolog-regexp-dash-continuous-chars (substring chars end))))
3324 ;; )))
3326 ;;(defun prolog-condense-character-sets (regexp)
3327 ;; "Condense adjacent characters in character sets of REGEXP."
3328 ;; (let ((next -1))
3329 ;; (while (setq next (string-match "\\[\\(.*?\\)\\]" regexp (1+ next)))
3330 ;; (setq regexp (replace-match (prolog-dash-letters (match-string 1 regexp))
3331 ;; t t regexp 1))))
3332 ;; regexp)
3334 ;;-------------------------------------------------------------------
3335 ;; Menu stuff (both for the editing buffer and for the inferior
3336 ;; prolog buffer)
3337 ;;-------------------------------------------------------------------
3339 ;; GNU Emacs ignores `easy-menu-add' so the order in which the menus
3340 ;; are defined _is_ important!
3342 (easy-menu-define
3343 prolog-menu-help (list prolog-mode-map prolog-inferior-mode-map)
3344 "Help menu for the Prolog mode."
3345 ;; FIXME: Does it really deserve a whole menu to itself?
3346 `(,(if (featurep 'xemacs) "Help"
3347 ;; Not sure it's worth the trouble. --Stef
3348 ;; (add-to-list 'menu-bar-final-items
3349 ;; (easy-menu-intern "Prolog-Help"))
3350 "Prolog-help")
3351 ["On predicate" prolog-help-on-predicate prolog-help-function-i]
3352 ["Apropos" prolog-help-apropos (eq prolog-system 'swi)]
3353 "---"
3354 ["Describe mode" describe-mode t]))
3356 (easy-menu-define
3357 prolog-edit-menu-runtime prolog-mode-map
3358 "Runtime Prolog commands available from the editing buffer"
3359 ;; FIXME: Don't use a whole menu for just "Run Mercury". --Stef
3360 `("System"
3361 ;; Runtime menu name.
3362 ,@(unless (featurep 'xemacs)
3363 '(:label (cond ((eq prolog-system 'eclipse) "ECLiPSe")
3364 ((eq prolog-system 'mercury) "Mercury")
3365 (t "System"))))
3367 ;; Consult items, NIL for mercury.
3368 ["Consult file" prolog-consult-file
3369 :included (not (eq prolog-system 'mercury))]
3370 ["Consult buffer" prolog-consult-buffer
3371 :included (not (eq prolog-system 'mercury))]
3372 ["Consult region" prolog-consult-region :active (use-region-p)
3373 :included (not (eq prolog-system 'mercury))]
3374 ["Consult predicate" prolog-consult-predicate
3375 :included (not (eq prolog-system 'mercury))]
3377 ;; Compile items, NIL for everything but SICSTUS.
3378 ,(if (featurep 'xemacs) "---"
3379 ["---" nil :included (eq prolog-system 'sicstus)])
3380 ["Compile file" prolog-compile-file
3381 :included (eq prolog-system 'sicstus)]
3382 ["Compile buffer" prolog-compile-buffer
3383 :included (eq prolog-system 'sicstus)]
3384 ["Compile region" prolog-compile-region :active (use-region-p)
3385 :included (eq prolog-system 'sicstus)]
3386 ["Compile predicate" prolog-compile-predicate
3387 :included (eq prolog-system 'sicstus)]
3389 ;; Debug items, NIL for Mercury.
3390 ,(if (featurep 'xemacs) "---"
3391 ["---" nil :included (not (eq prolog-system 'mercury))])
3392 ;; FIXME: Could we use toggle or radio buttons? --Stef
3393 ["Debug" prolog-debug-on :included (not (eq prolog-system 'mercury))]
3394 ["Debug off" prolog-debug-off
3395 ;; In SICStus, these are pairwise disjunctive,
3396 ;; so it's enough with a single "off"-command
3397 :included (not (memq prolog-system '(mercury sicstus)))]
3398 ["Trace" prolog-trace-on :included (not (eq prolog-system 'mercury))]
3399 ["Trace off" prolog-trace-off
3400 :included (not (memq prolog-system '(mercury sicstus)))]
3401 ["Zip" prolog-zip-on :included (and (eq prolog-system 'sicstus)
3402 (prolog-atleast-version '(3 . 7)))]
3403 ["All debug off" prolog-debug-off
3404 :included (eq prolog-system 'sicstus)]
3405 ["Source level debugging"
3406 prolog-toggle-sicstus-sd
3407 :included (and (eq prolog-system 'sicstus)
3408 (prolog-atleast-version '(3 . 7)))
3409 :style toggle
3410 :selected prolog-use-sicstus-sd]
3412 "---"
3413 ["Run" run-prolog
3414 :suffix (cond ((eq prolog-system 'eclipse) "ECLiPSe")
3415 ((eq prolog-system 'mercury) "Mercury")
3416 (t "Prolog"))]))
3418 (easy-menu-define
3419 prolog-edit-menu-insert-move prolog-mode-map
3420 "Commands for Prolog code manipulation."
3421 '("Prolog"
3422 ["Comment region" comment-region (use-region-p)]
3423 ["Uncomment region" prolog-uncomment-region (use-region-p)]
3424 ["Add comment/move to comment" indent-for-comment t]
3425 ["Convert variables in region to '_'" prolog-variables-to-anonymous
3426 :active (use-region-p) :included (not (eq prolog-system 'mercury))]
3427 "---"
3428 ["Insert predicate template" prolog-insert-predicate-template t]
3429 ["Insert next clause head" prolog-insert-next-clause t]
3430 ["Insert predicate spec" prolog-insert-predspec t]
3431 ["Insert module modeline" prolog-insert-module-modeline t]
3432 "---"
3433 ["Beginning of clause" prolog-beginning-of-clause t]
3434 ["End of clause" prolog-end-of-clause t]
3435 ["Beginning of predicate" prolog-beginning-of-predicate t]
3436 ["End of predicate" prolog-end-of-predicate t]
3437 "---"
3438 ["Indent line" indent-according-to-mode t]
3439 ["Indent region" indent-region (use-region-p)]
3440 ["Indent predicate" prolog-indent-predicate t]
3441 ["Indent buffer" prolog-indent-buffer t]
3442 ["Align region" align (use-region-p)]
3443 "---"
3444 ["Mark clause" prolog-mark-clause t]
3445 ["Mark predicate" prolog-mark-predicate t]
3446 ["Mark paragraph" mark-paragraph t]
3449 (defun prolog-menu ()
3450 "Add the menus for the Prolog editing buffers."
3452 (easy-menu-add prolog-edit-menu-insert-move)
3453 (easy-menu-add prolog-edit-menu-runtime)
3455 ;; Add predicate index menu
3456 (setq-local imenu-create-index-function
3457 'imenu-default-create-index-function)
3458 ;;Milan (this has problems with object methods...) ###### Does it? (Stefan)
3459 (setq-local imenu-prev-index-position-function
3460 #'prolog-beginning-of-predicate)
3461 (setq-local imenu-extract-index-name-function #'prolog-get-predspec)
3463 (if (and prolog-imenu-flag
3464 (< (count-lines (point-min) (point-max)) prolog-imenu-max-lines))
3465 (imenu-add-to-menubar "Predicates"))
3467 (easy-menu-add prolog-menu-help))
3469 (easy-menu-define
3470 prolog-inferior-menu-all prolog-inferior-mode-map
3471 "Menu for the inferior Prolog buffer."
3472 `("Prolog"
3473 ;; Runtime menu name.
3474 ,@(unless (featurep 'xemacs)
3475 '(:label (cond ((eq prolog-system 'eclipse) "ECLiPSe")
3476 ((eq prolog-system 'mercury) "Mercury")
3477 (t "Prolog"))))
3479 ;; Debug items, NIL for Mercury.
3480 ,(if (featurep 'xemacs) "---"
3481 ["---" nil :included (not (eq prolog-system 'mercury))])
3482 ;; FIXME: Could we use toggle or radio buttons? --Stef
3483 ["Debug" prolog-debug-on :included (not (eq prolog-system 'mercury))]
3484 ["Debug off" prolog-debug-off
3485 ;; In SICStus, these are pairwise disjunctive,
3486 ;; so it's enough with a single "off"-command
3487 :included (not (memq prolog-system '(mercury sicstus)))]
3488 ["Trace" prolog-trace-on :included (not (eq prolog-system 'mercury))]
3489 ["Trace off" prolog-trace-off
3490 :included (not (memq prolog-system '(mercury sicstus)))]
3491 ["Zip" prolog-zip-on :included (and (eq prolog-system 'sicstus)
3492 (prolog-atleast-version '(3 . 7)))]
3493 ["All debug off" prolog-debug-off
3494 :included (eq prolog-system 'sicstus)]
3495 ["Source level debugging"
3496 prolog-toggle-sicstus-sd
3497 :included (and (eq prolog-system 'sicstus)
3498 (prolog-atleast-version '(3 . 7)))
3499 :style toggle
3500 :selected prolog-use-sicstus-sd]
3502 ;; Runtime.
3503 "---"
3504 ["Interrupt Prolog" comint-interrupt-subjob t]
3505 ["Quit Prolog" comint-quit-subjob t]
3506 ["Kill Prolog" comint-kill-subjob t]))
3509 (defun prolog-inferior-menu ()
3510 "Create the menus for the Prolog inferior buffer.
3511 This menu is dynamically created because one may change systems during
3512 the life of an Emacs session."
3513 (easy-menu-add prolog-inferior-menu-all)
3514 (easy-menu-add prolog-menu-help))
3516 (defun prolog-mode-version ()
3517 "Echo the current version of Prolog mode in the minibuffer."
3518 (interactive)
3519 (message "Using Prolog mode version %s" prolog-mode-version))
3521 (provide 'prolog)
3523 ;;; prolog.el ends here