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