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