Fix MS-Windows build.
[emacs.git] / lisp / progmodes / prolog.el
blob0f3c1504ee9c409bb2bf1f15d07b9c286b3cdf6f
1 ;;; prolog.el --- major mode for Prolog (and Mercury) -*- coding: utf-8 -*-
3 ;; Copyright (C) 1986-1987, 1997-1999, 2002-2003, 2011-2013 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 <http://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 ;; The code requires the comint, easymenu, info, imenu, and font-lock
58 ;; libraries. These are normally distributed with GNU Emacs and
59 ;; XEmacs.
61 ;;; Installation:
63 ;; Insert the following lines in your init file:
65 ;; (setq load-path (cons "/usr/lib/xemacs/site-lisp" load-path))
66 ;; (autoload 'run-prolog "prolog" "Start a Prolog sub-process." t)
67 ;; (autoload 'prolog-mode "prolog" "Major mode for editing Prolog programs." t)
68 ;; (autoload 'mercury-mode "prolog" "Major mode for editing Mercury programs." t)
69 ;; (setq prolog-system 'swi) ; optional, the system you are using;
70 ;; ; see `prolog-system' below for possible values
71 ;; (setq auto-mode-alist (append '(("\\.pl$" . prolog-mode)
72 ;; ("\\.m$" . mercury-mode))
73 ;; auto-mode-alist))
75 ;; where the path in the first line is the file system path to this file.
76 ;; MSDOS paths can be written like "d:/programs/emacs-19.34/site-lisp".
77 ;; Note: In XEmacs, either `/usr/lib/xemacs/site-lisp' (RPM default in
78 ;; Red Hat-based distributions) or `/usr/local/lib/xemacs/site-lisp'
79 ;; (default when compiling from sources) are automatically added to
80 ;; `load-path', so the first line is not necessary provided that you
81 ;; put this file in the appropriate place.
83 ;; The last s-expression above makes sure that files ending with .pl
84 ;; are assumed to be Prolog files and not Perl, which is the default
85 ;; Emacs setting. If this is not wanted, remove this line. It is then
86 ;; necessary to either
88 ;; o insert in your Prolog files the following comment as the first line:
90 ;; % -*- Mode: Prolog -*-
92 ;; and then the file will be open in Prolog mode no matter its
93 ;; extension, or
95 ;; o manually switch to prolog mode after opening a Prolog file, by typing
96 ;; M-x prolog-mode.
98 ;; If the command to start the prolog process ('sicstus', 'pl' or
99 ;; 'swipl' for SWI prolog, etc.) is not available in the default path,
100 ;; then it is necessary to set the value of the environment variable
101 ;; EPROLOG to a shell command to invoke the prolog process. In XEmacs
102 ;; and Emacs 20+ you can also customize the variable
103 ;; `prolog-program-name' (in the group `prolog-inferior') and provide
104 ;; a full path for your Prolog system (swi, scitus, etc.).
106 ;; Note: I (Stefan, the current maintainer) work under XEmacs. Future
107 ;; developments will thus be biased towards XEmacs (OK, I admit it,
108 ;; I am biased towards XEmacs in general), though I will do my best
109 ;; to keep the GNU Emacs compatibility. So if you work under Emacs
110 ;; and see something that does not work do drop me a line, as I have
111 ;; a smaller chance to notice this kind of bugs otherwise.
113 ;; Changelog:
115 ;; Version 1.22:
116 ;; o Allowed both 'swipl' and 'pl' as names for the SWI Prolog
117 ;; interpreter.
118 ;; o Atoms that start a line are not blindly colored as
119 ;; predicates. Instead we check that they are followed by ( or
120 ;; :- first. Patch suggested by Guy Wiener.
121 ;; Version 1.21:
122 ;; o Cleaned up the code that defines faces. The missing face
123 ;; warnings on some Emacsen should disappear.
124 ;; Version 1.20:
125 ;; o Improved the handling of clause start detection and multi-line
126 ;; comments: `prolog-clause-start' no longer finds non-predicate
127 ;; (e.g., capitalized strings) beginning of clauses.
128 ;; `prolog-tokenize' recognizes when the end point is within a
129 ;; multi-line comment.
130 ;; Version 1.19:
131 ;; o Minimal changes for Aquamacs inclusion and in general for
132 ;; better coping with finding the Prolog executable. Patch
133 ;; provided by David Reitter
134 ;; Version 1.18:
135 ;; o Fixed syntax highlighting for clause heads that do not begin at
136 ;; the beginning of the line.
137 ;; o Fixed compilation warnings under Emacs.
138 ;; o Updated the email address of the current maintainer.
139 ;; Version 1.17:
140 ;; o Minor indentation fix (patch by Markus Triska)
141 ;; o `prolog-underscore-wordchar-flag' defaults now to nil (more
142 ;; consistent to other Emacs modes)
143 ;; Version 1.16:
144 ;; o Eliminated a possible compilation warning.
145 ;; Version 1.15:
146 ;; o Introduced three new customizable variables: electric colon
147 ;; (`prolog-electric-colon-flag', default nil), electric dash
148 ;; (`prolog-electric-dash-flag', default nil), and a possibility
149 ;; to prevent the predicate template insertion from adding commas
150 ;; (`prolog-electric-dot-full-predicate-template', defaults to t
151 ;; since it seems quicker to me to just type those commas). A
152 ;; trivial adaptation of a patch by Markus Triska.
153 ;; o Improved the behavior of electric if-then-else to only skip
154 ;; forward if the parenthesis/semicolon is preceded by
155 ;; whitespace. Once more a trivial adaptation of a patch by
156 ;; Markus Triska.
157 ;; Version 1.14:
158 ;; o Cleaned up align code. `prolog-align-flag' is eliminated (since
159 ;; on a second thought it does not do anything useful). Added key
160 ;; binding (C-c C-a) and menu entry for alignment.
161 ;; o Condensed regular expressions for lower and upper case
162 ;; characters (GNU Emacs seems to go over the regexp length limit
163 ;; with the original form). My code on the matter was improved
164 ;; considerably by Markus Triska.
165 ;; o Fixed `prolog-insert-spaces-after-paren' (which used an
166 ;; uninitialized variable).
167 ;; o Minor changes to clean up the code and avoid some implicit
168 ;; package requirements.
169 ;; Version 1.13:
170 ;; o Removed the use of `map-char-table' in `prolog-build-case-strings'
171 ;; which appears to cause problems in (at least) Emacs 23.0.0.1.
172 ;; o Added if-then-else indentation + corresponding electric
173 ;; characters. New customization: `prolog-electric-if-then-else-flag'
174 ;; o Align support (requires `align'). New customization:
175 ;; `prolog-align-flag'.
176 ;; o Temporary consult files have now the same name throughout the
177 ;; session. This prevents issues with reconsulting a buffer
178 ;; (this event is no longer passed to Prolog as a request to
179 ;; consult a new file).
180 ;; o Adaptive fill mode is now turned on. Comment indentation is
181 ;; still worse than it could be though, I am working on it.
182 ;; o Improved filling and auto-filling capabilities. Now block
183 ;; comments should be [auto-]filled correctly most of the time;
184 ;; the following pattern in particular is worth noting as being
185 ;; filled correctly:
186 ;; <some code here> % some comment here that goes beyond the
187 ;; % rightmost column, possibly combined with
188 ;; % subsequent comment lines
189 ;; o `prolog-char-quote-workaround' now defaults to nil.
190 ;; o Note: Many of the above improvements have been suggested by
191 ;; Markus Triska, who also provided useful patches on the matter
192 ;; when he realized that I was slow in responding. Many thanks.
193 ;; Version 1.11 / 1.12
194 ;; o GNU Emacs compatibility fix for paragraph filling (fixed
195 ;; incorrectly in 1.11, fix fixed in 1.12).
196 ;; Version 1.10
197 ;; o Added paragraph filling in comment blocks and also correct auto
198 ;; filling for comments.
199 ;; o Fixed the possible "Regular expression too big" error in
200 ;; `prolog-electric-dot'.
201 ;; Version 1.9
202 ;; o Parenthesis expressions are now indented by default so that
203 ;; components go one underneath the other, just as for compound
204 ;; terms. You can use the old style (the second and subsequent
205 ;; lines being indented to the right in a parenthesis expression)
206 ;; by setting the customizable variable `prolog-paren-indent-p'
207 ;; (group "Prolog Indentation") to t.
208 ;; o (Somehow awkward) handling of the 0' character escape
209 ;; sequence. I am looking into a better way of doing it but
210 ;; prospects look bleak. If this breaks things for you please let
211 ;; me know and also set the `prolog-char-quote-workaround' (group
212 ;; "Prolog Other") to nil.
213 ;; Version 1.8
214 ;; o Key binding fix.
215 ;; Version 1.7
216 ;; o Fixed a number of issues with the syntax of single quotes,
217 ;; including Debian bug #324520.
218 ;; Version 1.6
219 ;; o Fixed mercury mode menu initialization (Debian bug #226121).
220 ;; o Fixed (i.e., eliminated) Delete remapping (Debian bug #229636).
221 ;; o Corrected indentation for clauses defining quoted atoms.
222 ;; Version 1.5:
223 ;; o Keywords fontifying should work in console mode so this is
224 ;; enabled everywhere.
225 ;; Version 1.4:
226 ;; o Now supports GNU Prolog--minor adaptation of a patch by Stefan
227 ;; Moeding.
228 ;; Version 1.3:
229 ;; o Info-follow-nearest-node now called correctly under Emacs too
230 ;; (thanks to Nicolas Pelletier). Should be implemented more
231 ;; elegantly (i.e., without compilation warnings) in the future.
232 ;; Version 1.2:
233 ;; o Another prompt fix, still in SWI mode (people seem to have
234 ;; changed the prompt of SWI Prolog).
235 ;; Version 1.1:
236 ;; o Fixed dots in the end of line comments causing indentation
237 ;; problems. The following code is now correctly indented (note
238 ;; the dot terminating the comment):
239 ;; a(X) :- b(X),
240 ;; c(X). % comment here.
241 ;; a(X).
242 ;; and so is this (and variants):
243 ;; a(X) :- b(X),
244 ;; c(X). /* comment here. */
245 ;; a(X).
246 ;; Version 1.0:
247 ;; o Revamped the menu system.
248 ;; o Yet another prompt recognition fix (SWI mode).
249 ;; o This is more of a renumbering than a new edition. I promoted
250 ;; the mode to version 1.0 to emphasize the fact that it is now
251 ;; mature and stable enough to be considered production (in my
252 ;; opinion anyway).
253 ;; Version 0.1.41:
254 ;; o GNU Emacs compatibility fixes.
255 ;; Version 0.1.40:
256 ;; o prolog-get-predspec is now suitable to be called as
257 ;; imenu-extract-index-name-function. The predicate index works.
258 ;; o Since imenu works now as advertised, prolog-imenu-flag is t
259 ;; by default.
260 ;; o Eliminated prolog-create-predicate-index since the imenu
261 ;; utilities now work well. Actually, this function is also
262 ;; buggy, and I see no reason to fix it since we do not need it
263 ;; anyway.
264 ;; o Fixed prolog-pred-start, prolog-clause-start, prolog-clause-info.
265 ;; o Fix for prolog-build-case-strings; now prolog-upper-case-string
266 ;; and prolog-lower-case-string are correctly initialized,
267 ;; o Various font-lock changes; most importantly, block comments (/*
268 ;; ... */) are now correctly fontified in XEmacs even when they
269 ;; extend on multiple lines.
270 ;; Version 0.1.36:
271 ;; o The debug prompt of SWI Prolog is now correctly recognized.
272 ;; Version 0.1.35:
273 ;; o Minor font-lock bug fixes.
275 ;;; TODO:
277 ;; Replace ":type 'sexp" with more precise Custom types.
279 ;;; Code:
281 (require 'comint)
283 (eval-when-compile
284 (require 'font-lock)
285 ;; We need imenu everywhere because of the predicate index!
286 (require 'imenu)
288 (require 'shell)
291 (require 'easymenu)
292 (require 'align)
295 (defgroup prolog nil
296 "Editing and running Prolog and Mercury files."
297 :group 'languages)
299 (defgroup prolog-faces nil
300 "Prolog mode specific faces."
301 :group 'font-lock)
303 (defgroup prolog-indentation nil
304 "Prolog mode indentation configuration."
305 :group 'prolog)
307 (defgroup prolog-font-lock nil
308 "Prolog mode font locking patterns."
309 :group 'prolog)
311 (defgroup prolog-keyboard nil
312 "Prolog mode keyboard flags."
313 :group 'prolog)
315 (defgroup prolog-inferior nil
316 "Inferior Prolog mode options."
317 :group 'prolog)
319 (defgroup prolog-other nil
320 "Other Prolog mode options."
321 :group 'prolog)
324 ;;-------------------------------------------------------------------
325 ;; User configurable variables
326 ;;-------------------------------------------------------------------
328 ;; General configuration
330 (defcustom prolog-system nil
331 "Prolog interpreter/compiler used.
332 The value of this variable is nil or a symbol.
333 If it is a symbol, it determines default values of other configuration
334 variables with respect to properties of the specified Prolog
335 interpreter/compiler.
337 Currently recognized symbol values are:
338 eclipse - Eclipse Prolog
339 mercury - Mercury
340 sicstus - SICStus Prolog
341 swi - SWI Prolog
342 gnu - GNU Prolog"
343 :version "24.1"
344 :group 'prolog
345 :type '(choice (const :tag "SICStus" :value sicstus)
346 (const :tag "SWI Prolog" :value swi)
347 (const :tag "GNU Prolog" :value gnu)
348 (const :tag "ECLiPSe Prolog" :value eclipse)
349 ;; Mercury shouldn't be needed since we have a separate
350 ;; major mode for it.
351 (const :tag "Default" :value nil)))
352 (make-variable-buffer-local 'prolog-system)
354 ;; NB: This alist can not be processed in prolog-mode-variables to
355 ;; create a prolog-system-version-i variable since it is needed
356 ;; prior to the call to prolog-mode-variables.
357 (defcustom prolog-system-version
358 '((sicstus (3 . 6))
359 (swi (0 . 0))
360 (mercury (0 . 0))
361 (eclipse (3 . 7))
362 (gnu (0 . 0)))
363 ;; FIXME: This should be auto-detected instead of user-provided.
364 "Alist of Prolog system versions.
365 The version numbers are of the format (Major . Minor)."
366 :version "24.1"
367 :type '(repeat (list (symbol :tag "System")
368 (cons :tag "Version numbers" (integer :tag "Major")
369 (integer :tag "Minor"))))
370 :group 'prolog)
372 ;; Indentation
374 (defcustom prolog-indent-width 4
375 "The indentation width used by the editing buffer."
376 :group 'prolog-indentation
377 :type 'integer)
379 (defcustom prolog-align-comments-flag t
380 "Non-nil means automatically align comments when indenting."
381 :version "24.1"
382 :group 'prolog-indentation
383 :type 'boolean)
385 (defcustom prolog-indent-mline-comments-flag t
386 "Non-nil means indent contents of /* */ comments.
387 Otherwise leave such lines as they are."
388 :version "24.1"
389 :group 'prolog-indentation
390 :type 'boolean)
392 (defcustom prolog-object-end-to-0-flag t
393 "Non-nil means indent closing '}' in SICStus object definitions to level 0.
394 Otherwise indent to `prolog-indent-width'."
395 :version "24.1"
396 :group 'prolog-indentation
397 :type 'boolean)
399 (defcustom prolog-left-indent-regexp "\\(;\\|\\*?->\\)"
400 "Regexp for character sequences after which next line is indented.
401 Next line after such a regexp is indented to the opening parenthesis level."
402 :version "24.1"
403 :group 'prolog-indentation
404 :type 'regexp)
406 (defcustom prolog-paren-indent-p nil
407 "If non-nil, increase indentation for parenthesis expressions.
408 The second and subsequent line in a parenthesis expression other than
409 a compound term can either be indented `prolog-paren-indent' to the
410 right (if this variable is non-nil) or in the same way as for compound
411 terms (if this variable is nil, default)."
412 :version "24.1"
413 :group 'prolog-indentation
414 :type 'boolean)
416 (defcustom prolog-paren-indent 4
417 "The indentation increase for parenthesis expressions.
418 Only used in ( If -> Then ; Else) and ( Disj1 ; Disj2 ) style expressions."
419 :version "24.1"
420 :group 'prolog-indentation
421 :type 'integer)
423 (defcustom prolog-parse-mode 'beg-of-clause
424 "The parse mode used (decides from which point parsing is done).
425 Legal values:
426 'beg-of-line - starts parsing at the beginning of a line, unless the
427 previous line ends with a backslash. Fast, but has
428 problems detecting multiline /* */ comments.
429 'beg-of-clause - starts parsing at the beginning of the current clause.
430 Slow, but copes better with /* */ comments."
431 :version "24.1"
432 :group 'prolog-indentation
433 :type '(choice (const :value beg-of-line)
434 (const :value beg-of-clause)))
436 ;; Font locking
438 (defcustom prolog-keywords
439 '((eclipse
440 ("use_module" "begin_module" "module_interface" "dynamic"
441 "external" "export" "dbgcomp" "nodbgcomp" "compile"))
442 (mercury
443 ("all" "else" "end_module" "equality" "external" "fail" "func" "if"
444 "implementation" "import_module" "include_module" "inst" "instance"
445 "interface" "mode" "module" "not" "pragma" "pred" "some" "then" "true"
446 "type" "typeclass" "use_module" "where"))
447 (sicstus
448 ("block" "dynamic" "mode" "module" "multifile" "meta_predicate"
449 "parallel" "public" "sequential" "volatile"))
450 (swi
451 ("discontiguous" "dynamic" "ensure_loaded" "export" "export_list" "import"
452 "meta_predicate" "module" "module_transparent" "multifile" "require"
453 "use_module" "volatile"))
454 (gnu
455 ("built_in" "char_conversion" "discontiguous" "dynamic" "ensure_linked"
456 "ensure_loaded" "foreign" "include" "initialization" "multifile" "op"
457 "public" "set_prolog_flag"))
459 ;; FIXME: Shouldn't we just use the union of all the above here?
460 ("dynamic" "module")))
461 "Alist of Prolog keywords which is used for font locking of directives."
462 :version "24.1"
463 :group 'prolog-font-lock
464 :type 'sexp)
466 (defcustom prolog-types
467 '((mercury
468 ("char" "float" "int" "io__state" "string" "univ"))
469 (t nil))
470 "Alist of Prolog types used by font locking."
471 :version "24.1"
472 :group 'prolog-font-lock
473 :type 'sexp)
475 (defcustom prolog-mode-specificators
476 '((mercury
477 ("bound" "di" "free" "ground" "in" "mdi" "mui" "muo" "out" "ui" "uo"))
478 (t nil))
479 "Alist of Prolog mode specificators used by font locking."
480 :version "24.1"
481 :group 'prolog-font-lock
482 :type 'sexp)
484 (defcustom prolog-determinism-specificators
485 '((mercury
486 ("cc_multi" "cc_nondet" "det" "erroneous" "failure" "multi" "nondet"
487 "semidet"))
488 (t nil))
489 "Alist of Prolog determinism specificators used by font locking."
490 :version "24.1"
491 :group 'prolog-font-lock
492 :type 'sexp)
494 (defcustom prolog-directives
495 '((mercury
496 ("^#[0-9]+"))
497 (t nil))
498 "Alist of Prolog source code directives used by font locking."
499 :version "24.1"
500 :group 'prolog-font-lock
501 :type 'sexp)
504 ;; Keyboard
506 (defcustom prolog-electric-newline-flag (not (fboundp 'electric-indent-mode))
507 "Non-nil means automatically indent the next line when the user types RET."
508 :version "24.1"
509 :group 'prolog-keyboard
510 :type 'boolean)
512 (defcustom prolog-hungry-delete-key-flag nil
513 "Non-nil means delete key consumes all preceding spaces."
514 :version "24.1"
515 :group 'prolog-keyboard
516 :type 'boolean)
518 (defcustom prolog-electric-dot-flag nil
519 "Non-nil means make dot key electric.
520 Electric dot appends newline or inserts head of a new clause.
521 If dot is pressed at the end of a line where at least one white space
522 precedes the point, it inserts a recursive call to the current predicate.
523 If dot is pressed at the beginning of an empty line, it inserts the head
524 of a new clause for the current predicate. It does not apply in strings
525 and comments.
526 It does not apply in strings and comments."
527 :version "24.1"
528 :group 'prolog-keyboard
529 :type 'boolean)
531 (defcustom prolog-electric-dot-full-predicate-template nil
532 "If nil, electric dot inserts only the current predicate's name and `('
533 for recursive calls or new clause heads. Non-nil means to also
534 insert enough commas to cover the predicate's arity and `)',
535 and dot and newline for recursive calls."
536 :version "24.1"
537 :group 'prolog-keyboard
538 :type 'boolean)
540 (defcustom prolog-electric-underscore-flag nil
541 "Non-nil means make underscore key electric.
542 Electric underscore replaces the current variable with underscore.
543 If underscore is pressed not on a variable then it behaves as usual."
544 :version "24.1"
545 :group 'prolog-keyboard
546 :type 'boolean)
548 (defcustom prolog-electric-tab-flag nil
549 "Non-nil means make TAB key electric.
550 Electric TAB inserts spaces after parentheses, ->, and ;
551 in ( If -> Then ; Else) and ( Disj1 ; Disj2 ) style expressions."
552 :version "24.1"
553 :group 'prolog-keyboard
554 :type 'boolean)
556 (defcustom prolog-electric-if-then-else-flag nil
557 "Non-nil makes `(', `>' and `;' electric
558 to automatically indent if-then-else constructs."
559 :version "24.1"
560 :group 'prolog-keyboard
561 :type 'boolean)
563 (defcustom prolog-electric-colon-flag nil
564 "Makes `:' electric (inserts `:-' on a new line).
565 If non-nil, pressing `:' at the end of a line that starts in
566 the first column (i.e., clause heads) inserts ` :-' and newline."
567 :version "24.1"
568 :group 'prolog-keyboard
569 :type 'boolean)
571 (defcustom prolog-electric-dash-flag nil
572 "Makes `-' electric (inserts a `-->' on a new line).
573 If non-nil, pressing `-' at the end of a line that starts in
574 the first column (i.e., DCG heads) inserts ` -->' and newline."
575 :version "24.1"
576 :group 'prolog-keyboard
577 :type 'boolean)
579 (defcustom prolog-old-sicstus-keys-flag nil
580 "Non-nil means old SICStus Prolog mode keybindings are used."
581 :version "24.1"
582 :group 'prolog-keyboard
583 :type 'boolean)
585 ;; Inferior mode
587 (defcustom prolog-program-name
588 `(((getenv "EPROLOG") (eval (getenv "EPROLOG")))
589 (eclipse "eclipse")
590 (mercury nil)
591 (sicstus "sicstus")
592 (swi ,(if (not (executable-find "swipl")) "pl" "swipl"))
593 (gnu "gprolog")
594 (t ,(let ((names '("prolog" "gprolog" "swipl" "pl")))
595 (while (and names
596 (not (executable-find (car names))))
597 (setq names (cdr names)))
598 (or (car names) "prolog"))))
599 "Alist of program names for invoking an inferior Prolog with `run-prolog'."
600 :group 'prolog-inferior
601 :type 'sexp)
602 (defun prolog-program-name ()
603 (prolog-find-value-by-system prolog-program-name))
605 (defcustom prolog-program-switches
606 '((sicstus ("-i"))
607 (t nil))
608 "Alist of switches given to inferior Prolog run with `run-prolog'."
609 :version "24.1"
610 :group 'prolog-inferior
611 :type 'sexp)
612 (defun prolog-program-switches ()
613 (prolog-find-value-by-system prolog-program-switches))
615 (defcustom prolog-consult-string
616 '((eclipse "[%f].")
617 (mercury nil)
618 (sicstus (eval (if (prolog-atleast-version '(3 . 7))
619 "prolog:zap_file(%m,%b,consult,%l)."
620 "prolog:zap_file(%m,%b,consult).")))
621 (swi "[%f].")
622 (gnu "[%f].")
623 (t "reconsult(%f)."))
624 "Alist of strings defining predicate for reconsulting.
626 Some parts of the string are replaced:
627 `%f' by the name of the consulted file (can be a temporary file)
628 `%b' by the file name of the buffer to consult
629 `%m' by the module name and name of the consulted file separated by colon
630 `%l' by the line offset into the file. This is 0 unless consulting a
631 region of a buffer, in which case it is the number of lines before
632 the region."
633 :group 'prolog-inferior
634 :type 'sexp)
635 (defun prolog-consult-string ()
636 (prolog-find-value-by-system prolog-consult-string))
638 (defcustom prolog-compile-string
639 '((eclipse "[%f].")
640 (mercury "mmake ")
641 (sicstus (eval (if (prolog-atleast-version '(3 . 7))
642 "prolog:zap_file(%m,%b,compile,%l)."
643 "prolog:zap_file(%m,%b,compile).")))
644 (swi "[%f].")
645 (t "compile(%f)."))
646 "Alist of strings and lists defining predicate for recompilation.
648 Some parts of the string are replaced:
649 `%f' by the name of the compiled file (can be a temporary file)
650 `%b' by the file name of the buffer to compile
651 `%m' by the module name and name of the compiled file separated by colon
652 `%l' by the line offset into the file. This is 0 unless compiling a
653 region of a buffer, in which case it is the number of lines before
654 the region.
656 If `prolog-program-name' is non-nil, it is a string sent to a Prolog process.
657 If `prolog-program-name' is nil, it is an argument to the `compile' function."
658 :group 'prolog-inferior
659 :type 'sexp)
660 (defun prolog-compile-string ()
661 (prolog-find-value-by-system prolog-compile-string))
663 (defcustom prolog-eof-string "end_of_file.\n"
664 "Alist of strings that represent end of file for prolog.
665 nil means send actual operating system end of file."
666 :group 'prolog-inferior
667 :type 'sexp)
669 (defcustom prolog-prompt-regexp
670 '((eclipse "^[a-zA-Z0-9()]* *\\?- \\|^\\[[a-zA-Z]* [0-9]*\\]:")
671 (sicstus "| [ ?][- ] *")
672 (swi "^\\(\\[[a-zA-Z]*\\] \\)?[1-9]?[0-9]*[ ]?\\?- \\|^| +")
673 (gnu "^| \\?-")
674 (t "^|? *\\?-"))
675 "Alist of prompts of the prolog system command line."
676 :version "24.1"
677 :group 'prolog-inferior
678 :type 'sexp)
679 (defun prolog-prompt-regexp ()
680 (prolog-find-value-by-system prolog-prompt-regexp))
682 ;; (defcustom prolog-continued-prompt-regexp
683 ;; '((sicstus "^\\(| +\\| +\\)")
684 ;; (t "^|: +"))
685 ;; "Alist of regexps matching the prompt when consulting `user'."
686 ;; :group 'prolog-inferior
687 ;; :type 'sexp)
689 (defcustom prolog-debug-on-string "debug.\n"
690 "Predicate for enabling debug mode."
691 :version "24.1"
692 :group 'prolog-inferior
693 :type 'string)
695 (defcustom prolog-debug-off-string "nodebug.\n"
696 "Predicate for disabling debug mode."
697 :version "24.1"
698 :group 'prolog-inferior
699 :type 'string)
701 (defcustom prolog-trace-on-string "trace.\n"
702 "Predicate for enabling tracing."
703 :version "24.1"
704 :group 'prolog-inferior
705 :type 'string)
707 (defcustom prolog-trace-off-string "notrace.\n"
708 "Predicate for disabling tracing."
709 :version "24.1"
710 :group 'prolog-inferior
711 :type 'string)
713 (defcustom prolog-zip-on-string "zip.\n"
714 "Predicate for enabling zip mode for SICStus."
715 :version "24.1"
716 :group 'prolog-inferior
717 :type 'string)
719 (defcustom prolog-zip-off-string "nozip.\n"
720 "Predicate for disabling zip mode for SICStus."
721 :version "24.1"
722 :group 'prolog-inferior
723 :type 'string)
725 (defcustom prolog-use-standard-consult-compile-method-flag t
726 "Non-nil means use the standard compilation method.
727 Otherwise the new compilation method will be used. This
728 utilizes a special compilation buffer with the associated
729 features such as parsing of error messages and automatically
730 jumping to the source code responsible for the error.
732 Warning: the new method is so far only experimental and
733 does contain bugs. The recommended setting for the novice user
734 is non-nil for this variable."
735 :version "24.1"
736 :group 'prolog-inferior
737 :type 'boolean)
740 ;; Miscellaneous
742 (defcustom prolog-use-prolog-tokenizer-flag
743 (not (fboundp 'syntax-propertize-rules))
744 "Non-nil means use the internal prolog tokenizer for indentation etc.
745 Otherwise use `parse-partial-sexp' which is faster but sometimes incorrect."
746 :version "24.1"
747 :group 'prolog-other
748 :type 'boolean)
750 (defcustom prolog-imenu-flag t
751 "Non-nil means add a clause index menu for all prolog files."
752 :version "24.1"
753 :group 'prolog-other
754 :type 'boolean)
756 (defcustom prolog-imenu-max-lines 3000
757 "The maximum number of lines of the file for imenu to be enabled.
758 Relevant only when `prolog-imenu-flag' is non-nil."
759 :version "24.1"
760 :group 'prolog-other
761 :type 'integer)
763 (defcustom prolog-info-predicate-index
764 "(sicstus)Predicate Index"
765 "The info node for the SICStus predicate index."
766 :version "24.1"
767 :group 'prolog-other
768 :type 'string)
770 (defcustom prolog-underscore-wordchar-flag nil
771 "Non-nil means underscore (_) is a word-constituent character."
772 :version "24.1"
773 :group 'prolog-other
774 :type 'boolean)
775 (make-obsolete-variable 'prolog-underscore-wordchar-flag
776 'superword-mode "24.4")
778 (defcustom prolog-use-sicstus-sd nil
779 "If non-nil, use the source level debugger of SICStus 3#7 and later."
780 :version "24.1"
781 :group 'prolog-other
782 :type 'boolean)
784 (defcustom prolog-char-quote-workaround nil
785 "If non-nil, declare 0 as a quote character to handle 0'<char>.
786 This is really kludgy, and unneeded (i.e. obsolete) in Emacs>=24."
787 :version "24.1"
788 :group 'prolog-other
789 :type 'boolean)
790 (make-obsolete-variable 'prolog-char-quote-workaround nil "24.1")
793 ;;-------------------------------------------------------------------
794 ;; Internal variables
795 ;;-------------------------------------------------------------------
797 ;;(defvar prolog-temp-filename "") ; Later set by `prolog-temporary-file'
799 (defvar prolog-mode-syntax-table
800 ;; The syntax accepted varies depending on the implementation used.
801 ;; Here are some of the differences:
802 ;; - SWI-Prolog accepts nested /*..*/ comments.
803 ;; - Edinburgh-style Prologs take <radix>'<number> for non-decimal number,
804 ;; whereas ISO-style Prologs use 0[obx]<number> instead.
805 ;; - In atoms \x<hex> sometimes needs a terminating \ (ISO-style)
806 ;; and sometimes not.
807 (let ((table (make-syntax-table)))
808 (modify-syntax-entry ?_ (if prolog-underscore-wordchar-flag "w" "_") table)
809 (modify-syntax-entry ?+ "." table)
810 (modify-syntax-entry ?- "." table)
811 (modify-syntax-entry ?= "." table)
812 (modify-syntax-entry ?< "." table)
813 (modify-syntax-entry ?> "." table)
814 (modify-syntax-entry ?| "." table)
815 (modify-syntax-entry ?\' "\"" table)
817 ;; Any better way to handle the 0'<char> construct?!?
818 (when (and prolog-char-quote-workaround
819 (not (fboundp 'syntax-propertize-rules)))
820 (modify-syntax-entry ?0 "\\" table))
822 (modify-syntax-entry ?% "<" table)
823 (modify-syntax-entry ?\n ">" table)
824 (if (featurep 'xemacs)
825 (progn
826 (modify-syntax-entry ?* ". 67" table)
827 (modify-syntax-entry ?/ ". 58" table)
829 ;; Emacs wants to see this it seems:
830 (modify-syntax-entry ?* ". 23b" table)
831 (modify-syntax-entry ?/ ". 14" table)
833 table))
834 (defvar prolog-mode-abbrev-table nil)
836 (if (eval-when-compile
837 (and (string-match "[[:upper:]]" "A")
838 (with-temp-buffer
839 (insert "A") (skip-chars-backward "[:upper:]") (bolp))))
840 (progn
841 (defconst prolog-upper-case-string "[:upper:]"
842 "A string containing a char-range matching all upper case characters.")
843 (defconst prolog-lower-case-string "[:lower:]"
844 "A string containing a char-range matching all lower case characters."))
846 ;; GNU Emacs compatibility: GNU Emacs does not differentiate between
847 ;; ints and chars, or at least these two are interchangeable.
848 (defalias 'prolog-int-to-char
849 (if (fboundp 'int-to-char) #'int-to-char #'identity))
851 (defalias 'prolog-char-to-int
852 (if (fboundp 'char-to-int) #'char-to-int #'identity))
854 (defun prolog-ints-intervals (ints)
855 "Return a list of intervals (from . to) covering INTS."
856 (when ints
857 (setq ints (sort ints '<))
858 (let ((prev (car ints))
859 (interval-start (car ints))
860 intervals)
861 (while ints
862 (let ((next (car ints)))
863 (when (> next (1+ prev)) ; start of new interval
864 (setq intervals (cons (cons interval-start prev) intervals))
865 (setq interval-start next))
866 (setq prev next)
867 (setq ints (cdr ints))))
868 (setq intervals (cons (cons interval-start prev) intervals))
869 (reverse intervals))))
871 (defun prolog-dash-letters (string)
872 "Return a condensed regexp covering all letters in STRING."
873 (let ((intervals (prolog-ints-intervals (mapcar #'prolog-char-to-int
874 (string-to-list string))))
875 codes)
876 (while intervals
877 (let* ((i (car intervals))
878 (from (car i))
879 (to (cdr i))
880 (c (cond ((= from to) `(,from))
881 ((= (1+ from) to) `(,from ,to))
882 (t `(,from ?- ,to)))))
883 (setq codes (cons c codes)))
884 (setq intervals (cdr intervals)))
885 (apply 'concat (reverse codes))))
887 (let ((up_string "")
888 (low_string ""))
889 ;; Use `map-char-table' if it is defined. Otherwise enumerate all
890 ;; numbers between 0 and 255. `map-char-table' is probably safer.
892 ;; `map-char-table' causes problems under Emacs 23.0.0.1, the
893 ;; while loop seems to do its job well (Ryszard Szopa)
895 ;;(if (and (not (featurep 'xemacs))
896 ;; (fboundp 'map-char-table))
897 ;; (map-char-table
898 ;; (lambda (key value)
899 ;; (cond
900 ;; ((and
901 ;; (eq (prolog-int-to-char key) (downcase key))
902 ;; (eq (prolog-int-to-char key) (upcase key)))
903 ;; ;; Do nothing if upper and lower case are the same
904 ;; )
905 ;; ((eq (prolog-int-to-char key) (downcase key))
906 ;; ;; The char is lower case
907 ;; (setq low_string (format "%s%c" low_string key)))
908 ;; ((eq (prolog-int-to-char key) (upcase key))
909 ;; ;; The char is upper case
910 ;; (setq up_string (format "%s%c" up_string key)))
911 ;; ))
912 ;; (current-case-table))
913 ;; `map-char-table' was undefined.
914 (let ((key 0))
915 (while (< key 256)
916 (cond
917 ((and
918 (eq (prolog-int-to-char key) (downcase key))
919 (eq (prolog-int-to-char key) (upcase key)))
920 ;; Do nothing if upper and lower case are the same
922 ((eq (prolog-int-to-char key) (downcase key))
923 ;; The char is lower case
924 (setq low_string (format "%s%c" low_string key)))
925 ((eq (prolog-int-to-char key) (upcase key))
926 ;; The char is upper case
927 (setq up_string (format "%s%c" up_string key)))
929 (setq key (1+ key))))
930 ;; )
931 ;; The strings are single-byte strings.
932 (defconst prolog-upper-case-string (prolog-dash-letters up_string)
933 "A string containing a char-range matching all upper case characters.")
934 (defconst prolog-lower-case-string (prolog-dash-letters low_string)
935 "A string containing a char-range matching all lower case characters.")
938 (defconst prolog-atom-char-regexp
939 (if (string-match "[[:alnum:]]" "0")
940 "[[:alnum:]_$]"
941 (format "[%s%s0-9_$]" prolog-lower-case-string prolog-upper-case-string))
942 "Regexp specifying characters which constitute atoms without quoting.")
943 (defconst prolog-atom-regexp
944 (format "[%s$]%s*" prolog-lower-case-string prolog-atom-char-regexp))
946 (defconst prolog-left-paren "[[({]" ;FIXME: Why not \\s(?
947 "The characters used as left parentheses for the indentation code.")
948 (defconst prolog-right-paren "[])}]" ;FIXME: Why not \\s)?
949 "The characters used as right parentheses for the indentation code.")
951 (defconst prolog-quoted-atom-regexp
952 "\\(^\\|[^0-9]\\)\\('\\([^\n']\\|\\\\'\\)*'\\)"
953 "Regexp matching a quoted atom.")
954 (defconst prolog-string-regexp
955 "\\(\"\\([^\n\"]\\|\\\\\"\\)*\"\\)"
956 "Regexp matching a string.")
957 (defconst prolog-head-delimiter "\\(:-\\|\\+:\\|-:\\|\\+\\?\\|-\\?\\|-->\\)"
958 "A regexp for matching on the end delimiter of a head (e.g. \":-\").")
960 (defvar prolog-compilation-buffer "*prolog-compilation*"
961 "Name of the output buffer for Prolog compilation/consulting.")
963 (defvar prolog-temporary-file-name nil)
964 (defvar prolog-keywords-i nil)
965 (defvar prolog-types-i nil)
966 (defvar prolog-mode-specificators-i nil)
967 (defvar prolog-determinism-specificators-i nil)
968 (defvar prolog-directives-i nil)
969 (defvar prolog-eof-string-i nil)
970 ;; (defvar prolog-continued-prompt-regexp-i nil)
971 (defvar prolog-help-function-i nil)
973 (defvar prolog-align-rules
974 (eval-when-compile
975 (mapcar
976 (lambda (x)
977 (let ((name (car x))
978 (sym (cdr x)))
979 `(,(intern (format "prolog-%s" name))
980 (regexp . ,(format "\\(\\s-*\\)%s\\(\\s-*\\)" sym))
981 (tab-stop . nil)
982 (modes . '(prolog-mode))
983 (group . (1 2)))))
984 '(("dcg" . "-->") ("rule" . ":-") ("simplification" . "<=>")
985 ("propagation" . "==>")))))
987 ;; SMIE support
989 (require 'smie)
991 (defvar prolog-use-smie t)
993 (defun prolog-smie-forward-token ()
994 ;; FIXME: Add support for 0'<char>, if needed after adding it to
995 ;; syntax-propertize-functions.
996 (forward-comment (point-max))
997 (buffer-substring-no-properties
998 (point)
999 (progn (cond
1000 ((looking-at "[!;]") (forward-char 1))
1001 ((not (zerop (skip-chars-forward "#&*+-./:<=>?@\\^`~"))))
1002 ((not (zerop (skip-syntax-forward "w_'"))))
1003 ;; In case of non-ASCII punctuation.
1004 ((not (zerop (skip-syntax-forward ".")))))
1005 (point))))
1007 (defun prolog-smie-backward-token ()
1008 ;; FIXME: Add support for 0'<char>, if needed after adding it to
1009 ;; syntax-propertize-functions.
1010 (forward-comment (- (point-max)))
1011 (buffer-substring-no-properties
1012 (point)
1013 (progn (cond
1014 ((memq (char-before) '(?! ?\;)) (forward-char -1))
1015 ((not (zerop (skip-chars-backward "#&*+-./:<=>?@\\^`~"))))
1016 ((not (zerop (skip-syntax-backward "w_'"))))
1017 ;; In case of non-ASCII punctuation.
1018 ((not (zerop (skip-syntax-backward ".")))))
1019 (point))))
1021 (defconst prolog-smie-grammar
1022 ;; Rather than construct the operator levels table from the BNF,
1023 ;; we directly provide the operator precedences from GNU Prolog's
1024 ;; manual (7.14.10 op/3). The only problem is that GNU Prolog's
1025 ;; manual uses precedence levels in the opposite sense (higher
1026 ;; numbers bind less tightly) than SMIE, so we use negative numbers.
1027 '(("." -10000 -10000)
1028 (":-" -1200 -1200)
1029 ("-->" -1200 -1200)
1030 (";" -1100 -1100)
1031 ("->" -1050 -1050)
1032 ("," -1000 -1000)
1033 ("\\+" -900 -900)
1034 ("=" -700 -700)
1035 ("\\=" -700 -700)
1036 ("=.." -700 -700)
1037 ("==" -700 -700)
1038 ("\\==" -700 -700)
1039 ("@<" -700 -700)
1040 ("@=<" -700 -700)
1041 ("@>" -700 -700)
1042 ("@>=" -700 -700)
1043 ("is" -700 -700)
1044 ("=:=" -700 -700)
1045 ("=\\=" -700 -700)
1046 ("<" -700 -700)
1047 ("=<" -700 -700)
1048 (">" -700 -700)
1049 (">=" -700 -700)
1050 (":" -600 -600)
1051 ("+" -500 -500)
1052 ("-" -500 -500)
1053 ("/\\" -500 -500)
1054 ("\\/" -500 -500)
1055 ("*" -400 -400)
1056 ("/" -400 -400)
1057 ("//" -400 -400)
1058 ("rem" -400 -400)
1059 ("mod" -400 -400)
1060 ("<<" -400 -400)
1061 (">>" -400 -400)
1062 ("**" -200 -200)
1063 ("^" -200 -200)
1064 ;; Prefix
1065 ;; ("+" 200 200)
1066 ;; ("-" 200 200)
1067 ;; ("\\" 200 200)
1068 (:smie-closer-alist (t . "."))
1070 "Precedence levels of infix operators.")
1072 (defun prolog-smie-rules (kind token)
1073 (pcase (cons kind token)
1074 (`(:elem . basic) prolog-indent-width)
1075 (`(:after . ".") '(column . 0)) ;; To work around smie-closer-alist.
1076 (`(:after . ,(or `":-" `"->" `"-->")) prolog-indent-width)))
1079 ;;-------------------------------------------------------------------
1080 ;; Prolog mode
1081 ;;-------------------------------------------------------------------
1083 ;; Example: (prolog-atleast-version '(3 . 6))
1084 (defun prolog-atleast-version (version)
1085 "Return t if the version of the current prolog system is VERSION or later.
1086 VERSION is of the format (Major . Minor)"
1087 ;; Version.major < major or
1088 ;; Version.major = major and Version.minor <= minor
1089 (let* ((thisversion (prolog-find-value-by-system prolog-system-version))
1090 (thismajor (car thisversion))
1091 (thisminor (cdr thisversion)))
1092 (or (< (car version) thismajor)
1093 (and (= (car version) thismajor)
1094 (<= (cdr version) thisminor)))
1097 (define-abbrev-table 'prolog-mode-abbrev-table ())
1099 (defun prolog-find-value-by-system (alist)
1100 "Get value from ALIST according to `prolog-system'."
1101 (let ((system (or prolog-system
1102 (let ((infbuf (prolog-inferior-buffer 'dont-run)))
1103 (when infbuf
1104 (buffer-local-value 'prolog-system infbuf))))))
1105 (if (listp alist)
1106 (let (result
1108 (while alist
1109 (setq id (car (car alist)))
1110 (if (or (eq id system)
1111 (eq id t)
1112 (and (listp id)
1113 (eval id)))
1114 (progn
1115 (setq result (car (cdr (car alist))))
1116 (if (and (listp result)
1117 (eq (car result) 'eval))
1118 (setq result (eval (car (cdr result)))))
1119 (setq alist nil))
1120 (setq alist (cdr alist))))
1121 result)
1122 alist)))
1124 (defconst prolog-syntax-propertize-function
1125 (when (fboundp 'syntax-propertize-rules)
1126 (syntax-propertize-rules
1127 ;; GNU Prolog only accepts 0'\' rather than 0'', but the only
1128 ;; possible meaning of 0'' is rather clear.
1129 ("\\<0\\(''?\\)"
1130 (1 (unless (save-excursion (nth 8 (syntax-ppss (match-beginning 0))))
1131 (string-to-syntax "_"))))
1132 ;; We could check that we're not inside an atom, but I don't think
1133 ;; that 'foo 8'z could be a valid syntax anyway, so why bother?
1134 ("\\<[1-9][0-9]*\\('\\)[0-9a-zA-Z]" (1 "_"))
1135 ;; Supposedly, ISO-Prolog wants \NNN\ for octal and \xNNN\ for hexadecimal
1136 ;; escape sequences in atoms, so be careful not to let the terminating \
1137 ;; escape a subsequent quote.
1138 ("\\\\[x0-7][0-9a-fA-F]*\\(\\\\\\)" (1 "_"))
1141 (defun prolog-mode-variables ()
1142 "Set some common variables to Prolog code specific values."
1143 (setq local-abbrev-table prolog-mode-abbrev-table)
1144 (set (make-local-variable 'paragraph-start)
1145 (concat "[ \t]*$\\|" page-delimiter)) ;'%%..'
1146 (set (make-local-variable 'paragraph-separate) paragraph-start)
1147 (set (make-local-variable 'paragraph-ignore-fill-prefix) t)
1148 (set (make-local-variable 'normal-auto-fill-function) 'prolog-do-auto-fill)
1149 (set (make-local-variable 'comment-start) "%")
1150 (set (make-local-variable 'comment-end) "")
1151 (set (make-local-variable 'comment-add) 1)
1152 (set (make-local-variable 'comment-start-skip) "\\(?:/\\*+ *\\|%%+ *\\)")
1153 (set (make-local-variable 'parens-require-spaces) nil)
1154 ;; Initialize Prolog system specific variables
1155 (dolist (var '(prolog-keywords prolog-types prolog-mode-specificators
1156 prolog-determinism-specificators prolog-directives
1157 prolog-eof-string
1158 ;; prolog-continued-prompt-regexp
1159 prolog-help-function))
1160 (set (intern (concat (symbol-name var) "-i"))
1161 (prolog-find-value-by-system (symbol-value var))))
1162 (when (null (prolog-program-name))
1163 (set (make-local-variable 'compile-command) (prolog-compile-string)))
1164 (set (make-local-variable 'font-lock-defaults)
1165 '(prolog-font-lock-keywords nil nil ((?_ . "w"))))
1166 (set (make-local-variable 'syntax-propertize-function)
1167 prolog-syntax-propertize-function)
1169 (if prolog-use-smie
1170 ;; Setup SMIE.
1171 (smie-setup prolog-smie-grammar #'prolog-smie-rules
1172 :forward-token #'prolog-smie-forward-token
1173 :backward-token #'prolog-smie-backward-token)
1174 (set (make-local-variable 'indent-line-function) 'prolog-indent-line))
1177 (defun prolog-mode-keybindings-common (map)
1178 "Define keybindings common to both Prolog modes in MAP."
1179 (define-key map "\C-c?" 'prolog-help-on-predicate)
1180 (define-key map "\C-c/" 'prolog-help-apropos)
1181 (define-key map "\C-c\C-d" 'prolog-debug-on)
1182 (define-key map "\C-c\C-t" 'prolog-trace-on)
1183 (define-key map "\C-c\C-z" 'prolog-zip-on)
1184 (define-key map "\C-c\r" 'run-prolog))
1186 (defun prolog-mode-keybindings-edit (map)
1187 "Define keybindings for Prolog mode in MAP."
1188 (define-key map "\M-a" 'prolog-beginning-of-clause)
1189 (define-key map "\M-e" 'prolog-end-of-clause)
1190 (define-key map "\M-q" 'prolog-fill-paragraph)
1191 (define-key map "\C-c\C-a" 'align)
1192 (define-key map "\C-\M-a" 'prolog-beginning-of-predicate)
1193 (define-key map "\C-\M-e" 'prolog-end-of-predicate)
1194 (define-key map "\M-\C-c" 'prolog-mark-clause)
1195 (define-key map "\M-\C-h" 'prolog-mark-predicate)
1196 (define-key map "\M-\C-n" 'prolog-forward-list)
1197 (define-key map "\M-\C-p" 'prolog-backward-list)
1198 (define-key map "\C-c\C-n" 'prolog-insert-predicate-template)
1199 (define-key map "\C-c\C-s" 'prolog-insert-predspec)
1200 (define-key map "\M-\r" 'prolog-insert-next-clause)
1201 (define-key map "\C-c\C-va" 'prolog-variables-to-anonymous)
1202 (define-key map "\C-c\C-v\C-s" 'prolog-view-predspec)
1204 (define-key map [Backspace] 'prolog-electric-delete)
1205 (define-key map "." 'prolog-electric-dot)
1206 (define-key map "_" 'prolog-electric-underscore)
1207 (define-key map "(" 'prolog-electric-if-then-else)
1208 (define-key map ";" 'prolog-electric-if-then-else)
1209 (define-key map ">" 'prolog-electric-if-then-else)
1210 (define-key map ":" 'prolog-electric-colon)
1211 (define-key map "-" 'prolog-electric-dash)
1212 (if prolog-electric-newline-flag
1213 (define-key map "\r" 'newline-and-indent))
1215 ;; If we're running SICStus, then map C-c C-c e/d to enabling
1216 ;; and disabling of the source-level debugging facilities.
1217 ;(if (and (eq prolog-system 'sicstus)
1218 ; (prolog-atleast-version '(3 . 7)))
1219 ; (progn
1220 ; (define-key map "\C-c\C-ce" 'prolog-enable-sicstus-sd)
1221 ; (define-key map "\C-c\C-cd" 'prolog-disable-sicstus-sd)
1222 ; ))
1224 (if prolog-old-sicstus-keys-flag
1225 (progn
1226 (define-key map "\C-c\C-c" 'prolog-consult-predicate)
1227 (define-key map "\C-cc" 'prolog-consult-region)
1228 (define-key map "\C-cC" 'prolog-consult-buffer)
1229 (define-key map "\C-c\C-k" 'prolog-compile-predicate)
1230 (define-key map "\C-ck" 'prolog-compile-region)
1231 (define-key map "\C-cK" 'prolog-compile-buffer))
1232 (define-key map "\C-c\C-p" 'prolog-consult-predicate)
1233 (define-key map "\C-c\C-r" 'prolog-consult-region)
1234 (define-key map "\C-c\C-b" 'prolog-consult-buffer)
1235 (define-key map "\C-c\C-f" 'prolog-consult-file)
1236 (define-key map "\C-c\C-cp" 'prolog-compile-predicate)
1237 (define-key map "\C-c\C-cr" 'prolog-compile-region)
1238 (define-key map "\C-c\C-cb" 'prolog-compile-buffer)
1239 (define-key map "\C-c\C-cf" 'prolog-compile-file))
1241 ;; Inherited from the old prolog.el.
1242 (define-key map "\e\C-x" 'prolog-consult-region)
1243 (define-key map "\C-c\C-l" 'prolog-consult-file)
1244 (define-key map "\C-c\C-z" 'switch-to-prolog))
1246 (defun prolog-mode-keybindings-inferior (_map)
1247 "Define keybindings for inferior Prolog mode in MAP."
1248 ;; No inferior mode specific keybindings now.
1251 (defvar prolog-mode-map
1252 (let ((map (make-sparse-keymap)))
1253 (prolog-mode-keybindings-common map)
1254 (prolog-mode-keybindings-edit map)
1255 map))
1258 (defvar prolog-mode-hook nil
1259 "List of functions to call after the prolog mode has initialized.")
1261 (unless (fboundp 'prog-mode)
1262 (defalias 'prog-mode 'fundamental-mode))
1263 ;;;###autoload
1264 (define-derived-mode prolog-mode prog-mode "Prolog"
1265 "Major mode for editing Prolog code.
1267 Blank lines and `%%...' separate paragraphs. `%'s starts a comment
1268 line and comments can also be enclosed in /* ... */.
1270 If an optional argument SYSTEM is non-nil, set up mode for the given system.
1272 To find out what version of Prolog mode you are running, enter
1273 `\\[prolog-mode-version]'.
1275 Commands:
1276 \\{prolog-mode-map}
1277 Entry to this mode calls the value of `prolog-mode-hook'
1278 if that value is non-nil."
1279 (setq mode-name (concat "Prolog"
1280 (cond
1281 ((eq prolog-system 'eclipse) "[ECLiPSe]")
1282 ((eq prolog-system 'sicstus) "[SICStus]")
1283 ((eq prolog-system 'swi) "[SWI]")
1284 ((eq prolog-system 'gnu) "[GNU]")
1285 (t ""))))
1286 (prolog-mode-variables)
1287 (dolist (ar prolog-align-rules) (add-to-list 'align-rules-list ar))
1289 ;; `imenu' entry moved to the appropriate hook for consistency.
1291 ;; Load SICStus debugger if suitable
1292 (if (and (eq prolog-system 'sicstus)
1293 (prolog-atleast-version '(3 . 7))
1294 prolog-use-sicstus-sd)
1295 (prolog-enable-sicstus-sd))
1297 (prolog-menu))
1299 (defvar mercury-mode-map
1300 (let ((map (make-sparse-keymap)))
1301 (set-keymap-parent map prolog-mode-map)
1302 map))
1304 ;;;###autoload
1305 (define-derived-mode mercury-mode prolog-mode "Prolog[Mercury]"
1306 "Major mode for editing Mercury programs.
1307 Actually this is just customized `prolog-mode'."
1308 (set (make-local-variable 'prolog-system) 'mercury))
1311 ;;-------------------------------------------------------------------
1312 ;; Inferior prolog mode
1313 ;;-------------------------------------------------------------------
1315 (defvar prolog-inferior-mode-map
1316 (let ((map (make-sparse-keymap)))
1317 (prolog-mode-keybindings-common map)
1318 (prolog-mode-keybindings-inferior map)
1319 (define-key map [remap self-insert-command]
1320 'prolog-inferior-self-insert-command)
1321 map))
1323 (defvar prolog-inferior-mode-hook nil
1324 "List of functions to call after the inferior prolog mode has initialized.")
1326 (defvar prolog-inferior-error-regexp-alist
1327 '(;; GNU Prolog used to not follow the GNU standard format.
1328 ;; ("^\\(.*?\\):\\([0-9]+\\) error: .*(char:\\([0-9]+\\)" 1 2 3)
1329 ;; SWI-Prolog.
1330 ("^\\(?:\\?- *\\)?\\(\\(?:ERROR\\|\\(W\\)arning\\): *\\(.*?\\):\\([1-9][0-9]*\\):\\(?:\\([0-9]*\\):\\)?\\)\\(?:$\\| \\)"
1331 3 4 5 (2 . nil) 1)
1332 ;; GNU-Prolog now uses the GNU standard format.
1333 gnu))
1335 (defun prolog-inferior-self-insert-command ()
1336 "Insert the char in the buffer or pass it directly to the process."
1337 (interactive)
1338 (let* ((proc (get-buffer-process (current-buffer)))
1339 (pmark (and proc (marker-position (process-mark proc)))))
1340 ;; FIXME: the same treatment would be needed for SWI-Prolog, but I can't
1341 ;; seem to find any way for Emacs to figure out when to use it because
1342 ;; SWI doesn't include a " ? " or some such recognizable marker.
1343 (if (and (eq prolog-system 'gnu)
1344 pmark
1345 (null current-prefix-arg)
1346 (eobp)
1347 (eq (point) pmark)
1348 (save-excursion
1349 (goto-char (- pmark 3))
1350 ;; FIXME: check this comes from the process's output, maybe?
1351 (looking-at " \\? ")))
1352 ;; This is GNU prolog waiting to know whether you want more answers
1353 ;; or not (or abort, etc...). The answer is a single char, not
1354 ;; a line, so pass this char directly rather than wait for RET to
1355 ;; send a whole line.
1356 (comint-send-string proc (string last-command-event))
1357 (call-interactively 'self-insert-command))))
1359 (declare-function 'compilation-shell-minor-mode "compile" (&optional arg))
1360 (defvar compilation-error-regexp-alist)
1362 (define-derived-mode prolog-inferior-mode comint-mode "Inferior Prolog"
1363 "Major mode for interacting with an inferior Prolog process.
1365 The following commands are available:
1366 \\{prolog-inferior-mode-map}
1368 Entry to this mode calls the value of `prolog-mode-hook' with no arguments,
1369 if that value is non-nil. Likewise with the value of `comint-mode-hook'.
1370 `prolog-mode-hook' is called after `comint-mode-hook'.
1372 You can send text to the inferior Prolog from other buffers
1373 using the commands `send-region', `send-string' and \\[prolog-consult-region].
1375 Commands:
1376 Tab indents for Prolog; with argument, shifts rest
1377 of expression rigidly with the current line.
1378 Paragraphs are separated only by blank lines and '%%'. '%'s start comments.
1380 Return at end of buffer sends line as input.
1381 Return not at end copies rest of line to end and sends it.
1382 \\[comint-delchar-or-maybe-eof] sends end-of-file as input.
1383 \\[comint-kill-input] and \\[backward-kill-word] are kill commands,
1384 imitating normal Unix input editing.
1385 \\[comint-interrupt-subjob] interrupts the shell or its current subjob if any.
1386 \\[comint-stop-subjob] stops, likewise.
1387 \\[comint-quit-subjob] sends quit signal, likewise.
1389 To find out what version of Prolog mode you are running, enter
1390 `\\[prolog-mode-version]'."
1391 (require 'compile)
1392 (setq comint-input-filter 'prolog-input-filter)
1393 (setq mode-line-process '(": %s"))
1394 (prolog-mode-variables)
1395 (setq comint-prompt-regexp (prolog-prompt-regexp))
1396 (set (make-local-variable 'shell-dirstack-query) "pwd.")
1397 (set (make-local-variable 'compilation-error-regexp-alist)
1398 prolog-inferior-error-regexp-alist)
1399 (compilation-shell-minor-mode)
1400 (prolog-inferior-menu))
1402 (defun prolog-input-filter (str)
1403 (cond ((string-match "\\`\\s *\\'" str) nil) ;whitespace
1404 ((not (derived-mode-p 'prolog-inferior-mode)) t)
1405 ((= (length str) 1) nil) ;one character
1406 ((string-match "\\`[rf] *[0-9]*\\'" str) nil) ;r(edo) or f(ail)
1407 (t t)))
1409 ;;;###autoload
1410 (defun run-prolog (arg)
1411 "Run an inferior Prolog process, input and output via buffer *prolog*.
1412 With prefix argument ARG, restart the Prolog process if running before."
1413 (interactive "P")
1414 ;; FIXME: It should be possible to interactively specify the command to use
1415 ;; to run prolog.
1416 (if (and arg (get-process "prolog"))
1417 (progn
1418 (process-send-string "prolog" "halt.\n")
1419 (while (get-process "prolog") (sit-for 0.1))))
1420 (let ((buff (buffer-name)))
1421 (if (not (string= buff "*prolog*"))
1422 (prolog-goto-prolog-process-buffer))
1423 ;; Load SICStus debugger if suitable
1424 (if (and (eq prolog-system 'sicstus)
1425 (prolog-atleast-version '(3 . 7))
1426 prolog-use-sicstus-sd)
1427 (prolog-enable-sicstus-sd))
1428 (prolog-mode-variables)
1429 (prolog-ensure-process)
1432 (defun prolog-inferior-guess-flavor (&optional ignored)
1433 (setq prolog-system
1434 (when (or (numberp prolog-system) (markerp prolog-system))
1435 (save-excursion
1436 (goto-char (1+ prolog-system))
1437 (cond
1438 ((looking-at "GNU Prolog") 'gnu)
1439 ((looking-at "Welcome to SWI-Prolog\\|%.*\\<swi_") 'swi)
1440 ((looking-at ".*\n") nil) ;There's at least one line.
1441 (t prolog-system)))))
1442 (when (symbolp prolog-system)
1443 (remove-hook 'comint-output-filter-functions
1444 'prolog-inferior-guess-flavor t)
1445 (when prolog-system
1446 (setq comint-prompt-regexp (prolog-prompt-regexp))
1447 (if (eq prolog-system 'gnu)
1448 (set (make-local-variable 'comint-process-echoes) t)))))
1450 (defun prolog-ensure-process (&optional wait)
1451 "If Prolog process is not running, run it.
1452 If the optional argument WAIT is non-nil, wait for Prolog prompt specified by
1453 the variable `prolog-prompt-regexp'."
1454 (if (null (prolog-program-name))
1455 (error "This Prolog system has defined no interpreter."))
1456 (if (comint-check-proc "*prolog*")
1458 (with-current-buffer (get-buffer-create "*prolog*")
1459 (prolog-inferior-mode)
1460 (apply 'make-comint-in-buffer "prolog" (current-buffer)
1461 (prolog-program-name) nil (prolog-program-switches))
1462 (unless prolog-system
1463 ;; Setup auto-detection.
1464 (set (make-local-variable 'prolog-system)
1465 ;; Force re-detection.
1466 (let* ((proc (get-buffer-process (current-buffer)))
1467 (pmark (and proc (marker-position (process-mark proc)))))
1468 (cond
1469 ((null pmark) (1- (point-min)))
1470 ;; The use of insert-before-markers in comint.el together with
1471 ;; the potential use of comint-truncate-buffer in the output
1472 ;; filter, means that it's difficult to reliably keep track of
1473 ;; the buffer position where the process's output started.
1474 ;; If possible we use a marker at "start - 1", so that
1475 ;; insert-before-marker at `start' won't shift it. And if not,
1476 ;; we fall back on using a plain integer.
1477 ((> pmark (point-min)) (copy-marker (1- pmark)))
1478 (t (1- pmark)))))
1479 (add-hook 'comint-output-filter-functions
1480 'prolog-inferior-guess-flavor nil t))
1481 (if wait
1482 (progn
1483 (goto-char (point-max))
1484 (while
1485 (save-excursion
1486 (not
1487 (re-search-backward
1488 (concat "\\(" (prolog-prompt-regexp) "\\)" "\\=")
1489 nil t)))
1490 (sit-for 0.1)))))))
1492 (defun prolog-inferior-buffer (&optional dont-run)
1493 (or (get-buffer "*prolog*")
1494 (unless dont-run
1495 (prolog-ensure-process)
1496 (get-buffer "*prolog*"))))
1498 (defun prolog-process-insert-string (process string)
1499 "Insert STRING into inferior Prolog buffer running PROCESS."
1500 ;; Copied from elisp manual, greek to me
1501 (with-current-buffer (process-buffer process)
1502 ;; FIXME: Use window-point-insertion-type instead.
1503 (let ((moving (= (point) (process-mark process))))
1504 (save-excursion
1505 ;; Insert the text, moving the process-marker.
1506 (goto-char (process-mark process))
1507 (insert string)
1508 (set-marker (process-mark process) (point)))
1509 (if moving (goto-char (process-mark process))))))
1511 ;;------------------------------------------------------------
1512 ;; Old consulting and compiling functions
1513 ;;------------------------------------------------------------
1515 (declare-function compilation-forget-errors "compile" ())
1516 (declare-function compilation-fake-loc "compile"
1517 (marker file &optional line col))
1519 (defun prolog-old-process-region (compilep start end)
1520 "Process the region limited by START and END positions.
1521 If COMPILEP is non-nil then use compilation, otherwise consulting."
1522 (prolog-ensure-process)
1523 ;(let ((tmpfile prolog-temp-filename)
1524 (let ((tmpfile (prolog-temporary-file))
1525 ;(process (get-process "prolog"))
1526 (first-line (1+ (count-lines
1527 (point-min)
1528 (save-excursion
1529 (goto-char start)
1530 (point))))))
1531 (write-region start end tmpfile)
1532 (setq start (copy-marker start))
1533 (with-current-buffer (prolog-inferior-buffer)
1534 (compilation-forget-errors)
1535 (compilation-fake-loc start tmpfile))
1536 (process-send-string
1537 "prolog" (prolog-build-prolog-command
1538 compilep tmpfile (prolog-bsts buffer-file-name)
1539 first-line))
1540 (prolog-goto-prolog-process-buffer)))
1542 (defun prolog-old-process-predicate (compilep)
1543 "Process the predicate around point.
1544 If COMPILEP is non-nil then use compilation, otherwise consulting."
1545 (prolog-old-process-region
1546 compilep (prolog-pred-start) (prolog-pred-end)))
1548 (defun prolog-old-process-buffer (compilep)
1549 "Process the entire buffer.
1550 If COMPILEP is non-nil then use compilation, otherwise consulting."
1551 (prolog-old-process-region compilep (point-min) (point-max)))
1553 (defun prolog-old-process-file (compilep)
1554 "Process the file of the current buffer.
1555 If COMPILEP is non-nil then use compilation, otherwise consulting."
1556 (save-some-buffers)
1557 (prolog-ensure-process)
1558 (with-current-buffer (prolog-inferior-buffer)
1559 (compilation-forget-errors))
1560 (process-send-string
1561 "prolog" (prolog-build-prolog-command
1562 compilep buffer-file-name
1563 (prolog-bsts buffer-file-name)))
1564 (prolog-goto-prolog-process-buffer))
1567 ;;------------------------------------------------------------
1568 ;; Consulting and compiling
1569 ;;------------------------------------------------------------
1571 ;; Interactive interface functions, used by both the standard
1572 ;; and the experimental consultation and compilation functions
1573 (defun prolog-consult-file ()
1574 "Consult file of current buffer."
1575 (interactive)
1576 (if prolog-use-standard-consult-compile-method-flag
1577 (prolog-old-process-file nil)
1578 (prolog-consult-compile-file nil)))
1580 (defun prolog-consult-buffer ()
1581 "Consult buffer."
1582 (interactive)
1583 (if prolog-use-standard-consult-compile-method-flag
1584 (prolog-old-process-buffer nil)
1585 (prolog-consult-compile-buffer nil)))
1587 (defun prolog-consult-region (beg end)
1588 "Consult region between BEG and END."
1589 (interactive "r")
1590 (if prolog-use-standard-consult-compile-method-flag
1591 (prolog-old-process-region nil beg end)
1592 (prolog-consult-compile-region nil beg end)))
1594 (defun prolog-consult-predicate ()
1595 "Consult the predicate around current point."
1596 (interactive)
1597 (if prolog-use-standard-consult-compile-method-flag
1598 (prolog-old-process-predicate nil)
1599 (prolog-consult-compile-predicate nil)))
1601 (defun prolog-compile-file ()
1602 "Compile file of current buffer."
1603 (interactive)
1604 (if prolog-use-standard-consult-compile-method-flag
1605 (prolog-old-process-file t)
1606 (prolog-consult-compile-file t)))
1608 (defun prolog-compile-buffer ()
1609 "Compile buffer."
1610 (interactive)
1611 (if prolog-use-standard-consult-compile-method-flag
1612 (prolog-old-process-buffer t)
1613 (prolog-consult-compile-buffer t)))
1615 (defun prolog-compile-region (beg end)
1616 "Compile region between BEG and END."
1617 (interactive "r")
1618 (if prolog-use-standard-consult-compile-method-flag
1619 (prolog-old-process-region t beg end)
1620 (prolog-consult-compile-region t beg end)))
1622 (defun prolog-compile-predicate ()
1623 "Compile the predicate around current point."
1624 (interactive)
1625 (if prolog-use-standard-consult-compile-method-flag
1626 (prolog-old-process-predicate t)
1627 (prolog-consult-compile-predicate t)))
1629 (defun prolog-buffer-module ()
1630 "Select Prolog module name appropriate for current buffer.
1631 Bases decision on buffer contents (-*- line)."
1632 ;; Look for -*- ... module: MODULENAME; ... -*-
1633 (let (beg end)
1634 (save-excursion
1635 (goto-char (point-min))
1636 (skip-chars-forward " \t")
1637 (and (search-forward "-*-" (line-end-position) t)
1638 (progn
1639 (skip-chars-forward " \t")
1640 (setq beg (point))
1641 (search-forward "-*-" (line-end-position) t))
1642 (progn
1643 (forward-char -3)
1644 (skip-chars-backward " \t")
1645 (setq end (point))
1646 (goto-char beg)
1647 (and (let ((case-fold-search t))
1648 (search-forward "module:" end t))
1649 (progn
1650 (skip-chars-forward " \t")
1651 (setq beg (point))
1652 (if (search-forward ";" end t)
1653 (forward-char -1)
1654 (goto-char end))
1655 (skip-chars-backward " \t")
1656 (buffer-substring beg (point)))))))))
1658 (defun prolog-build-prolog-command (compilep file buffername
1659 &optional first-line)
1660 "Make Prolog command for FILE compilation/consulting.
1661 If COMPILEP is non-nil, consider compilation, otherwise consulting."
1662 (let* ((compile-string
1663 ;; FIXME: If the process is not running yet, the auto-detection of
1664 ;; prolog-system won't help here, so we should make sure
1665 ;; we first run Prolog and then build the command.
1666 (if compilep (prolog-compile-string) (prolog-consult-string)))
1667 (module (prolog-buffer-module))
1668 (file-name (concat "'" (prolog-bsts file) "'"))
1669 (module-name (if module (concat "'" module "'")))
1670 (module-file (if module
1671 (concat module-name ":" file-name)
1672 file-name))
1673 strbeg strend
1674 (lineoffset (if first-line
1675 (- first-line 1)
1676 0)))
1678 ;; Assure that there is a buffer name
1679 (if (not buffername)
1680 (error "The buffer is not saved"))
1682 (if (not (string-match "\\`'.*'\\'" buffername)) ; Add quotes
1683 (setq buffername (concat "'" buffername "'")))
1684 (while (string-match "%m" compile-string)
1685 (setq strbeg (substring compile-string 0 (match-beginning 0)))
1686 (setq strend (substring compile-string (match-end 0)))
1687 (setq compile-string (concat strbeg module-file strend)))
1688 ;; FIXME: The code below will %-expand any %[fbl] that appears in
1689 ;; module-file.
1690 (while (string-match "%f" compile-string)
1691 (setq strbeg (substring compile-string 0 (match-beginning 0)))
1692 (setq strend (substring compile-string (match-end 0)))
1693 (setq compile-string (concat strbeg file-name strend)))
1694 (while (string-match "%b" compile-string)
1695 (setq strbeg (substring compile-string 0 (match-beginning 0)))
1696 (setq strend (substring compile-string (match-end 0)))
1697 (setq compile-string (concat strbeg buffername strend)))
1698 (while (string-match "%l" compile-string)
1699 (setq strbeg (substring compile-string 0 (match-beginning 0)))
1700 (setq strend (substring compile-string (match-end 0)))
1701 (setq compile-string (concat strbeg (format "%d" lineoffset) strend)))
1702 (concat compile-string "\n")))
1704 ;; The rest of this page is experimental code!
1706 ;; Global variables for process filter function
1707 (defvar prolog-process-flag nil
1708 "Non-nil means that a prolog task (i.e. a consultation or compilation job)
1709 is running.")
1710 (defvar prolog-consult-compile-output ""
1711 "Hold the unprocessed output from the current prolog task.")
1712 (defvar prolog-consult-compile-first-line 1
1713 "The number of the first line of the file to consult/compile.
1714 Used for temporary files.")
1715 (defvar prolog-consult-compile-file nil
1716 "The file to compile/consult (can be a temporary file).")
1717 (defvar prolog-consult-compile-real-file nil
1718 "The file name of the buffer to compile/consult.")
1720 (defvar compilation-parse-errors-function)
1722 (defun prolog-consult-compile (compilep file &optional first-line)
1723 "Consult/compile FILE.
1724 If COMPILEP is non-nil, perform compilation, otherwise perform CONSULTING.
1725 COMMAND is a string described by the variables `prolog-consult-string'
1726 and `prolog-compile-string'.
1727 Optional argument FIRST-LINE is the number of the first line in the compiled
1728 region.
1730 This function must be called from the source code buffer."
1731 (if prolog-process-flag
1732 (error "Another Prolog task is running."))
1733 (prolog-ensure-process t)
1734 (let* ((buffer (get-buffer-create prolog-compilation-buffer))
1735 (real-file buffer-file-name)
1736 (command-string (prolog-build-prolog-command compilep file
1737 real-file first-line))
1738 (process (get-process "prolog")))
1739 (with-current-buffer buffer
1740 (delete-region (point-min) (point-max))
1741 ;; FIXME: Wasn't this supposed to use prolog-inferior-mode?
1742 (compilation-mode)
1743 ;; FIXME: This doesn't seem to cooperate well with new(ish) compile.el.
1744 ;; Setting up font-locking for this buffer
1745 (set (make-local-variable 'font-lock-defaults)
1746 '(prolog-font-lock-keywords nil nil ((?_ . "w"))))
1747 (if (eq prolog-system 'sicstus)
1748 ;; FIXME: This looks really problematic: not only is this using
1749 ;; the old compilation-parse-errors-function, but
1750 ;; prolog-parse-sicstus-compilation-errors only accepts one argument
1751 ;; whereas compile.el calls it with 2 (and did so at least since
1752 ;; Emacs-20).
1753 (set (make-local-variable 'compilation-parse-errors-function)
1754 'prolog-parse-sicstus-compilation-errors))
1755 (setq buffer-read-only nil)
1756 (insert command-string "\n"))
1757 (display-buffer buffer)
1758 (setq prolog-process-flag t
1759 prolog-consult-compile-output ""
1760 prolog-consult-compile-first-line (if first-line (1- first-line) 0)
1761 prolog-consult-compile-file file
1762 prolog-consult-compile-real-file (if (string=
1763 file buffer-file-name)
1765 real-file))
1766 (with-current-buffer buffer
1767 (goto-char (point-max))
1768 (add-function :override (process-filter process)
1769 #'prolog-consult-compile-filter)
1770 (process-send-string "prolog" command-string)
1771 ;; (prolog-build-prolog-command compilep file real-file first-line))
1772 (while (and prolog-process-flag
1773 (accept-process-output process 10)) ; 10 secs is ok?
1774 (sit-for 0.1)
1775 (unless (get-process "prolog")
1776 (setq prolog-process-flag nil)))
1777 (insert (if compilep
1778 "\nCompilation finished.\n"
1779 "\nConsulted.\n"))
1780 (remove-function (process-filter process)
1781 #'prolog-consult-compile-filter))))
1783 (defvar compilation-error-list)
1785 (defun prolog-parse-sicstus-compilation-errors (limit)
1786 "Parse the prolog compilation buffer for errors.
1787 Argument LIMIT is a buffer position limiting searching.
1788 For use with the `compilation-parse-errors-function' variable."
1789 (setq compilation-error-list nil)
1790 (message "Parsing SICStus error messages...")
1791 (let (filepath dir file errorline)
1792 (while
1793 (re-search-backward
1794 "{\\([a-zA-Z ]* ERROR\\|Warning\\):.* in line[s ]*\\([0-9]+\\)"
1795 limit t)
1796 (setq errorline (string-to-number (match-string 2)))
1797 (save-excursion
1798 (re-search-backward
1799 "{\\(consulting\\|compiling\\|processing\\) \\(.*\\)\\.\\.\\.}"
1800 limit t)
1801 (setq filepath (match-string 2)))
1803 ;; ###### Does this work with SICStus under Windows
1804 ;; (i.e. backslashes and stuff?)
1805 (if (string-match "\\(.*/\\)\\([^/]*\\)$" filepath)
1806 (progn
1807 (setq dir (match-string 1 filepath))
1808 (setq file (match-string 2 filepath))))
1810 (setq compilation-error-list
1811 (cons
1812 (cons (save-excursion
1813 (beginning-of-line)
1814 (point-marker))
1815 (list (list file dir) errorline))
1816 compilation-error-list)
1820 (defun prolog-consult-compile-filter (process output)
1821 "Filter function for Prolog compilation PROCESS.
1822 Argument OUTPUT is a name of the output file."
1823 ;;(message "start")
1824 (setq prolog-consult-compile-output
1825 (concat prolog-consult-compile-output output))
1826 ;;(message "pccf1: %s" prolog-consult-compile-output)
1827 ;; Iterate through the lines of prolog-consult-compile-output
1828 (let (outputtype)
1829 (while (and prolog-process-flag
1831 ;; Trace question
1832 (progn
1833 (setq outputtype 'trace)
1834 (and (eq prolog-system 'sicstus)
1835 (string-match
1836 "^[ \t]*[0-9]+[ \t]*[0-9]+[ \t]*Call:.*? "
1837 prolog-consult-compile-output)))
1839 ;; Match anything
1840 (progn
1841 (setq outputtype 'normal)
1842 (string-match "^.*\n" prolog-consult-compile-output))
1844 ;;(message "outputtype: %s" outputtype)
1846 (setq output (match-string 0 prolog-consult-compile-output))
1847 ;; remove the text in output from prolog-consult-compile-output
1848 (setq prolog-consult-compile-output
1849 (substring prolog-consult-compile-output (length output)))
1850 ;;(message "pccf2: %s" prolog-consult-compile-output)
1852 ;; If temporary files were used, then we change the error
1853 ;; messages to point to the original source file.
1854 ;; FIXME: Use compilation-fake-loc instead.
1855 (cond
1857 ;; If the prolog process was in trace mode then it requires
1858 ;; user input
1859 ((and (eq prolog-system 'sicstus)
1860 (eq outputtype 'trace))
1861 (let ((input (concat (read-string output) "\n")))
1862 (process-send-string process input)
1863 (setq output (concat output input))))
1865 ((eq prolog-system 'sicstus)
1866 (if (and prolog-consult-compile-real-file
1867 (string-match
1868 "\\({.*:.* in line[s ]*\\)\\([0-9]+\\)-\\([0-9]+\\)" output))
1869 (setq output (replace-match
1870 ;; Adds a {processing ...} line so that
1871 ;; `prolog-parse-sicstus-compilation-errors'
1872 ;; finds the real file instead of the temporary one.
1873 ;; Also fixes the line numbers.
1874 (format "Added by Emacs: {processing %s...}\n%s%d-%d"
1875 prolog-consult-compile-real-file
1876 (match-string 1 output)
1877 (+ prolog-consult-compile-first-line
1878 (string-to-number
1879 (match-string 2 output)))
1880 (+ prolog-consult-compile-first-line
1881 (string-to-number
1882 (match-string 3 output))))
1883 t t output)))
1886 ((eq prolog-system 'swi)
1887 (if (and prolog-consult-compile-real-file
1888 (string-match (format
1889 "%s\\([ \t]*:[ \t]*\\)\\([0-9]+\\)"
1890 prolog-consult-compile-file)
1891 output))
1892 (setq output (replace-match
1893 ;; Real filename + text + fixed linenum
1894 (format "%s%s%d"
1895 prolog-consult-compile-real-file
1896 (match-string 1 output)
1897 (+ prolog-consult-compile-first-line
1898 (string-to-number
1899 (match-string 2 output))))
1900 t t output)))
1903 (t ())
1905 ;; Write the output in the *prolog-compilation* buffer
1906 (insert output)))
1908 ;; If the prompt is visible, then the task is finished
1909 (if (string-match (prolog-prompt-regexp) prolog-consult-compile-output)
1910 (setq prolog-process-flag nil)))
1912 (defun prolog-consult-compile-file (compilep)
1913 "Consult/compile file of current buffer.
1914 If COMPILEP is non-nil, compile, otherwise consult."
1915 (let ((file buffer-file-name))
1916 (if file
1917 (progn
1918 (save-some-buffers)
1919 (prolog-consult-compile compilep file))
1920 (prolog-consult-compile-region compilep (point-min) (point-max)))))
1922 (defun prolog-consult-compile-buffer (compilep)
1923 "Consult/compile current buffer.
1924 If COMPILEP is non-nil, compile, otherwise consult."
1925 (prolog-consult-compile-region compilep (point-min) (point-max)))
1927 (defun prolog-consult-compile-region (compilep beg end)
1928 "Consult/compile region between BEG and END.
1929 If COMPILEP is non-nil, compile, otherwise consult."
1930 ;(let ((file prolog-temp-filename)
1931 (let ((file (prolog-bsts (prolog-temporary-file)))
1932 (lines (count-lines 1 beg)))
1933 (write-region beg end file nil 'no-message)
1934 (write-region "\n" nil file t 'no-message)
1935 (prolog-consult-compile compilep file
1936 (if (bolp) (1+ lines) lines))
1937 (delete-file file)))
1939 (defun prolog-consult-compile-predicate (compilep)
1940 "Consult/compile the predicate around current point.
1941 If COMPILEP is non-nil, compile, otherwise consult."
1942 (prolog-consult-compile-region
1943 compilep (prolog-pred-start) (prolog-pred-end)))
1946 ;;-------------------------------------------------------------------
1947 ;; Font-lock stuff
1948 ;;-------------------------------------------------------------------
1950 ;; Auxiliary functions
1952 (defun prolog-font-lock-object-matcher (bound)
1953 "Find SICStus objects method name for font lock.
1954 Argument BOUND is a buffer position limiting searching."
1955 (let (point
1956 (case-fold-search nil))
1957 (while (and (not point)
1958 (re-search-forward "\\(::[ \t\n]*{\\|&\\)[ \t]*"
1959 bound t))
1960 (while (or (re-search-forward "\\=\n[ \t]*" bound t)
1961 (re-search-forward "\\=%.*" bound t)
1962 (and (re-search-forward "\\=/\\*" bound t)
1963 (re-search-forward "\\*/[ \t]*" bound t))))
1964 (setq point (re-search-forward
1965 (format "\\=\\(%s\\)" prolog-atom-regexp)
1966 bound t)))
1967 point))
1969 (defsubst prolog-face-name-p (facename)
1970 ;; Return t if FACENAME is the name of a face. This method is
1971 ;; necessary since facep in XEmacs only returns t for the actual
1972 ;; face objects (while it's only their names that are used just
1973 ;; about anywhere else) without providing a predicate that tests
1974 ;; face names. This function (including the above commentary) is
1975 ;; borrowed from cc-mode.
1976 (memq facename (face-list)))
1978 ;; Set everything up
1979 (defun prolog-font-lock-keywords ()
1980 "Set up font lock keywords for the current Prolog system."
1981 ;(when window-system
1982 (require 'font-lock)
1984 ;; Define Prolog faces
1985 (defface prolog-redo-face
1986 '((((class grayscale)) (:italic t))
1987 (((class color)) (:foreground "darkorchid"))
1988 (t (:italic t)))
1989 "Prolog mode face for highlighting redo trace lines."
1990 :group 'prolog-faces)
1991 (defface prolog-exit-face
1992 '((((class grayscale)) (:underline t))
1993 (((class color) (background dark)) (:foreground "green"))
1994 (((class color) (background light)) (:foreground "ForestGreen"))
1995 (t (:underline t)))
1996 "Prolog mode face for highlighting exit trace lines."
1997 :group 'prolog-faces)
1998 (defface prolog-exception-face
1999 '((((class grayscale)) (:bold t :italic t :underline t))
2000 (((class color)) (:bold t :foreground "black" :background "Khaki"))
2001 (t (:bold t :italic t :underline t)))
2002 "Prolog mode face for highlighting exception trace lines."
2003 :group 'prolog-faces)
2004 (defface prolog-warning-face
2005 '((((class grayscale)) (:underline t))
2006 (((class color) (background dark)) (:foreground "blue"))
2007 (((class color) (background light)) (:foreground "MidnightBlue"))
2008 (t (:underline t)))
2009 "Face name to use for compiler warnings."
2010 :group 'prolog-faces)
2011 (defface prolog-builtin-face
2012 '((((class color) (background light)) (:foreground "Purple"))
2013 (((class color) (background dark)) (:foreground "Cyan"))
2014 (((class grayscale) (background light))
2015 :foreground "LightGray" :bold t)
2016 (((class grayscale) (background dark)) (:foreground "DimGray" :bold t))
2017 (t (:bold t)))
2018 "Face name to use for compiler warnings."
2019 :group 'prolog-faces)
2020 (defvar prolog-warning-face
2021 (if (prolog-face-name-p 'font-lock-warning-face)
2022 'font-lock-warning-face
2023 'prolog-warning-face)
2024 "Face name to use for built in predicates.")
2025 (defvar prolog-builtin-face
2026 (if (prolog-face-name-p 'font-lock-builtin-face)
2027 'font-lock-builtin-face
2028 'prolog-builtin-face)
2029 "Face name to use for built in predicates.")
2030 (defvar prolog-redo-face 'prolog-redo-face
2031 "Face name to use for redo trace lines.")
2032 (defvar prolog-exit-face 'prolog-exit-face
2033 "Face name to use for exit trace lines.")
2034 (defvar prolog-exception-face 'prolog-exception-face
2035 "Face name to use for exception trace lines.")
2037 ;; Font Lock Patterns
2038 (let (
2039 ;; "Native" Prolog patterns
2040 (head-predicates
2041 (list (format "^\\(%s\\)\\((\\|[ \t]*:-\\)" prolog-atom-regexp)
2042 1 font-lock-function-name-face))
2043 ;(list (format "^%s" prolog-atom-regexp)
2044 ; 0 font-lock-function-name-face))
2045 (head-predicates-1
2046 (list (format "\\.[ \t]*\\(%s\\)" prolog-atom-regexp)
2047 1 font-lock-function-name-face) )
2048 (variables
2049 '("\\<\\([_A-Z][a-zA-Z0-9_]*\\)"
2050 1 font-lock-variable-name-face))
2051 (important-elements
2052 (list (if (eq prolog-system 'mercury)
2053 "[][}{;|]\\|\\\\[+=]\\|<?=>?"
2054 "[][}{!;|]\\|\\*->")
2055 0 'font-lock-keyword-face))
2056 (important-elements-1
2057 '("[^-*]\\(->\\)" 1 font-lock-keyword-face))
2058 (predspecs ; module:predicate/cardinality
2059 (list (format "\\<\\(%s:\\|\\)%s/[0-9]+"
2060 prolog-atom-regexp prolog-atom-regexp)
2061 0 font-lock-function-name-face 'prepend))
2062 (keywords ; directives (queries)
2063 (list
2064 (if (eq prolog-system 'mercury)
2065 (concat
2066 "\\<\\("
2067 (regexp-opt prolog-keywords-i)
2068 "\\|"
2069 (regexp-opt
2070 prolog-determinism-specificators-i)
2071 "\\)\\>")
2072 (concat
2073 "^[?:]- *\\("
2074 (regexp-opt prolog-keywords-i)
2075 "\\)\\>"))
2076 1 prolog-builtin-face))
2077 ;; SICStus specific patterns
2078 (sicstus-object-methods
2079 (if (eq prolog-system 'sicstus)
2080 '(prolog-font-lock-object-matcher
2081 1 font-lock-function-name-face)))
2082 ;; Mercury specific patterns
2083 (types
2084 (if (eq prolog-system 'mercury)
2085 (list
2086 (regexp-opt prolog-types-i 'words)
2087 0 'font-lock-type-face)))
2088 (modes
2089 (if (eq prolog-system 'mercury)
2090 (list
2091 (regexp-opt prolog-mode-specificators-i 'words)
2092 0 'font-lock-constant-face)))
2093 (directives
2094 (if (eq prolog-system 'mercury)
2095 (list
2096 (regexp-opt prolog-directives-i 'words)
2097 0 'prolog-warning-face)))
2098 ;; Inferior mode specific patterns
2099 (prompt
2100 ;; FIXME: Should be handled by comint already.
2101 (list (prolog-prompt-regexp) 0 'font-lock-keyword-face))
2102 (trace-exit
2103 ;; FIXME: Add to compilation-error-regexp-alist instead.
2104 (cond
2105 ((eq prolog-system 'sicstus)
2106 '("[ \t]*[0-9]+[ \t]+[0-9]+[ \t]*\\(Exit\\):"
2107 1 prolog-exit-face))
2108 ((eq prolog-system 'swi)
2109 '("[ \t]*\\(Exit\\):[ \t]*([ \t0-9]*)" 1 prolog-exit-face))
2110 (t nil)))
2111 (trace-fail
2112 ;; FIXME: Add to compilation-error-regexp-alist instead.
2113 (cond
2114 ((eq prolog-system 'sicstus)
2115 '("[ \t]*[0-9]+[ \t]+[0-9]+[ \t]*\\(Fail\\):"
2116 1 prolog-warning-face))
2117 ((eq prolog-system 'swi)
2118 '("[ \t]*\\(Fail\\):[ \t]*([ \t0-9]*)" 1 prolog-warning-face))
2119 (t nil)))
2120 (trace-redo
2121 ;; FIXME: Add to compilation-error-regexp-alist instead.
2122 (cond
2123 ((eq prolog-system 'sicstus)
2124 '("[ \t]*[0-9]+[ \t]+[0-9]+[ \t]*\\(Redo\\):"
2125 1 prolog-redo-face))
2126 ((eq prolog-system 'swi)
2127 '("[ \t]*\\(Redo\\):[ \t]*([ \t0-9]*)" 1 prolog-redo-face))
2128 (t nil)))
2129 (trace-call
2130 ;; FIXME: Add to compilation-error-regexp-alist instead.
2131 (cond
2132 ((eq prolog-system 'sicstus)
2133 '("[ \t]*[0-9]+[ \t]+[0-9]+[ \t]*\\(Call\\):"
2134 1 font-lock-function-name-face))
2135 ((eq prolog-system 'swi)
2136 '("[ \t]*\\(Call\\):[ \t]*([ \t0-9]*)"
2137 1 font-lock-function-name-face))
2138 (t nil)))
2139 (trace-exception
2140 ;; FIXME: Add to compilation-error-regexp-alist instead.
2141 (cond
2142 ((eq prolog-system 'sicstus)
2143 '("[ \t]*[0-9]+[ \t]+[0-9]+[ \t]*\\(Exception\\):"
2144 1 prolog-exception-face))
2145 ((eq prolog-system 'swi)
2146 '("[ \t]*\\(Exception\\):[ \t]*([ \t0-9]*)"
2147 1 prolog-exception-face))
2148 (t nil)))
2149 (error-message-identifier
2150 ;; FIXME: Add to compilation-error-regexp-alist instead.
2151 (cond
2152 ((eq prolog-system 'sicstus)
2153 '("{\\([A-Z]* ?ERROR:\\)" 1 prolog-exception-face prepend))
2154 ((eq prolog-system 'swi)
2155 '("^[[]\\(WARNING:\\)" 1 prolog-builtin-face prepend))
2156 (t nil)))
2157 (error-whole-messages
2158 ;; FIXME: Add to compilation-error-regexp-alist instead.
2159 (cond
2160 ((eq prolog-system 'sicstus)
2161 '("{\\([A-Z]* ?ERROR:.*\\)}[ \t]*$"
2162 1 font-lock-comment-face append))
2163 ((eq prolog-system 'swi)
2164 '("^[[]WARNING:[^]]*[]]$" 0 font-lock-comment-face append))
2165 (t nil)))
2166 (error-warning-messages
2167 ;; FIXME: Add to compilation-error-regexp-alist instead.
2168 ;; Mostly errors that SICStus asks the user about how to solve,
2169 ;; such as "NAME CLASH:" for example.
2170 (cond
2171 ((eq prolog-system 'sicstus)
2172 '("^[A-Z ]*[A-Z]+:" 0 prolog-warning-face))
2173 (t nil)))
2174 (warning-messages
2175 ;; FIXME: Add to compilation-error-regexp-alist instead.
2176 (cond
2177 ((eq prolog-system 'sicstus)
2178 '("\\({ ?\\(Warning\\|WARNING\\) ?:.*}\\)[ \t]*$"
2179 2 prolog-warning-face prepend))
2180 (t nil))))
2182 ;; Make font lock list
2183 (delq
2185 (cond
2186 ((eq major-mode 'prolog-mode)
2187 (list
2188 head-predicates
2189 head-predicates-1
2190 variables
2191 important-elements
2192 important-elements-1
2193 predspecs
2194 keywords
2195 sicstus-object-methods
2196 types
2197 modes
2198 directives))
2199 ((eq major-mode 'prolog-inferior-mode)
2200 (list
2201 prompt
2202 error-message-identifier
2203 error-whole-messages
2204 error-warning-messages
2205 warning-messages
2206 predspecs
2207 trace-exit
2208 trace-fail
2209 trace-redo
2210 trace-call
2211 trace-exception))
2212 ((eq major-mode 'compilation-mode)
2213 (list
2214 error-message-identifier
2215 error-whole-messages
2216 error-warning-messages
2217 warning-messages
2218 predspecs))))
2222 ;;-------------------------------------------------------------------
2223 ;; Indentation stuff
2224 ;;-------------------------------------------------------------------
2226 ;; NB: This function *MUST* have this optional argument since XEmacs
2227 ;; assumes it. This does not mean we have to use it...
2228 (defun prolog-indent-line (&optional _whole-exp)
2229 "Indent current line as Prolog code.
2230 With argument, indent any additional lines of the same clause
2231 rigidly along with this one (not yet)."
2232 (interactive "p")
2233 (let ((indent (prolog-indent-level))
2234 (pos (- (point-max) (point))))
2235 (beginning-of-line)
2236 (skip-chars-forward " \t")
2237 (indent-line-to indent)
2238 (if (> (- (point-max) pos) (point))
2239 (goto-char (- (point-max) pos)))
2241 ;; Align comments
2242 (if (and prolog-align-comments-flag
2243 (save-excursion
2244 (line-beginning-position)
2245 ;; (let ((start (comment-search-forward (line-end-position) t)))
2246 ;; (and start ;There's a comment to indent.
2247 ;; ;; If it's first on the line, we've indented it already
2248 ;; ;; and prolog-goto-comment-column would inf-loop.
2249 ;; (progn (goto-char start) (skip-chars-backward " \t")
2250 ;; (not (bolp)))))))
2251 (and (looking-at comment-start-skip)
2252 ;; The definition of comment-start-skip used in this
2253 ;; mode is unusual in that it only matches at BOL.
2254 (progn (skip-chars-forward " \t")
2255 (not (eq (point) (match-end 1)))))))
2256 (save-excursion
2257 (prolog-goto-comment-column t)))
2259 ;; Insert spaces if needed
2260 (if (or prolog-electric-tab-flag prolog-electric-if-then-else-flag)
2261 (prolog-insert-spaces-after-paren))
2264 (defun prolog-indent-level ()
2265 "Compute prolog indentation level."
2266 (save-excursion
2267 (beginning-of-line)
2268 (let ((totbal (prolog-region-paren-balance
2269 (prolog-clause-start t) (point)))
2270 (oldpoint (point)))
2271 (skip-chars-forward " \t")
2272 (cond
2273 ((looking-at "%%%") (prolog-indentation-level-of-line))
2274 ;Large comment starts
2275 ((looking-at "%[^%]") comment-column) ;Small comment starts
2276 ((bobp) 0) ;Beginning of buffer
2278 ;; If we found '}' then we must check if it's the
2279 ;; end of an object declaration or something else.
2280 ((and (looking-at "}")
2281 (save-excursion
2282 (forward-char 1)
2283 ;; Goto to matching {
2284 (if prolog-use-prolog-tokenizer-flag
2285 (prolog-backward-list)
2286 (backward-list))
2287 (skip-chars-backward " \t")
2288 (backward-char 2)
2289 (looking-at "::")))
2290 ;; It was an object
2291 (if prolog-object-end-to-0-flag
2293 prolog-indent-width))
2295 ;;End of /* */ comment
2296 ((looking-at "\\*/")
2297 (save-excursion
2298 (prolog-find-start-of-mline-comment)
2299 (skip-chars-backward " \t")
2300 (- (current-column) 2)))
2302 ;; Here we check if the current line is within a /* */ pair
2303 ((and (looking-at "[^%/]")
2304 (eq (prolog-in-string-or-comment) 'cmt))
2305 (if prolog-indent-mline-comments-flag
2306 (prolog-find-start-of-mline-comment)
2307 ;; Same as before
2308 (prolog-indentation-level-of-line)))
2311 (let ((empty t) ind linebal)
2312 ;; See previous indentation
2313 (while empty
2314 (forward-line -1)
2315 (beginning-of-line)
2316 (if (bobp)
2317 (setq empty nil)
2318 (skip-chars-forward " \t")
2319 (if (not (or (not (member (prolog-in-string-or-comment)
2320 '(nil txt)))
2321 (looking-at "%")
2322 (looking-at "\n")))
2323 (setq empty nil))))
2325 ;; Store this line's indentation
2326 (setq ind (if (bobp)
2327 0 ;Beginning of buffer.
2328 (current-column))) ;Beginning of clause.
2330 ;; Compute the balance of the line
2331 (setq linebal (prolog-paren-balance))
2332 ;;(message "bal of previous line %d totbal %d" linebal totbal)
2333 (if (< linebal 0)
2334 (progn
2335 ;; Add 'indent-level' mode to find-unmatched-paren instead?
2336 (end-of-line)
2337 (setq ind (prolog-find-indent-of-matching-paren))))
2339 ;;(message "ind %d" ind)
2340 (beginning-of-line)
2342 ;; Check if the line ends with ":-", ".", ":: {", "}" (might be
2343 ;; unnecessary), "&" or ")" (The last four concerns SICStus objects)
2344 (cond
2345 ;; If the last char of the line is a '&' then set the indent level
2346 ;; to prolog-indent-width (used in SICStus objects)
2347 ((and (eq prolog-system 'sicstus)
2348 (looking-at ".+&[ \t]*\\(%.*\\|\\)$"))
2349 (setq ind prolog-indent-width))
2351 ;; Increase indentation if the previous line was the head of a rule
2352 ;; and does not contain a '.'
2353 ((and (looking-at (format ".*%s[^\\.]*[ \t]*\\(%%.*\\|\\)$"
2354 prolog-head-delimiter))
2355 ;; We must check that the match is at a paren balance of 0.
2356 (save-excursion
2357 (let ((p (point)))
2358 (re-search-forward prolog-head-delimiter)
2359 (>= 0 (prolog-region-paren-balance p (point))))))
2360 (let ((headindent
2361 (if (< (prolog-paren-balance) 0)
2362 (save-excursion
2363 (end-of-line)
2364 (prolog-find-indent-of-matching-paren))
2365 (prolog-indentation-level-of-line))))
2366 (setq ind (+ headindent prolog-indent-width))))
2368 ;; The previous line was the head of an object
2369 ((looking-at ".+ *::.*{[ \t]*$")
2370 (setq ind prolog-indent-width))
2372 ;; If a '.' is found at the end of the previous line, then
2373 ;; decrease the indentation. (The \\(%.*\\|\\) part of the
2374 ;; regexp is for comments at the end of the line)
2375 ((and (looking-at "^.+\\.[ \t]*\\(%.*\\|\\)$")
2376 ;; Make sure that the '.' found is not in a comment or string
2377 (save-excursion
2378 (end-of-line)
2379 (re-search-backward "\\.[ \t]*\\(%.*\\|\\)$" (point-min))
2380 ;; Guard against the real '.' being followed by a
2381 ;; commented '.'.
2382 (if (eq (prolog-in-string-or-comment) 'cmt)
2383 ;; commented out '.'
2384 (let ((here (line-beginning-position)))
2385 (end-of-line)
2386 (re-search-backward "\\.[ \t]*%.*$" here t))
2387 (not (prolog-in-string-or-comment))
2390 (setq ind 0))
2392 ;; If a '.' is found at the end of the previous line, then
2393 ;; decrease the indentation. (The /\\*.*\\*/ part of the
2394 ;; regexp is for C-like comments at the end of the
2395 ;; line--can we merge with the case above?).
2396 ((and (looking-at "^.+\\.[ \t]*\\(/\\*.*\\|\\)$")
2397 ;; Make sure that the '.' found is not in a comment or string
2398 (save-excursion
2399 (end-of-line)
2400 (re-search-backward "\\.[ \t]*\\(/\\*.*\\|\\)$" (point-min))
2401 ;; Guard against the real '.' being followed by a
2402 ;; commented '.'.
2403 (if (eq (prolog-in-string-or-comment) 'cmt)
2404 ;; commented out '.'
2405 (let ((here (line-beginning-position)))
2406 (end-of-line)
2407 (re-search-backward "\\.[ \t]*/\\*.*$" here t))
2408 (not (prolog-in-string-or-comment))
2411 (setq ind 0))
2415 ;; If the last non comment char is a ',' or left paren or a left-
2416 ;; indent-regexp then indent to open parenthesis level
2417 (if (and
2418 (> totbal 0)
2419 ;; SICStus objects have special syntax rules if point is
2420 ;; not inside additional parens (objects are defined
2421 ;; within {...})
2422 (not (and (eq prolog-system 'sicstus)
2423 (= totbal 1)
2424 (prolog-in-object))))
2425 (if (looking-at
2426 (format "\\(%s\\|%s\\|0'.\\|[0-9]+'[0-9a-zA-Z]+\\|[^\n\'\"%%]\\)*\\(,\\|%s\\|%s\\)\[ \t]*\\(%%.*\\|\\)$"
2427 prolog-quoted-atom-regexp prolog-string-regexp
2428 prolog-left-paren prolog-left-indent-regexp))
2429 (progn
2430 (goto-char oldpoint)
2431 (setq ind (prolog-find-unmatched-paren
2432 (if prolog-paren-indent-p
2433 'termdependent
2434 'skipwhite)))
2435 ;;(setq ind (prolog-find-unmatched-paren 'termdependent))
2437 (goto-char oldpoint)
2438 (setq ind (prolog-find-unmatched-paren nil))
2442 ;; Return the indentation level
2444 ))))))
2446 (defun prolog-find-indent-of-matching-paren ()
2447 "Find the indentation level based on the matching parenthesis.
2448 Indentation level is set to the one the point is after when the function is
2449 called."
2450 (save-excursion
2451 ;; Go to the matching paren
2452 (if prolog-use-prolog-tokenizer-flag
2453 (prolog-backward-list)
2454 (backward-list))
2456 ;; If this was the first paren on the line then return this line's
2457 ;; indentation level
2458 (if (prolog-paren-is-the-first-on-line-p)
2459 (prolog-indentation-level-of-line)
2460 ;; It was not the first one
2461 (progn
2462 ;; Find the next paren
2463 (prolog-goto-next-paren 0)
2465 ;; If this paren is a left one then use its column as indent level,
2466 ;; if not then recurse this function
2467 (if (looking-at prolog-left-paren)
2468 (+ (current-column) 1)
2469 (progn
2470 (forward-char 1)
2471 (prolog-find-indent-of-matching-paren)))
2475 (defun prolog-indentation-level-of-line ()
2476 "Return the indentation level of the current line."
2477 (save-excursion
2478 (beginning-of-line)
2479 (skip-chars-forward " \t")
2480 (current-column)))
2482 (defun prolog-paren-is-the-first-on-line-p ()
2483 "Return t if the parenthesis under the point is the first one on the line.
2484 Return nil otherwise.
2485 Note: does not check if the point is actually at a parenthesis!"
2486 (save-excursion
2487 (let ((begofline (line-beginning-position)))
2488 (if (= begofline (point))
2490 (if (prolog-goto-next-paren begofline)
2492 t)))))
2494 (defun prolog-find-unmatched-paren (&optional mode)
2495 "Return the column of the last unmatched left parenthesis.
2496 If MODE is `skipwhite' then any white space after the parenthesis is added to
2497 the answer.
2498 If MODE is `plusone' then the parenthesis' column +1 is returned.
2499 If MODE is `termdependent' then if the unmatched parenthesis is part of
2500 a compound term the function will work as `skipwhite', otherwise
2501 it will return the column paren plus the value of `prolog-paren-indent'.
2502 If MODE is nil or not set then the parenthesis' exact column is returned."
2503 (save-excursion
2504 ;; If the next paren we find is a left one we're finished, if it's
2505 ;; a right one then we go back one step and recurse
2506 (prolog-goto-next-paren 0)
2508 (let ((roundparen (looking-at "(")))
2509 (if (looking-at prolog-left-paren)
2510 (let ((not-part-of-term
2511 (save-excursion
2512 (backward-char 1)
2513 (looking-at "[ \t]"))))
2514 (if (eq mode nil)
2515 (current-column)
2516 (if (and roundparen
2517 (eq mode 'termdependent)
2518 not-part-of-term)
2519 (+ (current-column)
2520 (if prolog-electric-tab-flag
2521 ;; Electric TAB
2522 prolog-paren-indent
2523 ;; Not electric TAB
2524 (if (looking-at ".[ \t]*$")
2526 prolog-paren-indent))
2529 (forward-char 1)
2530 (if (or (eq mode 'skipwhite) (eq mode 'termdependent) )
2531 (skip-chars-forward " \t"))
2532 (current-column))))
2533 ;; Not looking at left paren
2534 (progn
2535 (forward-char 1)
2536 ;; Go to the matching paren. When we get there we have a total
2537 ;; balance of 0.
2538 (if prolog-use-prolog-tokenizer-flag
2539 (prolog-backward-list)
2540 (backward-list))
2541 (prolog-find-unmatched-paren mode)))
2545 (defun prolog-paren-balance ()
2546 "Return the parenthesis balance of the current line.
2547 A return value of n means n more left parentheses than right ones."
2548 (save-excursion
2549 (end-of-line)
2550 (prolog-region-paren-balance (line-beginning-position) (point))))
2552 (defun prolog-region-paren-balance (beg end)
2553 "Return the summed parenthesis balance in the region.
2554 The region is limited by BEG and END positions."
2555 (save-excursion
2556 (let ((state (if prolog-use-prolog-tokenizer-flag
2557 (prolog-tokenize beg end)
2558 (parse-partial-sexp beg end))))
2559 (nth 0 state))))
2561 (defun prolog-goto-next-paren (limit-pos)
2562 "Move the point to the next parenthesis earlier in the buffer.
2563 Return t if a match was found before LIMIT-POS. Return nil otherwise."
2564 (let ((retval (re-search-backward
2565 (concat prolog-left-paren "\\|" prolog-right-paren)
2566 limit-pos t)))
2568 ;; If a match was found but it was in a string or comment, then recurse
2569 (if (and retval (prolog-in-string-or-comment))
2570 (prolog-goto-next-paren limit-pos)
2571 retval)
2574 (defun prolog-in-string-or-comment ()
2575 "Check whether string, atom, or comment is under current point.
2576 Return:
2577 `txt' if the point is in a string, atom, or character code expression
2578 `cmt' if the point is in a comment
2579 nil otherwise."
2580 (save-excursion
2581 (let* ((start
2582 (if (eq prolog-parse-mode 'beg-of-line)
2583 ;; 'beg-of-line
2584 (save-excursion
2585 (let (safepoint)
2586 (beginning-of-line)
2587 (setq safepoint (point))
2588 (while (and (> (point) (point-min))
2589 (progn
2590 (forward-line -1)
2591 (end-of-line)
2592 (if (not (bobp))
2593 (backward-char 1))
2594 (looking-at "\\\\"))
2596 (beginning-of-line)
2597 (setq safepoint (point)))
2598 safepoint))
2599 ;; 'beg-of-clause
2600 (prolog-clause-start)))
2601 (end (point))
2602 (state (if prolog-use-prolog-tokenizer-flag
2603 (prolog-tokenize start end)
2604 (if (fboundp 'syntax-ppss)
2605 (syntax-ppss)
2606 (parse-partial-sexp start end)))))
2607 (cond
2608 ((nth 3 state) 'txt) ; String
2609 ((nth 4 state) 'cmt) ; Comment
2611 (cond
2612 ((looking-at "%") 'cmt) ; Start of a comment
2613 ((looking-at "/\\*") 'cmt) ; Start of a comment
2614 ((looking-at "\'") 'txt) ; Start of an atom
2615 ((looking-at "\"") 'txt) ; Start of a string
2616 (t nil)
2617 ))))
2620 (defun prolog-find-start-of-mline-comment ()
2621 "Return the start column of a /* */ comment.
2622 This assumes that the point is inside a comment."
2623 (re-search-backward "/\\*" (point-min) t)
2624 (forward-char 2)
2625 (skip-chars-forward " \t")
2626 (current-column))
2628 (defun prolog-insert-spaces-after-paren ()
2629 "Insert spaces after the opening parenthesis, \"then\" (->) and \"else\" (;) branches.
2630 Spaces are inserted if all preceding objects on the line are
2631 whitespace characters, parentheses, or then/else branches."
2632 (save-excursion
2633 (let ((regexp (concat "(\\|" prolog-left-indent-regexp))
2634 level)
2635 (beginning-of-line)
2636 (skip-chars-forward " \t")
2637 (when (looking-at regexp)
2638 ;; Treat "( If -> " lines specially.
2639 ;;(setq incr (if (looking-at "(.*->")
2640 ;; 2
2641 ;; prolog-paren-indent))
2643 ;; work on all subsequent "->", "(", ";"
2644 (while (looking-at regexp)
2645 (goto-char (match-end 0))
2646 (setq level (+ (prolog-find-unmatched-paren) prolog-paren-indent))
2648 ;; Remove old white space
2649 (let ((start (point)))
2650 (skip-chars-forward " \t")
2651 (delete-region start (point)))
2652 (indent-to level)
2653 (skip-chars-forward " \t"))
2655 (when (save-excursion
2656 (backward-char 2)
2657 (looking-at "\\s ;\\|\\s (\\|->")) ; (looking-at "\\s \\((\\|;\\)"))
2658 (skip-chars-forward " \t"))
2661 ;;;; Comment filling
2663 (defun prolog-comment-limits ()
2664 "Return the current comment limits plus the comment type (block or line).
2665 The comment limits are the range of a block comment or the range that
2666 contains all adjacent line comments (i.e. all comments that starts in
2667 the same column with no empty lines or non-whitespace characters
2668 between them)."
2669 (let ((here (point))
2670 lit-limits-b lit-limits-e lit-type beg end
2672 (save-restriction
2673 ;; Widen to catch comment limits correctly.
2674 (widen)
2675 (setq end (line-end-position)
2676 beg (line-beginning-position))
2677 (save-excursion
2678 (beginning-of-line)
2679 (setq lit-type (if (search-forward-regexp "%" end t) 'line 'block))
2680 ; (setq lit-type 'line)
2681 ;(if (search-forward-regexp "^[ \t]*%" end t)
2682 ; (setq lit-type 'line)
2683 ; (if (not (search-forward-regexp "%" end t))
2684 ; (setq lit-type 'block)
2685 ; (if (not (= (forward-line 1) 0))
2686 ; (setq lit-type 'block)
2687 ; (setq done t
2688 ; ret (prolog-comment-limits)))
2689 ; ))
2690 (if (eq lit-type 'block)
2691 (progn
2692 (goto-char here)
2693 (when (looking-at "/\\*") (forward-char 2))
2694 (when (and (looking-at "\\*") (> (point) (point-min))
2695 (forward-char -1) (looking-at "/"))
2696 (forward-char 1))
2697 (when (save-excursion (search-backward "/*" nil t))
2698 (list (save-excursion (search-backward "/*") (point))
2699 (or (search-forward "*/" nil t) (point-max)) lit-type)))
2700 ;; line comment
2701 (setq lit-limits-b (- (point) 1)
2702 lit-limits-e end)
2703 (condition-case nil
2704 (if (progn (goto-char lit-limits-b)
2705 (looking-at "%"))
2706 (let ((col (current-column)) done)
2707 (setq beg (point)
2708 end lit-limits-e)
2709 ;; Always at the beginning of the comment
2710 ;; Go backward now
2711 (beginning-of-line)
2712 (while (and (zerop (setq done (forward-line -1)))
2713 (search-forward-regexp "^[ \t]*%"
2714 (line-end-position) t)
2715 (= (+ 1 col) (current-column)))
2716 (setq beg (- (point) 1)))
2717 (when (= done 0)
2718 (forward-line 1))
2719 ;; We may have a line with code above...
2720 (when (and (zerop (setq done (forward-line -1)))
2721 (search-forward "%" (line-end-position) t)
2722 (= (+ 1 col) (current-column)))
2723 (setq beg (- (point) 1)))
2724 (when (= done 0)
2725 (forward-line 1))
2726 ;; Go forward
2727 (goto-char lit-limits-b)
2728 (beginning-of-line)
2729 (while (and (zerop (forward-line 1))
2730 (search-forward-regexp "^[ \t]*%"
2731 (line-end-position) t)
2732 (= (+ 1 col) (current-column)))
2733 (setq end (line-end-position)))
2734 (list beg end lit-type))
2735 (list lit-limits-b lit-limits-e lit-type)
2737 (error (list lit-limits-b lit-limits-e lit-type))))
2738 ))))
2740 (defun prolog-guess-fill-prefix ()
2741 ;; fill 'txt entities?
2742 (when (save-excursion
2743 (end-of-line)
2744 (equal (prolog-in-string-or-comment) 'cmt))
2745 (let* ((bounds (prolog-comment-limits))
2746 (cbeg (car bounds))
2747 (type (nth 2 bounds))
2748 beg end)
2749 (save-excursion
2750 (end-of-line)
2751 (setq end (point))
2752 (beginning-of-line)
2753 (setq beg (point))
2754 (if (and (eq type 'line)
2755 (> cbeg beg)
2756 (save-excursion (not (search-forward-regexp "^[ \t]*%"
2757 cbeg t))))
2758 (progn
2759 (goto-char cbeg)
2760 (search-forward-regexp "%+[ \t]*" end t)
2761 (prolog-replace-in-string (buffer-substring beg (point))
2762 "[^ \t%]" " "))
2763 ;(goto-char beg)
2764 (if (search-forward-regexp "^[ \t]*\\(%+\\|\\*+\\|/\\*+\\)[ \t]*"
2765 end t)
2766 (prolog-replace-in-string (buffer-substring beg (point)) "/" " ")
2767 (beginning-of-line)
2768 (when (search-forward-regexp "^[ \t]+" end t)
2769 (buffer-substring beg (point)))))))))
2771 (defun prolog-fill-paragraph ()
2772 "Fill paragraph comment at or after point."
2773 (interactive)
2774 (let* ((bounds (prolog-comment-limits))
2775 (type (nth 2 bounds)))
2776 (if (eq type 'line)
2777 (let ((fill-prefix (prolog-guess-fill-prefix)))
2778 (fill-paragraph nil))
2779 (save-excursion
2780 (save-restriction
2781 ;; exclude surrounding lines that delimit a multiline comment
2782 ;; and don't contain alphabetic characters, like "/*******",
2783 ;; "- - - */" etc.
2784 (save-excursion
2785 (backward-paragraph)
2786 (unless (bobp) (forward-line))
2787 (if (string-match "^/\\*[^a-zA-Z]*$" (thing-at-point 'line))
2788 (narrow-to-region (point-at-eol) (point-max))))
2789 (save-excursion
2790 (forward-paragraph)
2791 (forward-line -1)
2792 (if (string-match "^[^a-zA-Z]*\\*/$" (thing-at-point 'line))
2793 (narrow-to-region (point-min) (point-at-bol))))
2794 (let ((fill-prefix (prolog-guess-fill-prefix)))
2795 (fill-paragraph nil))))
2798 (defun prolog-do-auto-fill ()
2799 "Carry out Auto Fill for Prolog mode.
2800 In effect it sets the `fill-prefix' when inside comments and then calls
2801 `do-auto-fill'."
2802 (let ((fill-prefix (prolog-guess-fill-prefix)))
2803 (do-auto-fill)
2806 (defalias 'prolog-replace-in-string
2807 (if (fboundp 'replace-in-string)
2808 #'replace-in-string
2809 (lambda (str regexp newtext &optional literal)
2810 (replace-regexp-in-string regexp newtext str nil literal))))
2812 ;;-------------------------------------------------------------------
2813 ;; The tokenizer
2814 ;;-------------------------------------------------------------------
2816 (defconst prolog-tokenize-searchkey
2817 (concat "[0-9]+'"
2818 "\\|"
2819 "['\"]"
2820 "\\|"
2821 prolog-left-paren
2822 "\\|"
2823 prolog-right-paren
2824 "\\|"
2826 "\\|"
2827 "/\\*"
2830 (defun prolog-tokenize (beg end &optional stopcond)
2831 "Tokenize a region of prolog code between BEG and END.
2832 STOPCOND decides the stop condition of the parsing. Valid values
2833 are 'zerodepth which stops the parsing at the first right parenthesis
2834 where the parenthesis depth is zero, 'skipover which skips over
2835 the current entity (e.g. a list, a string, etc.) and nil.
2837 The function returns a list with the following information:
2838 0. parenthesis depth
2839 3. 'atm if END is inside an atom
2840 'str if END is inside a string
2841 'chr if END is in a character code expression (0'x)
2842 nil otherwise
2843 4. non-nil if END is inside a comment
2844 5. end position (always equal to END if STOPCOND is nil)
2845 The rest of the elements are undefined."
2846 (save-excursion
2847 (let* ((end2 (1+ end))
2848 oldp
2849 (depth 0)
2850 (quoted nil)
2851 inside_cmt
2852 (endpos end2)
2853 skiptype ; The type of entity we'll skip over
2855 (goto-char beg)
2857 (if (and (eq stopcond 'skipover)
2858 (looking-at "[^[({'\"]"))
2859 (setq endpos (point)) ; Stay where we are
2860 (while (and
2861 (re-search-forward prolog-tokenize-searchkey end2 t)
2862 (< (point) end2))
2863 (progn
2864 (setq oldp (point))
2865 (goto-char (match-beginning 0))
2866 (cond
2867 ;; Atoms and strings
2868 ((looking-at "'")
2869 ;; Find end of atom
2870 (if (re-search-forward "[^\\]'" end2 'limit)
2871 ;; Found end of atom
2872 (progn
2873 (setq oldp end2)
2874 (if (and (eq stopcond 'skipover)
2875 (not skiptype))
2876 (setq endpos (point))
2877 (setq oldp (point)))) ; Continue tokenizing
2878 (setq quoted 'atm)))
2880 ((looking-at "\"")
2881 ;; Find end of string
2882 (if (re-search-forward "[^\\]\"" end2 'limit)
2883 ;; Found end of string
2884 (progn
2885 (setq oldp end2)
2886 (if (and (eq stopcond 'skipover)
2887 (not skiptype))
2888 (setq endpos (point))
2889 (setq oldp (point)))) ; Continue tokenizing
2890 (setq quoted 'str)))
2892 ;; Paren stuff
2893 ((looking-at prolog-left-paren)
2894 (setq depth (1+ depth))
2895 (setq skiptype 'paren))
2897 ((looking-at prolog-right-paren)
2898 (setq depth (1- depth))
2899 (if (and
2900 (or (eq stopcond 'zerodepth)
2901 (and (eq stopcond 'skipover)
2902 (eq skiptype 'paren)))
2903 (= depth 0))
2904 (progn
2905 (setq endpos (1+ (point)))
2906 (setq oldp end2))))
2908 ;; Comment stuff
2909 ((looking-at comment-start)
2910 (end-of-line)
2911 ;; (if (>= (point) end2)
2912 (if (>= (point) end)
2913 (progn
2914 (setq inside_cmt t)
2915 (setq oldp end2))
2916 (setq oldp (point))))
2918 ((looking-at "/\\*")
2919 (if (re-search-forward "\\*/" end2 'limit)
2920 (setq oldp (point))
2921 (setq inside_cmt t)
2922 (setq oldp end2)))
2924 ;; 0'char
2925 ((looking-at "0'")
2926 (setq oldp (1+ (match-end 0)))
2927 (if (> oldp end)
2928 (setq quoted 'chr)))
2930 ;; base'number
2931 ((looking-at "[0-9]+'")
2932 (goto-char (match-end 0))
2933 (skip-chars-forward "0-9a-zA-Z")
2934 (setq oldp (point)))
2938 (goto-char oldp)
2939 )) ; End of while
2942 ;; Deal with multi-line comments
2943 (and (prolog-inside-mline-comment end)
2944 (setq inside_cmt t))
2946 ;; Create return list
2947 (list depth nil nil quoted inside_cmt endpos)
2950 (defun prolog-inside-mline-comment (here)
2951 (save-excursion
2952 (goto-char here)
2953 (let* ((next-close (save-excursion (search-forward "*/" nil t)))
2954 (next-open (save-excursion (search-forward "/*" nil t)))
2955 (prev-open (save-excursion (search-backward "/*" nil t)))
2956 (prev-close (save-excursion (search-backward "*/" nil t)))
2957 (unmatched-next-close (and next-close
2958 (or (not next-open)
2959 (> next-open next-close))))
2960 (unmatched-prev-open (and prev-open
2961 (or (not prev-close)
2962 (> prev-open prev-close))))
2964 (or unmatched-next-close unmatched-prev-open)
2968 ;;-------------------------------------------------------------------
2969 ;; Online help
2970 ;;-------------------------------------------------------------------
2972 (defvar prolog-help-function
2973 '((mercury nil)
2974 (eclipse prolog-help-online)
2975 ;; (sicstus prolog-help-info)
2976 (sicstus prolog-find-documentation)
2977 (swi prolog-help-online)
2978 (t prolog-help-online))
2979 "Alist for the name of the function for finding help on a predicate.")
2981 (defun prolog-help-on-predicate ()
2982 "Invoke online help on the atom under cursor."
2983 (interactive)
2985 (cond
2986 ;; Redirect help for SICStus to `prolog-find-documentation'.
2987 ((eq prolog-help-function-i 'prolog-find-documentation)
2988 (prolog-find-documentation))
2990 ;; Otherwise, ask for the predicate name and then call the function
2991 ;; in prolog-help-function-i
2993 (let* ((word (prolog-atom-under-point))
2994 (predicate (read-string
2995 (format "Help on predicate%s: "
2996 (if word
2997 (concat " (default " word ")")
2998 ""))
2999 nil nil word))
3000 ;;point
3002 (if prolog-help-function-i
3003 (funcall prolog-help-function-i predicate)
3004 (error "Sorry, no help method defined for this Prolog system."))))
3008 (autoload 'Info-goto-node "info" nil t)
3009 (declare-function Info-follow-nearest-node "info" (&optional FORK))
3011 (defun prolog-help-info (predicate)
3012 (let ((buffer (current-buffer))
3013 oldp
3014 (str (concat "^\\* " (regexp-quote predicate) " */")))
3015 (pop-to-buffer nil)
3016 (Info-goto-node prolog-info-predicate-index)
3017 (if (not (re-search-forward str nil t))
3018 (error (format "Help on predicate `%s' not found." predicate)))
3020 (setq oldp (point))
3021 (if (re-search-forward str nil t)
3022 ;; Multiple matches, ask user
3023 (let ((max 2)
3025 ;; Count matches
3026 (while (re-search-forward str nil t)
3027 (setq max (1+ max)))
3029 (goto-char oldp)
3030 (re-search-backward "[^ /]" nil t)
3031 (recenter 0)
3032 (setq n (read-string ;; was read-input, which is obsolete
3033 (format "Several matches, choose (1-%d): " max) "1"))
3034 (forward-line (- (string-to-number n) 1)))
3035 ;; Single match
3036 (re-search-backward "[^ /]" nil t))
3038 ;; (Info-follow-nearest-node (point))
3039 (prolog-Info-follow-nearest-node)
3040 (re-search-forward (concat "^`" (regexp-quote predicate)) nil t)
3041 (beginning-of-line)
3042 (recenter 0)
3043 (pop-to-buffer buffer)))
3045 (defun prolog-Info-follow-nearest-node ()
3046 (if (featurep 'xemacs)
3047 (Info-follow-nearest-node (point))
3048 (Info-follow-nearest-node)))
3050 (defun prolog-help-online (predicate)
3051 (prolog-ensure-process)
3052 (process-send-string "prolog" (concat "help(" predicate ").\n"))
3053 (display-buffer "*prolog*"))
3055 (defun prolog-help-apropos (string)
3056 "Find Prolog apropos on given STRING.
3057 This function is only available when `prolog-system' is set to `swi'."
3058 (interactive "sApropos: ")
3059 (cond
3060 ((eq prolog-system 'swi)
3061 (prolog-ensure-process)
3062 (process-send-string "prolog" (concat "apropos(" string ").\n"))
3063 (display-buffer "*prolog*"))
3065 (error "Sorry, no Prolog apropos available for this Prolog system."))))
3067 (defun prolog-atom-under-point ()
3068 "Return the atom under or left to the point."
3069 (save-excursion
3070 (let ((nonatom_chars "[](){},\. \t\n")
3071 start)
3072 (skip-chars-forward (concat "^" nonatom_chars))
3073 (skip-chars-backward nonatom_chars)
3074 (skip-chars-backward (concat "^" nonatom_chars))
3075 (setq start (point))
3076 (skip-chars-forward (concat "^" nonatom_chars))
3077 (buffer-substring-no-properties start (point))
3081 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3082 ;; Help function with completion
3083 ;; Stolen from Per Mildner's SICStus debugger mode and modified
3085 (defun prolog-find-documentation ()
3086 "Go to the Info node for a predicate in the SICStus Info manual."
3087 (interactive)
3088 (let ((pred (prolog-read-predicate)))
3089 (prolog-goto-predicate-info pred)))
3091 (defvar prolog-info-alist nil
3092 "Alist with all builtin predicates.
3093 Only for internal use by `prolog-find-documentation'")
3095 ;; Very similar to prolog-help-info except that that function cannot
3096 ;; cope with arity and that it asks the user if there are several
3097 ;; functors with different arity. This function also uses
3098 ;; prolog-info-alist for finding the info node, rather than parsing
3099 ;; the predicate index.
3100 (defun prolog-goto-predicate-info (predicate)
3101 "Go to the info page for PREDICATE, which is a PredSpec."
3102 (interactive)
3103 (string-match "\\(.*\\)/\\([0-9]+\\).*$" predicate)
3104 (let ((buffer (current-buffer))
3105 (name (match-string 1 predicate))
3106 (arity (string-to-number (match-string 2 predicate)))
3107 ;oldp
3108 ;(str (regexp-quote predicate))
3110 (pop-to-buffer nil)
3112 (Info-goto-node
3113 prolog-info-predicate-index) ;; We must be in the SICStus pages
3114 (Info-goto-node (car (cdr (assoc predicate prolog-info-alist))))
3116 (prolog-find-term (regexp-quote name) arity "^`")
3118 (recenter 0)
3119 (pop-to-buffer buffer))
3122 (defun prolog-read-predicate ()
3123 "Read a PredSpec from the user.
3124 Returned value is a string \"FUNCTOR/ARITY\".
3125 Interaction supports completion."
3126 (let ((default (prolog-atom-under-point)))
3127 ;; If the predicate index is not yet built, do it now
3128 (if (not prolog-info-alist)
3129 (prolog-build-info-alist))
3130 ;; Test if the default string could be the base for completion.
3131 ;; Discard it if not.
3132 (if (eq (try-completion default prolog-info-alist) nil)
3133 (setq default nil))
3134 ;; Read the PredSpec from the user
3135 (completing-read
3136 (if (zerop (length default))
3137 "Help on predicate: "
3138 (concat "Help on predicate (default " default "): "))
3139 prolog-info-alist nil t nil nil default)))
3141 (defun prolog-build-info-alist (&optional verbose)
3142 "Build an alist of all builtins and library predicates.
3143 Each element is of the form (\"NAME/ARITY\" . (INFO-NODE1 INFO-NODE2 ...)).
3144 Typically there is just one Info node associated with each name
3145 If an optional argument VERBOSE is non-nil, print messages at the beginning
3146 and end of list building."
3147 (if verbose
3148 (message "Building info alist..."))
3149 (setq prolog-info-alist
3150 (let ((l ())
3151 (last-entry (cons "" ())))
3152 (save-excursion
3153 (save-window-excursion
3154 ;; select any window but the minibuffer (as we cannot switch
3155 ;; buffers in minibuffer window.
3156 ;; I am not sure this is the right/best way
3157 (if (active-minibuffer-window) ; nil if none active
3158 (select-window (next-window)))
3159 ;; Do this after going away from minibuffer window
3160 (save-window-excursion
3161 (info))
3162 (Info-goto-node prolog-info-predicate-index)
3163 (goto-char (point-min))
3164 (while (re-search-forward
3165 "^\\* \\(.+\\)/\\([0-9]+\\)\\([^\n:*]*\\):" nil t)
3166 (let* ((name (match-string 1))
3167 (arity (string-to-number (match-string 2)))
3168 (comment (match-string 3))
3169 (fa (format "%s/%d%s" name arity comment))
3170 info-node)
3171 (beginning-of-line)
3172 ;; Extract the info node name
3173 (setq info-node (progn
3174 (re-search-forward ":[ \t]*\\([^:]+\\).$")
3175 (match-string 1)
3177 ;; ###### Easier? (from Milan version 0.1.28)
3178 ;; (setq info-node (Info-extract-menu-node-name))
3179 (if (equal fa (car last-entry))
3180 (setcdr last-entry (cons info-node (cdr last-entry)))
3181 (setq last-entry (cons fa (list info-node))
3182 l (cons last-entry l)))))
3183 (nreverse l)
3184 ))))
3185 (if verbose
3186 (message "Building info alist... done.")))
3189 ;;-------------------------------------------------------------------
3190 ;; Miscellaneous functions
3191 ;;-------------------------------------------------------------------
3193 ;; For Windows. Change backslash to slash. SICStus handles either
3194 ;; path separator but backslash must be doubled, therefore use slash.
3195 (defun prolog-bsts (string)
3196 "Change backslashes to slashes in STRING."
3197 (let ((str1 (copy-sequence string))
3198 (len (length string))
3199 (i 0))
3200 (while (< i len)
3201 (if (char-equal (aref str1 i) ?\\)
3202 (aset str1 i ?/))
3203 (setq i (1+ i)))
3204 str1))
3206 ;;(defun prolog-temporary-file ()
3207 ;; "Make temporary file name for compilation."
3208 ;; (make-temp-name
3209 ;; (concat
3210 ;; (or
3211 ;; (getenv "TMPDIR")
3212 ;; (getenv "TEMP")
3213 ;; (getenv "TMP")
3214 ;; (getenv "SYSTEMP")
3215 ;; "/tmp")
3216 ;; "/prolcomp")))
3217 ;;(setq prolog-temp-filename (prolog-bsts (prolog-temporary-file)))
3219 (defun prolog-temporary-file ()
3220 "Make temporary file name for compilation."
3221 (if prolog-temporary-file-name
3222 ;; We already have a file, erase content and continue
3223 (progn
3224 (write-region "" nil prolog-temporary-file-name nil 'silent)
3225 prolog-temporary-file-name)
3226 ;; Actually create the file and set `prolog-temporary-file-name'
3227 ;; accordingly.
3228 (setq prolog-temporary-file-name
3229 (make-temp-file "prolcomp" nil ".pl"))))
3231 (defun prolog-goto-prolog-process-buffer ()
3232 "Switch to the prolog process buffer and go to its end."
3233 (switch-to-buffer-other-window "*prolog*")
3234 (goto-char (point-max))
3237 (defun prolog-enable-sicstus-sd ()
3238 "Enable the source level debugging facilities of SICStus 3.7 and later."
3239 (interactive)
3240 (require 'pltrace) ; Load the SICStus debugger code
3241 ;; Turn on the source level debugging by default
3242 (add-hook 'prolog-inferior-mode-hook 'pltrace-on)
3243 (if (not prolog-use-sicstus-sd)
3244 (progn
3245 ;; If there is a *prolog* buffer, then call pltrace-on
3246 (if (get-buffer "*prolog*")
3247 ;; Avoid compilation warnings by using eval
3248 (eval '(pltrace-on)))
3249 (setq prolog-use-sicstus-sd t)
3252 (defun prolog-disable-sicstus-sd ()
3253 "Disable the source level debugging facilities of SICStus 3.7 and later."
3254 (interactive)
3255 (setq prolog-use-sicstus-sd nil)
3256 ;; Remove the hook
3257 (remove-hook 'prolog-inferior-mode-hook 'pltrace-on)
3258 ;; If there is a *prolog* buffer, then call pltrace-off
3259 (if (get-buffer "*prolog*")
3260 ;; Avoid compile warnings by using eval
3261 (eval '(pltrace-off))))
3263 (defun prolog-toggle-sicstus-sd ()
3264 ;; FIXME: Use define-minor-mode.
3265 "Toggle the source level debugging facilities of SICStus 3.7 and later."
3266 (interactive)
3267 (if prolog-use-sicstus-sd
3268 (prolog-disable-sicstus-sd)
3269 (prolog-enable-sicstus-sd)))
3271 (defun prolog-debug-on (&optional arg)
3272 "Enable debugging.
3273 When called with prefix argument ARG, disable debugging instead."
3274 (interactive "P")
3275 (if arg
3276 (prolog-debug-off)
3277 (prolog-process-insert-string (get-process "prolog")
3278 prolog-debug-on-string)
3279 (process-send-string "prolog" prolog-debug-on-string)))
3281 (defun prolog-debug-off ()
3282 "Disable debugging."
3283 (interactive)
3284 (prolog-process-insert-string (get-process "prolog")
3285 prolog-debug-off-string)
3286 (process-send-string "prolog" prolog-debug-off-string))
3288 (defun prolog-trace-on (&optional arg)
3289 "Enable tracing.
3290 When called with prefix argument ARG, disable tracing instead."
3291 (interactive "P")
3292 (if arg
3293 (prolog-trace-off)
3294 (prolog-process-insert-string (get-process "prolog")
3295 prolog-trace-on-string)
3296 (process-send-string "prolog" prolog-trace-on-string)))
3298 (defun prolog-trace-off ()
3299 "Disable tracing."
3300 (interactive)
3301 (prolog-process-insert-string (get-process "prolog")
3302 prolog-trace-off-string)
3303 (process-send-string "prolog" prolog-trace-off-string))
3305 (defun prolog-zip-on (&optional arg)
3306 "Enable zipping (for SICStus 3.7 and later).
3307 When called with prefix argument ARG, disable zipping instead."
3308 (interactive "P")
3309 (if (not (and (eq prolog-system 'sicstus)
3310 (prolog-atleast-version '(3 . 7))))
3311 (error "Only works for SICStus 3.7 and later"))
3312 (if arg
3313 (prolog-zip-off)
3314 (prolog-process-insert-string (get-process "prolog")
3315 prolog-zip-on-string)
3316 (process-send-string "prolog" prolog-zip-on-string)))
3318 (defun prolog-zip-off ()
3319 "Disable zipping (for SICStus 3.7 and later)."
3320 (interactive)
3321 (prolog-process-insert-string (get-process "prolog")
3322 prolog-zip-off-string)
3323 (process-send-string "prolog" prolog-zip-off-string))
3325 ;; (defun prolog-create-predicate-index ()
3326 ;; "Create an index for all predicates in the buffer."
3327 ;; (let ((predlist '())
3328 ;; clauseinfo
3329 ;; object
3330 ;; pos
3331 ;; )
3332 ;; (goto-char (point-min))
3333 ;; ;; Replace with prolog-clause-start!
3334 ;; (while (re-search-forward "^.+:-" nil t)
3335 ;; (setq pos (match-beginning 0))
3336 ;; (setq clauseinfo (prolog-clause-info))
3337 ;; (setq object (prolog-in-object))
3338 ;; (setq predlist (append
3339 ;; predlist
3340 ;; (list (cons
3341 ;; (if (and (eq prolog-system 'sicstus)
3342 ;; (prolog-in-object))
3343 ;; (format "%s::%s/%d"
3344 ;; object
3345 ;; (nth 0 clauseinfo)
3346 ;; (nth 1 clauseinfo))
3347 ;; (format "%s/%d"
3348 ;; (nth 0 clauseinfo)
3349 ;; (nth 1 clauseinfo)))
3350 ;; pos
3351 ;; ))))
3352 ;; (prolog-end-of-predicate))
3353 ;; predlist))
3355 (defun prolog-get-predspec ()
3356 (save-excursion
3357 (let ((state (prolog-clause-info))
3358 (object (prolog-in-object)))
3359 (if (or (equal (nth 0 state) "")
3360 (equal (prolog-in-string-or-comment) 'cmt))
3362 (if (and (eq prolog-system 'sicstus)
3363 object)
3364 (format "%s::%s/%d"
3365 object
3366 (nth 0 state)
3367 (nth 1 state))
3368 (format "%s/%d"
3369 (nth 0 state)
3370 (nth 1 state)))
3371 ))))
3373 ;; For backward compatibility. Stolen from custom.el.
3374 (or (fboundp 'match-string)
3375 ;; Introduced in Emacs 19.29.
3376 (defun match-string (num &optional string)
3377 "Return string of text matched by last search.
3378 NUM specifies which parenthesized expression in the last regexp.
3379 Value is nil if NUMth pair didn't match, or there were less than NUM pairs.
3380 Zero means the entire text matched by the whole regexp or whole string.
3381 STRING should be given if the last search was by `string-match' on STRING."
3382 (if (match-beginning num)
3383 (if string
3384 (substring string (match-beginning num) (match-end num))
3385 (buffer-substring (match-beginning num) (match-end num))))))
3387 (defun prolog-pred-start ()
3388 "Return the starting point of the first clause of the current predicate."
3389 ;; FIXME: Use SMIE.
3390 (save-excursion
3391 (goto-char (prolog-clause-start))
3392 ;; Find first clause, unless it was a directive
3393 (if (and (not (looking-at "[:?]-"))
3394 (not (looking-at "[ \t]*[%/]")) ; Comment
3397 (let* ((pinfo (prolog-clause-info))
3398 (predname (nth 0 pinfo))
3399 (arity (nth 1 pinfo))
3400 (op (point)))
3401 (while (and (re-search-backward
3402 (format "^%s\\([(\\.]\\| *%s\\)"
3403 predname prolog-head-delimiter) nil t)
3404 (= arity (nth 1 (prolog-clause-info)))
3406 (setq op (point)))
3407 (if (eq prolog-system 'mercury)
3408 ;; Skip to the beginning of declarations of the predicate
3409 (progn
3410 (goto-char (prolog-beginning-of-clause))
3411 (while (and (not (eq (point) op))
3412 (looking-at
3413 (format ":-[ \t]*\\(pred\\|mode\\)[ \t]+%s"
3414 predname)))
3415 (setq op (point))
3416 (goto-char (prolog-beginning-of-clause)))))
3418 (point))))
3420 (defun prolog-pred-end ()
3421 "Return the position at the end of the last clause of the current predicate."
3422 ;; FIXME: Use SMIE.
3423 (save-excursion
3424 (goto-char (prolog-clause-end)) ; If we are before the first predicate.
3425 (goto-char (prolog-clause-start))
3426 (let* ((pinfo (prolog-clause-info))
3427 (predname (nth 0 pinfo))
3428 (arity (nth 1 pinfo))
3429 oldp
3430 (notdone t)
3431 (op (point)))
3432 (if (looking-at "[:?]-")
3433 ;; This was a directive
3434 (progn
3435 (if (and (eq prolog-system 'mercury)
3436 (looking-at
3437 (format ":-[ \t]*\\(pred\\|mode\\)[ \t]+\\(%s+\\)"
3438 prolog-atom-regexp)))
3439 ;; Skip predicate declarations
3440 (progn
3441 (setq predname (buffer-substring-no-properties
3442 (match-beginning 2) (match-end 2)))
3443 (while (re-search-forward
3444 (format
3445 "\n*\\(:-[ \t]*\\(pred\\|mode\\)[ \t]+\\)?%s[( \t]"
3446 predname)
3447 nil t))))
3448 (goto-char (prolog-clause-end))
3449 (setq op (point)))
3450 ;; It was not a directive, find the last clause
3451 (while (and notdone
3452 (re-search-forward
3453 (format "^%s\\([(\\.]\\| *%s\\)"
3454 predname prolog-head-delimiter) nil t)
3455 (= arity (nth 1 (prolog-clause-info))))
3456 (setq oldp (point))
3457 (setq op (prolog-clause-end))
3458 (if (>= oldp op)
3459 ;; End of clause not found.
3460 (setq notdone nil)
3461 ;; Continue while loop
3462 (goto-char op))))
3463 op)))
3465 (defun prolog-clause-start (&optional not-allow-methods)
3466 "Return the position at the start of the head of the current clause.
3467 If NOTALLOWMETHODS is non-nil then do not match on methods in
3468 objects (relevant only if 'prolog-system' is set to 'sicstus)."
3469 (save-excursion
3470 (let ((notdone t)
3471 (retval (point-min)))
3472 (end-of-line)
3474 ;; SICStus object?
3475 (if (and (not not-allow-methods)
3476 (eq prolog-system 'sicstus)
3477 (prolog-in-object))
3478 (while (and
3479 notdone
3480 ;; Search for a head or a fact
3481 (re-search-backward
3482 ;; If in object, then find method start.
3483 ;; "^[ \t]+[a-z$].*\\(:-\\|&\\|:: {\\|,\\)"
3484 "^[ \t]+[a-z$].*\\(:-\\|&\\|:: {\\)" ; The comma causes
3485 ; problems since we cannot assume
3486 ; that the line starts at column 0,
3487 ; thus we don't know if the line
3488 ; is a head or a subgoal
3489 (point-min) t))
3490 (if (>= (prolog-paren-balance) 0) ; To no match on " a) :-"
3491 ;; Start of method found
3492 (progn
3493 (setq retval (point))
3494 (setq notdone nil)))
3495 ) ; End of while
3497 ;; Not in object
3498 (while (and
3499 notdone
3500 ;; Search for a text at beginning of a line
3501 ;; ######
3502 ;; (re-search-backward "^[a-z$']" nil t))
3503 (let ((case-fold-search nil))
3504 (re-search-backward
3505 ;; (format "^[%s$']" prolog-lower-case-string)
3506 ;; FIXME: Use [:lower:]
3507 (format "^\\([%s$']\\|[:?]-\\)" prolog-lower-case-string)
3508 nil t)))
3509 (let ((bal (prolog-paren-balance)))
3510 (cond
3511 ((> bal 0)
3512 ;; Start of clause found
3513 (progn
3514 (setq retval (point))
3515 (setq notdone nil)))
3516 ((and (= bal 0)
3517 (looking-at
3518 (format ".*\\(\\.\\|%s\\|!,\\)[ \t]*\\(%%.*\\|\\)$"
3519 prolog-head-delimiter)))
3520 ;; Start of clause found if the line ends with a '.' or
3521 ;; a prolog-head-delimiter
3522 (progn
3523 (setq retval (point))
3524 (setq notdone nil))
3526 (t nil) ; Do nothing
3527 ))))
3529 retval)))
3531 (defun prolog-clause-end (&optional not-allow-methods)
3532 "Return the position at the end of the current clause.
3533 If NOTALLOWMETHODS is non-nil then do not match on methods in
3534 objects (relevant only if 'prolog-system' is set to 'sicstus)."
3535 (save-excursion
3536 (beginning-of-line) ; Necessary since we use "^...." for the search.
3537 (if (re-search-forward
3538 (if (and (not not-allow-methods)
3539 (eq prolog-system 'sicstus)
3540 (prolog-in-object))
3541 (format
3542 "^\\(%s\\|%s\\|[^\n\'\"%%]\\)*&[ \t]*\\(\\|%%.*\\)$\\|[ \t]*}"
3543 prolog-quoted-atom-regexp prolog-string-regexp)
3544 (format
3545 "^\\(%s\\|%s\\|[^\n\'\"%%]\\)*\\.[ \t]*\\(\\|%%.*\\)$"
3546 prolog-quoted-atom-regexp prolog-string-regexp))
3547 nil t)
3548 (if (and (prolog-in-string-or-comment)
3549 (not (eobp)))
3550 (progn
3551 (forward-char)
3552 (prolog-clause-end))
3553 (point))
3554 (point))))
3556 (defun prolog-clause-info ()
3557 "Return a (name arity) list for the current clause."
3558 (save-excursion
3559 (goto-char (prolog-clause-start))
3560 (let* ((op (point))
3561 (predname
3562 (if (looking-at prolog-atom-char-regexp)
3563 (progn
3564 (skip-chars-forward "^ (\\.")
3565 (buffer-substring op (point)))
3566 ""))
3567 (arity 0))
3568 ;; Retrieve the arity.
3569 (if (looking-at prolog-left-paren)
3570 (let ((endp (save-excursion
3571 (prolog-forward-list) (point))))
3572 (setq arity 1)
3573 (forward-char 1) ; Skip the opening paren.
3574 (while (progn
3575 (skip-chars-forward "^[({,'\"")
3576 (< (point) endp))
3577 (if (looking-at ",")
3578 (progn
3579 (setq arity (1+ arity))
3580 (forward-char 1) ; Skip the comma.
3582 ;; We found a string, list or something else we want
3583 ;; to skip over. Always use prolog-tokenize,
3584 ;; parse-partial-sexp does not have a 'skipover mode.
3585 (goto-char (nth 5 (prolog-tokenize (point) endp 'skipover))))
3587 (list predname arity))))
3589 (defun prolog-in-object ()
3590 "Return object name if the point is inside a SICStus object definition."
3591 ;; Return object name if the last line that starts with a character
3592 ;; that is neither white space nor a comment start
3593 (save-excursion
3594 (if (save-excursion
3595 (beginning-of-line)
3596 (looking-at "\\([^\n ]+\\)[ \t]*::[ \t]*{"))
3597 ;; We were in the head of the object
3598 (match-string 1)
3599 ;; We were not in the head
3600 (if (and (re-search-backward "^[a-z$'}]" nil t)
3601 (looking-at "\\([^\n ]+\\)[ \t]*::[ \t]*{"))
3602 (match-string 1)
3603 nil))))
3605 (defun prolog-forward-list ()
3606 "Move the point to the matching right parenthesis."
3607 (interactive)
3608 (if prolog-use-prolog-tokenizer-flag
3609 (let ((state (prolog-tokenize (point) (point-max) 'zerodepth)))
3610 (goto-char (nth 5 state)))
3611 (forward-list)))
3613 ;; NB: This could be done more efficiently!
3614 (defun prolog-backward-list ()
3615 "Move the point to the matching left parenthesis."
3616 (interactive)
3617 (if prolog-use-prolog-tokenizer-flag
3618 (let ((bal 0)
3619 (paren-regexp (concat prolog-left-paren "\\|" prolog-right-paren))
3620 (notdone t))
3621 ;; FIXME: Doesn't this incorrectly count 0'( and 0') ?
3622 (while (and notdone (re-search-backward paren-regexp nil t))
3623 (cond
3624 ((looking-at prolog-left-paren)
3625 (if (not (prolog-in-string-or-comment))
3626 (setq bal (1+ bal)))
3627 (if (= bal 0)
3628 (setq notdone nil)))
3629 ((looking-at prolog-right-paren)
3630 (if (not (prolog-in-string-or-comment))
3631 (setq bal (1- bal))))
3633 (backward-list)))
3635 (defun prolog-beginning-of-clause ()
3636 "Move to the beginning of current clause.
3637 If already at the beginning of clause, move to previous clause."
3638 (interactive)
3639 (let ((point (point))
3640 (new-point (prolog-clause-start)))
3641 (if (and (>= new-point point)
3642 (> point 1))
3643 (progn
3644 (goto-char (1- point))
3645 (goto-char (prolog-clause-start)))
3646 (goto-char new-point)
3647 (skip-chars-forward " \t"))))
3649 ;; (defun prolog-previous-clause ()
3650 ;; "Move to the beginning of the previous clause."
3651 ;; (interactive)
3652 ;; (forward-char -1)
3653 ;; (prolog-beginning-of-clause))
3655 (defun prolog-end-of-clause ()
3656 "Move to the end of clause.
3657 If already at the end of clause, move to next clause."
3658 (interactive)
3659 (let ((point (point))
3660 (new-point (prolog-clause-end)))
3661 (if (and (<= new-point point)
3662 (not (eq new-point (point-max))))
3663 (progn
3664 (goto-char (1+ point))
3665 (goto-char (prolog-clause-end)))
3666 (goto-char new-point))))
3668 ;; (defun prolog-next-clause ()
3669 ;; "Move to the beginning of the next clause."
3670 ;; (interactive)
3671 ;; (prolog-end-of-clause)
3672 ;; (forward-char)
3673 ;; (prolog-end-of-clause)
3674 ;; (prolog-beginning-of-clause))
3676 (defun prolog-beginning-of-predicate ()
3677 "Go to the nearest beginning of predicate before current point.
3678 Return the final point or nil if no such a beginning was found."
3679 ;; FIXME: Hook into beginning-of-defun.
3680 (interactive)
3681 (let ((op (point))
3682 (pos (prolog-pred-start)))
3683 (if pos
3684 (if (= op pos)
3685 (if (not (bobp))
3686 (progn
3687 (goto-char pos)
3688 (backward-char 1)
3689 (setq pos (prolog-pred-start))
3690 (if pos
3691 (progn
3692 (goto-char pos)
3693 (point)))))
3694 (goto-char pos)
3695 (point)))))
3697 (defun prolog-end-of-predicate ()
3698 "Go to the end of the current predicate."
3699 ;; FIXME: Hook into end-of-defun.
3700 (interactive)
3701 (let ((op (point)))
3702 (goto-char (prolog-pred-end))
3703 (if (= op (point))
3704 (progn
3705 (forward-line 1)
3706 (prolog-end-of-predicate)))))
3708 (defun prolog-insert-predspec ()
3709 "Insert the predspec for the current predicate."
3710 (interactive)
3711 (let* ((pinfo (prolog-clause-info))
3712 (predname (nth 0 pinfo))
3713 (arity (nth 1 pinfo)))
3714 (insert (format "%s/%d" predname arity))))
3716 (defun prolog-view-predspec ()
3717 "Insert the predspec for the current predicate."
3718 (interactive)
3719 (let* ((pinfo (prolog-clause-info))
3720 (predname (nth 0 pinfo))
3721 (arity (nth 1 pinfo)))
3722 (message (format "%s/%d" predname arity))))
3724 (defun prolog-insert-predicate-template ()
3725 "Insert the template for the current clause."
3726 (interactive)
3727 (let* ((n 1)
3728 oldp
3729 (pinfo (prolog-clause-info))
3730 (predname (nth 0 pinfo))
3731 (arity (nth 1 pinfo)))
3732 (insert predname)
3733 (if (> arity 0)
3734 (progn
3735 (insert "(")
3736 (when prolog-electric-dot-full-predicate-template
3737 (setq oldp (point))
3738 (while (< n arity)
3739 (insert ",")
3740 (setq n (1+ n)))
3741 (insert ")")
3742 (goto-char oldp))
3746 (defun prolog-insert-next-clause ()
3747 "Insert newline and the name of the current clause."
3748 (interactive)
3749 (insert "\n")
3750 (prolog-insert-predicate-template))
3752 (defun prolog-insert-module-modeline ()
3753 "Insert a modeline for module specification.
3754 This line should be first in the buffer.
3755 The module name should be written manually just before the semi-colon."
3756 (interactive)
3757 (insert "%%% -*- Module: ; -*-\n")
3758 (backward-char 6))
3760 (defalias 'prolog-uncomment-region
3761 (if (fboundp 'uncomment-region) #'uncomment-region
3762 (lambda (beg end)
3763 "Uncomment the region between BEG and END."
3764 (interactive "r")
3765 (comment-region beg end -1))))
3767 (defun prolog-goto-comment-column (&optional nocreate)
3768 "Move comments on the current line to the correct position.
3769 If NOCREATE is nil (or omitted) and there is no comment on the line, then
3770 a new comment is created."
3771 (interactive)
3772 (beginning-of-line)
3773 (if (or (not nocreate)
3774 (and
3775 (re-search-forward
3776 (format "^\\(\\(%s\\|%s\\|[^\n\'\"%%]\\)*\\)%% *"
3777 prolog-quoted-atom-regexp prolog-string-regexp)
3778 (line-end-position) 'limit)
3779 (progn
3780 (goto-char (match-beginning 0))
3781 (not (eq (prolog-in-string-or-comment) 'txt)))))
3782 (indent-for-comment)))
3784 (defun prolog-indent-predicate ()
3785 "Indent the current predicate."
3786 (interactive)
3787 (indent-region (prolog-pred-start) (prolog-pred-end) nil))
3789 (defun prolog-indent-buffer ()
3790 "Indent the entire buffer."
3791 (interactive)
3792 (indent-region (point-min) (point-max) nil))
3794 (defun prolog-mark-clause ()
3795 "Put mark at the end of this clause and move point to the beginning."
3796 (interactive)
3797 (let ((pos (point)))
3798 (goto-char (prolog-clause-end))
3799 (forward-line 1)
3800 (beginning-of-line)
3801 (set-mark (point))
3802 (goto-char pos)
3803 (goto-char (prolog-clause-start))))
3805 (defun prolog-mark-predicate ()
3806 "Put mark at the end of this predicate and move point to the beginning."
3807 (interactive)
3808 (goto-char (prolog-pred-end))
3809 (let ((pos (point)))
3810 (forward-line 1)
3811 (beginning-of-line)
3812 (set-mark (point))
3813 (goto-char pos)
3814 (goto-char (prolog-pred-start))))
3816 ;; Stolen from `cc-mode.el':
3817 (defun prolog-electric-delete (arg)
3818 "Delete preceding character or whitespace.
3819 If `prolog-hungry-delete-key-flag' is non-nil, then all preceding whitespace is
3820 consumed. If however an ARG is supplied, or `prolog-hungry-delete-key-flag' is
3821 nil, or point is inside a literal then the function
3822 `backward-delete-char' is called."
3823 (interactive "P")
3824 (if (or (not prolog-hungry-delete-key-flag)
3826 (prolog-in-string-or-comment))
3827 (funcall 'backward-delete-char (prefix-numeric-value arg))
3828 (let ((here (point)))
3829 (skip-chars-backward " \t\n")
3830 (if (/= (point) here)
3831 (delete-region (point) here)
3832 (funcall 'backward-delete-char 1)
3833 ))))
3835 ;; For XEmacs compatibility (suggested by Per Mildner)
3836 (put 'prolog-electric-delete 'pending-delete 'supersede)
3838 (defun prolog-electric-if-then-else (arg)
3839 "If `prolog-electric-if-then-else-flag' is non-nil, indent if-then-else constructs.
3840 Bound to the >, ; and ( keys."
3841 ;; FIXME: Use post-self-insert-hook or electric-indent-mode.
3842 (interactive "P")
3843 (self-insert-command (prefix-numeric-value arg))
3844 (if prolog-electric-if-then-else-flag (prolog-insert-spaces-after-paren)))
3846 (defun prolog-electric-colon (arg)
3847 "If `prolog-electric-colon-flag' is non-nil, insert the electric `:' construct.
3848 That is, insert space (if appropriate), `:-' and newline if colon is pressed
3849 at the end of a line that starts in the first column (i.e., clause
3850 heads)."
3851 ;; FIXME: Use post-self-insert-hook.
3852 (interactive "P")
3853 (if (and prolog-electric-colon-flag
3854 (null arg)
3855 (eolp)
3856 ;(not (string-match "^\\s " (thing-at-point 'line))))
3857 (not (string-match "^\\(\\s \\|%\\)" (thing-at-point 'line))))
3858 (progn
3859 (unless (save-excursion (backward-char 1) (looking-at "\\s "))
3860 (insert " "))
3861 (insert ":-\n")
3862 (indent-according-to-mode))
3863 (self-insert-command (prefix-numeric-value arg))))
3865 (defun prolog-electric-dash (arg)
3866 "If `prolog-electric-dash-flag' is non-nil, insert the electric `-' construct.
3867 that is, insert space (if appropriate), `-->' and newline if dash is pressed
3868 at the end of a line that starts in the first column (i.e., DCG
3869 heads)."
3870 ;; FIXME: Use post-self-insert-hook.
3871 (interactive "P")
3872 (if (and prolog-electric-dash-flag
3873 (null arg)
3874 (eolp)
3875 ;(not (string-match "^\\s " (thing-at-point 'line))))
3876 (not (string-match "^\\(\\s \\|%\\)" (thing-at-point 'line))))
3877 (progn
3878 (unless (save-excursion (backward-char 1) (looking-at "\\s "))
3879 (insert " "))
3880 (insert "-->\n")
3881 (indent-according-to-mode))
3882 (self-insert-command (prefix-numeric-value arg))))
3884 (defun prolog-electric-dot (arg)
3885 "Insert dot and newline or a head of a new clause.
3887 If `prolog-electric-dot-flag' is nil, then simply insert dot.
3888 Otherwise::
3889 When invoked at the end of nonempty line, insert dot and newline.
3890 When invoked at the end of an empty line, insert a recursive call to
3891 the current predicate.
3892 When invoked at the beginning of line, insert a head of a new clause
3893 of the current predicate.
3895 When called with prefix argument ARG, insert just dot."
3896 ;; FIXME: Use post-self-insert-hook.
3897 (interactive "P")
3898 ;; Check for situations when the electricity should not be active
3899 (if (or (not prolog-electric-dot-flag)
3901 (prolog-in-string-or-comment)
3902 ;; Do not be electric in a floating point number or an operator
3903 (not
3905 ;; (re-search-backward
3906 ;; ######
3907 ;; "\\(^\\|[])}a-zA-Z_!'0-9]+\\)[ \t]*\\=" nil t)))
3908 (save-excursion
3909 (re-search-backward
3910 ;; "\\(^\\|[])}_!'0-9]+\\)[ \t]*\\=" nil t)))
3911 "\\(^\\|[])}_!'0-9]+\\)[ \t]*\\="
3912 nil t))
3913 (save-excursion
3914 (re-search-backward
3915 ;; "\\(^\\|[])}a-zA-Z]+\\)[ \t]*\\=" nil t)))
3916 (format "\\(^\\|[])}%s]+\\)[ \t]*\\="
3917 prolog-lower-case-string) ;FIXME: [:lower:]
3918 nil t))
3919 (save-excursion
3920 (re-search-backward
3921 ;; "\\(^\\|[])}a-zA-Z]+\\)[ \t]*\\=" nil t)))
3922 (format "\\(^\\|[])}%s]+\\)[ \t]*\\="
3923 prolog-upper-case-string) ;FIXME: [:upper:]
3924 nil t))
3927 ;; Do not be electric if inside a parenthesis pair.
3928 (not (= (prolog-region-paren-balance (prolog-clause-start) (point))
3931 (funcall 'self-insert-command (prefix-numeric-value arg))
3932 (cond
3933 ;; Beginning of line
3934 ((bolp)
3935 (prolog-insert-predicate-template))
3936 ;; At an empty line with at least one whitespace
3937 ((save-excursion
3938 (beginning-of-line)
3939 (looking-at "[ \t]+$"))
3940 (prolog-insert-predicate-template)
3941 (when prolog-electric-dot-full-predicate-template
3942 (save-excursion
3943 (end-of-line)
3944 (insert ".\n"))))
3945 ;; Default
3947 (insert ".\n"))
3950 (defun prolog-electric-underscore ()
3951 "Replace variable with an underscore.
3952 If `prolog-electric-underscore-flag' is non-nil and the point is
3953 on a variable then replace the variable with underscore and skip
3954 the following comma and whitespace, if any.
3955 If the point is not on a variable then insert underscore."
3956 ;; FIXME: Use post-self-insert-hook.
3957 (interactive)
3958 (if prolog-electric-underscore-flag
3959 (let (;start
3960 (case-fold-search nil)
3961 (oldp (point)))
3962 ;; ######
3963 ;;(skip-chars-backward "a-zA-Z_")
3964 (skip-chars-backward
3965 (format "%s%s_"
3966 ;; FIXME: Why not "a-zA-Z"?
3967 prolog-lower-case-string
3968 prolog-upper-case-string))
3970 ;(setq start (point))
3971 (if (and (not (prolog-in-string-or-comment))
3972 ;; ######
3973 ;; (looking-at "\\<[_A-Z][a-zA-Z_0-9]*\\>"))
3974 (looking-at (format "\\<[_%s][%s%s_0-9]*\\>"
3975 ;; FIXME: Use [:upper:] and friends.
3976 prolog-upper-case-string
3977 prolog-lower-case-string
3978 prolog-upper-case-string)))
3979 (progn
3980 (replace-match "_")
3981 (skip-chars-forward ", \t\n"))
3982 (goto-char oldp)
3983 (self-insert-command 1))
3985 (self-insert-command 1))
3989 (defun prolog-find-term (functor arity &optional prefix)
3990 "Go to the position at the start of the next occurrence of a term.
3991 The term is specified with FUNCTOR and ARITY. The optional argument
3992 PREFIX is the prefix of the search regexp."
3993 (let* (;; If prefix is not set then use the default "\\<"
3994 (prefix (if (not prefix)
3995 "\\<"
3996 prefix))
3997 (regexp (concat prefix functor))
3998 (i 1))
4000 ;; Build regexp for the search if the arity is > 0
4001 (if (= arity 0)
4002 ;; Add that the functor must be at the end of a word. This
4003 ;; does not work if the arity is > 0 since the closing )
4004 ;; is not a word constituent.
4005 (setq regexp (concat regexp "\\>"))
4006 ;; Arity is > 0, add parens and commas
4007 (setq regexp (concat regexp "("))
4008 (while (< i arity)
4009 (setq regexp (concat regexp ".+,"))
4010 (setq i (1+ i)))
4011 (setq regexp (concat regexp ".+)")))
4013 ;; Search, and return position
4014 (if (re-search-forward regexp nil t)
4015 (goto-char (match-beginning 0))
4016 (error "Term not found"))
4019 (defun prolog-variables-to-anonymous (beg end)
4020 "Replace all variables within a region BEG to END by anonymous variables."
4021 (interactive "r")
4022 (save-excursion
4023 (let ((case-fold-search nil))
4024 (goto-char end)
4025 (while (re-search-backward "\\<[A-Z_][a-zA-Z_0-9]*\\>" beg t)
4026 (progn
4027 (replace-match "_")
4028 (backward-char)))
4031 ;;(defun prolog-regexp-dash-continuous-chars (chars)
4032 ;; (let ((ints (mapcar #'prolog-char-to-int (string-to-list chars)))
4033 ;; (beg 0)
4034 ;; (end 0))
4035 ;; (if (null ints)
4036 ;; chars
4037 ;; (while (and (< (+ beg 1) (length chars))
4038 ;; (not (or (= (+ (nth beg ints) 1) (nth (+ beg 1) ints))
4039 ;; (= (nth beg ints) (nth (+ beg 1) ints)))))
4040 ;; (setq beg (+ beg 1)))
4041 ;; (setq beg (+ beg 1)
4042 ;; end beg)
4043 ;; (while (and (< (+ end 1) (length chars))
4044 ;; (or (= (+ (nth end ints) 1) (nth (+ end 1) ints))
4045 ;; (= (nth end ints) (nth (+ end 1) ints))))
4046 ;; (setq end (+ end 1)))
4047 ;; (if (equal (substring chars end) "")
4048 ;; (substring chars 0 beg)
4049 ;; (concat (substring chars 0 beg) "-"
4050 ;; (prolog-regexp-dash-continuous-chars (substring chars end))))
4051 ;; )))
4053 ;;(defun prolog-condense-character-sets (regexp)
4054 ;; "Condense adjacent characters in character sets of REGEXP."
4055 ;; (let ((next -1))
4056 ;; (while (setq next (string-match "\\[\\(.*?\\)\\]" regexp (1+ next)))
4057 ;; (setq regexp (replace-match (prolog-dash-letters (match-string 1 regexp))
4058 ;; t t regexp 1))))
4059 ;; regexp)
4061 ;;-------------------------------------------------------------------
4062 ;; Menu stuff (both for the editing buffer and for the inferior
4063 ;; prolog buffer)
4064 ;;-------------------------------------------------------------------
4066 (unless (fboundp 'region-exists-p)
4067 (defun region-exists-p ()
4068 "Non-nil iff the mark is set. Lobotomized version for Emacsen that do not provide their own."
4069 (mark)))
4072 ;; GNU Emacs ignores `easy-menu-add' so the order in which the menus
4073 ;; are defined _is_ important!
4075 (easy-menu-define
4076 prolog-menu-help (list prolog-mode-map prolog-inferior-mode-map)
4077 "Help menu for the Prolog mode."
4078 ;; FIXME: Does it really deserve a whole menu to itself?
4079 `(,(if (featurep 'xemacs) "Help"
4080 ;; Not sure it's worth the trouble. --Stef
4081 ;; (add-to-list 'menu-bar-final-items
4082 ;; (easy-menu-intern "Prolog-Help"))
4083 "Prolog-help")
4084 ["On predicate" prolog-help-on-predicate prolog-help-function-i]
4085 ["Apropos" prolog-help-apropos (eq prolog-system 'swi)]
4086 "---"
4087 ["Describe mode" describe-mode t]))
4089 (easy-menu-define
4090 prolog-edit-menu-runtime prolog-mode-map
4091 "Runtime Prolog commands available from the editing buffer"
4092 ;; FIXME: Don't use a whole menu for just "Run Mercury". --Stef
4093 `("System"
4094 ;; Runtime menu name.
4095 ,@(unless (featurep 'xemacs)
4096 '(:label (cond ((eq prolog-system 'eclipse) "ECLiPSe")
4097 ((eq prolog-system 'mercury) "Mercury")
4098 (t "System"))))
4100 ;; Consult items, NIL for mercury.
4101 ["Consult file" prolog-consult-file
4102 :included (not (eq prolog-system 'mercury))]
4103 ["Consult buffer" prolog-consult-buffer
4104 :included (not (eq prolog-system 'mercury))]
4105 ["Consult region" prolog-consult-region :active (region-exists-p)
4106 :included (not (eq prolog-system 'mercury))]
4107 ["Consult predicate" prolog-consult-predicate
4108 :included (not (eq prolog-system 'mercury))]
4110 ;; Compile items, NIL for everything but SICSTUS.
4111 ,(if (featurep 'xemacs) "---"
4112 ["---" nil :included (eq prolog-system 'sicstus)])
4113 ["Compile file" prolog-compile-file
4114 :included (eq prolog-system 'sicstus)]
4115 ["Compile buffer" prolog-compile-buffer
4116 :included (eq prolog-system 'sicstus)]
4117 ["Compile region" prolog-compile-region :active (region-exists-p)
4118 :included (eq prolog-system 'sicstus)]
4119 ["Compile predicate" prolog-compile-predicate
4120 :included (eq prolog-system 'sicstus)]
4122 ;; Debug items, NIL for Mercury.
4123 ,(if (featurep 'xemacs) "---"
4124 ["---" nil :included (not (eq prolog-system 'mercury))])
4125 ;; FIXME: Could we use toggle or radio buttons? --Stef
4126 ["Debug" prolog-debug-on :included (not (eq prolog-system 'mercury))]
4127 ["Debug off" prolog-debug-off
4128 ;; In SICStus, these are pairwise disjunctive,
4129 ;; so it's enough with a single "off"-command
4130 :included (not (memq prolog-system '(mercury sicstus)))]
4131 ["Trace" prolog-trace-on :included (not (eq prolog-system 'mercury))]
4132 ["Trace off" prolog-trace-off
4133 :included (not (memq prolog-system '(mercury sicstus)))]
4134 ["Zip" prolog-zip-on :included (and (eq prolog-system 'sicstus)
4135 (prolog-atleast-version '(3 . 7)))]
4136 ["All debug off" prolog-debug-off
4137 :included (eq prolog-system 'sicstus)]
4138 ["Source level debugging"
4139 prolog-toggle-sicstus-sd
4140 :included (and (eq prolog-system 'sicstus)
4141 (prolog-atleast-version '(3 . 7)))
4142 :style toggle
4143 :selected prolog-use-sicstus-sd]
4145 "---"
4146 ["Run" run-prolog
4147 :suffix (cond ((eq prolog-system 'eclipse) "ECLiPSe")
4148 ((eq prolog-system 'mercury) "Mercury")
4149 (t "Prolog"))]))
4151 (easy-menu-define
4152 prolog-edit-menu-insert-move prolog-mode-map
4153 "Commands for Prolog code manipulation."
4154 '("Prolog"
4155 ["Comment region" comment-region (region-exists-p)]
4156 ["Uncomment region" prolog-uncomment-region (region-exists-p)]
4157 ["Add comment/move to comment" indent-for-comment t]
4158 ["Convert variables in region to '_'" prolog-variables-to-anonymous
4159 :active (region-exists-p) :included (not (eq prolog-system 'mercury))]
4160 "---"
4161 ["Insert predicate template" prolog-insert-predicate-template t]
4162 ["Insert next clause head" prolog-insert-next-clause t]
4163 ["Insert predicate spec" prolog-insert-predspec t]
4164 ["Insert module modeline" prolog-insert-module-modeline t]
4165 "---"
4166 ["Beginning of clause" prolog-beginning-of-clause t]
4167 ["End of clause" prolog-end-of-clause t]
4168 ["Beginning of predicate" prolog-beginning-of-predicate t]
4169 ["End of predicate" prolog-end-of-predicate t]
4170 "---"
4171 ["Indent line" indent-according-to-mode t]
4172 ["Indent region" indent-region (region-exists-p)]
4173 ["Indent predicate" prolog-indent-predicate t]
4174 ["Indent buffer" prolog-indent-buffer t]
4175 ["Align region" align (region-exists-p)]
4176 "---"
4177 ["Mark clause" prolog-mark-clause t]
4178 ["Mark predicate" prolog-mark-predicate t]
4179 ["Mark paragraph" mark-paragraph t]
4180 ;;"---"
4181 ;;["Fontify buffer" font-lock-fontify-buffer t]
4184 (defun prolog-menu ()
4185 "Add the menus for the Prolog editing buffers."
4187 (easy-menu-add prolog-edit-menu-insert-move)
4188 (easy-menu-add prolog-edit-menu-runtime)
4190 ;; Add predicate index menu
4191 (set (make-local-variable 'imenu-create-index-function)
4192 'imenu-default-create-index-function)
4193 ;;Milan (this has problems with object methods...) ###### Does it? (Stefan)
4194 (setq imenu-prev-index-position-function 'prolog-beginning-of-predicate)
4195 (setq imenu-extract-index-name-function 'prolog-get-predspec)
4197 (if (and prolog-imenu-flag
4198 (< (count-lines (point-min) (point-max)) prolog-imenu-max-lines))
4199 (imenu-add-to-menubar "Predicates"))
4201 (easy-menu-add prolog-menu-help))
4203 (easy-menu-define
4204 prolog-inferior-menu-all prolog-inferior-mode-map
4205 "Menu for the inferior Prolog buffer."
4206 `("Prolog"
4207 ;; Runtime menu name.
4208 ,@(unless (featurep 'xemacs)
4209 '(:label (cond ((eq prolog-system 'eclipse) "ECLiPSe")
4210 ((eq prolog-system 'mercury) "Mercury")
4211 (t "Prolog"))))
4213 ;; Debug items, NIL for Mercury.
4214 ,(if (featurep 'xemacs) "---"
4215 ["---" nil :included (not (eq prolog-system 'mercury))])
4216 ;; FIXME: Could we use toggle or radio buttons? --Stef
4217 ["Debug" prolog-debug-on :included (not (eq prolog-system 'mercury))]
4218 ["Debug off" prolog-debug-off
4219 ;; In SICStus, these are pairwise disjunctive,
4220 ;; so it's enough with a single "off"-command
4221 :included (not (memq prolog-system '(mercury sicstus)))]
4222 ["Trace" prolog-trace-on :included (not (eq prolog-system 'mercury))]
4223 ["Trace off" prolog-trace-off
4224 :included (not (memq prolog-system '(mercury sicstus)))]
4225 ["Zip" prolog-zip-on :included (and (eq prolog-system 'sicstus)
4226 (prolog-atleast-version '(3 . 7)))]
4227 ["All debug off" prolog-debug-off
4228 :included (eq prolog-system 'sicstus)]
4229 ["Source level debugging"
4230 prolog-toggle-sicstus-sd
4231 :included (and (eq prolog-system 'sicstus)
4232 (prolog-atleast-version '(3 . 7)))
4233 :style toggle
4234 :selected prolog-use-sicstus-sd]
4236 ;; Runtime.
4237 "---"
4238 ["Interrupt Prolog" comint-interrupt-subjob t]
4239 ["Quit Prolog" comint-quit-subjob t]
4240 ["Kill Prolog" comint-kill-subjob t]))
4243 (defun prolog-inferior-menu ()
4244 "Create the menus for the Prolog inferior buffer.
4245 This menu is dynamically created because one may change systems during
4246 the life of an Emacs session."
4247 (easy-menu-add prolog-inferior-menu-all)
4248 (easy-menu-add prolog-menu-help))
4250 (defun prolog-mode-version ()
4251 "Echo the current version of Prolog mode in the minibuffer."
4252 (interactive)
4253 (message "Using Prolog mode version %s" prolog-mode-version))
4255 (provide 'prolog)
4257 ;;; prolog.el ends here