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