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