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