Commit e2019526 authored by Stefan Bruda's avatar Stefan Bruda Committed by Stefan Monnier
Browse files

* lisp/progmodes/prolog.el: Replace by a whole new file.

parent 3fa173b4
2011-01-11 Stefan Bruda <>
* progmodes/prolog.el: Replace by a whole new file.
2011-01-11 Stefan Monnier <>
* subr.el (eval-after-load): Fix timing for features (bug#7769).
;;; prolog.el --- major mode for editing and running Prolog under Emacs
;; prolog.el --- major mode for editing and running Prolog (and Mercury) code
;; Copyright (C) 1986, 1987, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
;; 2008, 2009, 2010 Free Software Foundation, Inc.
;; Copyright (C) 1986, 1987, 1997, 1998, 1999, 2002, 2003 Free Software Foundation, Inc.
;; Author: Masanobu UMEDA <>
;; Keywords: languages
;; Authors: Emil Åström <emil_astrom(at)hotmail(dot)com>
;; Milan Zamazal <pdm(at)freesoft(dot)cz>
;; Stefan Bruda <stefan(at)bruda(dot)ca> (current maintainer)
;; * See below for more details
;; Keywords: prolog major mode sicstus swi mercury
;; This file is part of GNU Emacs.
(defvar prolog-mode-version "1.22"
"Prolog mode version number")
;; GNU Emacs is free software: you can redistribute it and/or modify
;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.
;; the Free Software Foundation; either version 2, or (at your option)
;; any later version.
;; GNU Emacs is distributed in the hope that it will be useful,
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs. If not, see <>.
;; along with GNU Emacs; see the file COPYING. If not, write to the
;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
;; Boston, MA 02111-1307, USA.
;; Original author: Masanobu UMEDA <umerin(at)mse(dot)kyutech(dot)ac(dot)jp>
;; Parts of this file was taken from a modified version of the original
;; by Johan Andersson, Peter Olin, Mats Carlsson, Johan Bevemyr, Stefan
;; Andersson, and Per Danielsson (all SICS people), and Henrik Båkman
;; at Uppsala University, Sweden.
;; Some ideas and also a few lines of code have been borrowed (not stolen ;-)
;; from Oz.el, the Emacs major mode for the Oz programming language,
;; Copyright (C) 1993 DFKI GmbH, Germany, with permission.
;; Authors: Ralf Scheidhauer and Michael Mehl ([scheidhr|mehl](at)dfki(dot)uni-sb(dot)de)
;; More ideas and code have been taken from the SICStus debugger mode
;; ( -- broken link
;; as of Mon May 5 08:23:48 EDT 2003) by Per Mildner.
;; Additions for ECLiPSe and other helpful suggestions: Stephan Heuel
;; <heuel(at)ipb(dot)uni-bonn(dot)de>
;;; Commentary:
;; This package provides a major mode for editing Prolog code, with
;; all the bells and whistles one would expect, including syntax
;; highlighting and auto indentation. It can also send regions to an
;; inferior Prolog process.
;; The code requires the comint, easymenu, info, imenu, and font-lock
;; libraries. These are normally distributed with GNU Emacs and
;; XEmacs.
;;; Installation:
;; Insert the following lines in your init file--typically ~/.emacs
;; (GNU Emacs and XEmacs <21.4), or ~/.xemacs/init.el (XEmacs
;; 21.4)--to use this mode when editing Prolog files under Emacs:
;; (setq load-path (cons "/usr/lib/xemacs/site-lisp" load-path))
;; (autoload 'run-prolog "prolog" "Start a Prolog sub-process." t)
;; (autoload 'prolog-mode "prolog" "Major mode for editing Prolog programs." t)
;; (autoload 'mercury-mode "prolog" "Major mode for editing Mercury programs." t)
;; (setq prolog-system 'swi) ; optional, the system you are using;
;; ; see `prolog-system' below for possible values
;; (setq auto-mode-alist (append '(("\\.pl$" . prolog-mode)
;; ("\\.m$" . mercury-mode))
;; auto-mode-alist))
;; where the path in the first line is the file system path to this file.
;; MSDOS paths can be written like "d:/programs/emacs-19.34/site-lisp".
;; Note: In XEmacs, either `/usr/lib/xemacs/site-lisp' (RPM default in
;; Red Hat-based distributions) or `/usr/local/lib/xemacs/site-lisp'
;; (default when compiling from sources) are automatically added to
;; `load-path', so the first line is not necessary provided that you
;; put this file in the appropriate place.
;; The last s-expression above makes sure that files ending with .pl
;; are assumed to be Prolog files and not Perl, which is the default
;; Emacs setting. If this is not wanted, remove this line. It is then
;; necessary to either
;; o insert in your Prolog files the following comment as the first line:
;; % -*- Mode: Prolog -*-
;; and then the file will be open in Prolog mode no matter its
;; extension, or
;; o manually switch to prolog mode after opening a Prolog file, by typing
;; M-x prolog-mode.
;; If the command to start the prolog process ('sicstus', 'pl' or
;; 'swipl' for SWI prolog, etc.) is not available in the default path,
;; then it is necessary to set the value of the environment variable
;; EPROLOG to a shell command to invoke the prolog process. In XEmacs
;; and Emacs 20+ you can also customize the variable
;; `prolog-program-name' (in the group `prolog-inferior') and provide
;; a full path for your Prolog system (swi, scitus, etc.).
;; Note: I (Stefan, the current maintainer) work under XEmacs. Future
;; developments will thus be biased towards XEmacs (OK, I admit it,
;; I am biased towards XEmacs in general), though I will do my best
;; to keep the GNU Emacs compatibility. So if you work under Emacs
;; and see something that does not work do drop me a line, as I have
;; a smaller chance to notice this kind of bugs otherwise.
;; This package provides a major mode for editing Prolog. It knows
;; about Prolog syntax and comments, and can send regions to an inferior
;; Prolog interpreter process. Font locking is tuned towards GNU Prolog.
;; Changelog:
;; Version 1.22:
;; o Allowed both 'swipl' and 'pl' as names for the SWI Prolog
;; interpreter.
;; o Atoms that start a line are not blindly coloured as
;; predicates. Instead we check that they are followed by ( or
;; :- first. Patch suggested by Guy Wiener.
;; Version 1.21:
;; o Cleaned up the code that defines faces. The missing face
;; warnings on some Emacsen should disappear.
;; Version 1.20:
;; o Improved the handling of clause start detection and multi-line
;; comments: `prolog-clause-start' no longer finds non-predicate
;; (e.g., capitalized strings) beginning of clauses.
;; `prolog-tokenize' recognizes when the end point is within a
;; multi-line comment.
;; Version 1.19:
;; o Minimal changes for Aquamacs inclusion and in general for
;; better coping with finding the Prolog executable. Patch
;; provided by David Reitter
;; Version 1.18:
;; o Fixed syntax highlighting for clause heads that do not begin at
;; the beginning of the line.
;; o Fixed compilation warnings under Emacs.
;; o Updated the email address of the current maintainer.
;; Version 1.17:
;; o Minor indentation fix (patch by Markus Triska)
;; o `prolog-underscore-wordchar-flag' defaults now to nil (more
;; consistent to other Emacs modes)
;; Version 1.16:
;; o Eliminated a possible compilation warning.
;; Version 1.15:
;; o Introduced three new customizable variables: electric colon
;; (`prolog-electric-colon-flag', default nil), electric dash
;; (`prolog-electric-dash-flag', default nil), and a possibility
;; to prevent the predicate template insertion from adding commata
;; (`prolog-electric-dot-full-predicate-template', defaults to t
;; since it seems quicker to me to just type those commata). A
;; trivial adaptation of a patch by Markus Triska.
;; o Improved the behaviour of electric if-then-else to only skip
;; forward if the parenthesis/semicolon is preceded by
;; whitespace. Once more a trivial adaptation of a patch by
;; Markus Triska.
;; Version 1.14:
;; o Cleaned up align code. `prolog-align-flag' is eliminated (since
;; on a second thought it does not do anything useful). Added key
;; binding (C-c C-a) and menu entry for alignment.
;; o Condensed regular expressions for lower and upper case
;; characters (GNU Emacs seems to go over the regexp length limit
;; with the original form). My code on the matter was improved
;; considerably by Markus Triska.
;; o Fixed `prolog-insert-spaces-after-paren' (which used an
;; unitialized variable).
;; o Minor changes to clean up the code and avoid some implicit
;; package requirements.
;; Version 1.13:
;; o Removed the use of `map-char-table' in `prolog-build-case-strings'
;; which appears to cause prblems in (at least) Emacs
;; o Added if-then-else indentation + corresponding electric
;; characters. New customization: `prolog-electric-if-then-else-flag'
;; o Align support (requires `align'). New customization:
;; `prolog-align-flag'.
;; o Temporary consult files have now the same name throughout the
;; session. This prevents issues with reconsulting a buffer
;; (this event is no longer passed to Prolog as a request to
;; consult a new file).
;; o Adaptive fill mode is now turned on. Comment indentation is
;; still worse than it could be though, I am working on it.
;; o Improved filling and auto-filling capabilities. Now block
;; comments should be [auto-]filled correctly most of the time;
;; the following pattern in particular is worth noting as being
;; filled correctly:
;; <some code here> % some comment here that goes beyond the
;; % rightmost column, possibly combined with
;; % subsequent comment lines
;; o `prolog-char-quote-workaround' now defaults to nil.
;; o Note: Many of the above improvements have been suggested by
;; Markus Triska, who also provided useful patches on the matter
;; when he realized that I was slow in responding. Many thanks.
;; Version 1.11 / 1.12
;; o GNU Emacs compatibility fix for paragraph filling (fixed
;; incorrectly in 1.11, fix fixed in 1.12).
;; Version 1.10
;; o Added paragraph filling in comment blocks and also correct auto
;; filling for comments.
;; o Fixed the possible "Regular expression too big" error in
;; `prolog-electric-dot'.
;; Version 1.9
;; o Parenthesis expressions are now indented by default so that
;; components go one underneath the other, just as for compound
;; terms. You can use the old style (the second and subsequent
;; lines being indented to the right in a parenthesis expression)
;; by setting the customizable variable `prolog-paren-indent-p'
;; (group "Prolog Indentation") to t.
;; o (Somehow awkward) handling of the 0' character escape
;; sequence. I am looking into a better way of doing it but
;; prospects look bleak. If this breaks things for you please let
;; me know and also set the `prolog-char-quote-workaround' (group
;; "Prolog Other") to nil.
;; Version 1.8
;; o Key binding fix.
;; Version 1.7
;; o Fixed a number of issues with the syntax of single quotes,
;; including Debian bug #324520.
;; Version 1.6
;; o Fixed mercury mode menu initialization (Debian bug #226121).
;; o Fixed (i.e., eliminated) Delete remapping (Debian bug #229636).
;; o Corrected indentation for clauses defining quoted atoms.
;; Version 1.5:
;; o Keywords fontifying should work in console mode so this is
;; enabled everywhere.
;; Version 1.4:
;; o Now supports GNU Prolog--minor adaptation of a patch by Stefan
;; Moeding.
;; Version 1.3:
;; o Info-follow-nearest-node now called correctly under Emacs too
;; (thanks to Nicolas Pelletier). Should be implemented more
;; elegantly (i.e., without compilation warnings) in the future.
;; Version 1.2:
;; o Another prompt fix, still in SWI mode (people seem to have
;; changed the prompt of SWI Prolog).
;; Version 1.1:
;; o Fixed dots in the end of line comments causing indentation
;; problems. The following code is now correctly indented (note
;; the dot terminating the comment):
;; a(X) :- b(X),
;; c(X). % comment here.
;; a(X).
;; and so is this (and variants):
;; a(X) :- b(X),
;; c(X). /* comment here. */
;; a(X).
;; Version 1.0:
;; o Revamped the menu system.
;; o Yet another prompt recognition fix (SWI mode).
;; o This is more of a renumbering than a new edition. I promoted
;; the mode to version 1.0 to emphasize the fact that it is now
;; mature and stable enough to be considered production (in my
;; opinion anyway).
;; Version 0.1.41:
;; o GNU Emacs compatibility fixes.
;; Version 0.1.40:
;; o prolog-get-predspec is now suitable to be called as
;; imenu-extract-index-name-function. The predicate index works.
;; o Since imenu works now as advertised, prolog-imenu-flag is t
;; by default.
;; o Eliminated prolog-create-predicate-index since the imenu
;; utilities now work well. Actually, this function is also
;; buggy, and I see no reason to fix it since we do not need it
;; anyway.
;; o Fixed prolog-pred-start, prolog-clause-start, prolog-clause-info.
;; o Fix for prolog-build-case-strings; now prolog-upper-case-string
;; and prolog-lower-case-string are correctly initialized,
;; o Various font-lock changes; most importantly, block comments (/*
;; ... */) are now correctly fontified in XEmacs even when they
;; extend on multiple lines.
;; Version 0.1.36:
;; o The debug prompt of SWI Prolog is now correctly recognized.
;; Version 0.1.35:
;; o Minor font-lock bug fixes.
;;; Code:
(defvar comint-prompt-regexp)
(defvar comint-process-echoes)
(require 'smie)
(require 'compile)
(require 'font-lock)
;; We need imenu everywhere because of the predicate index!
(require 'imenu)
(require 'info)
(require 'shell)
(require 'comint)
(require 'easymenu)
(require 'align)
(defgroup prolog nil
"Major mode for editing and running Prolog under Emacs."
:link '(custom-group-link :tag "Font Lock Faces group" font-lock-faces)
"Major modes for editing and running Prolog and Mercury files."
:group 'languages)
(defgroup prolog-faces nil
"Prolog mode specific faces."
:group 'font-lock)
(defcustom prolog-program-name
(let ((names '("prolog" "gprolog" "swipl")))
(while (and names
(not (executable-find (car names))))
(setq names (cdr names)))
(or (car names) "prolog"))
"Program name for invoking an inferior Prolog with `run-prolog'."
:type 'string
(defgroup prolog-indentation nil
"Prolog mode indentation configuration."
:group 'prolog)
(defcustom prolog-consult-string "reconsult(user).\n"
"(Re)Consult mode (for C-Prolog and Quintus Prolog). "
:type 'string
(defgroup prolog-font-lock nil
"Prolog mode font locking patterns."
:group 'prolog)
(defcustom prolog-compile-string "compile(user).\n"
"Compile mode (for Quintus Prolog)."
:type 'string
(defgroup prolog-keyboard nil
"Prolog mode keyboard flags."
:group 'prolog)
(defcustom prolog-eof-string "end_of_file.\n"
"String that represents end of file for Prolog.
When nil, send actual operating system end of file."
:type 'string
(defgroup prolog-inferior nil
"Inferior Prolog mode options."
:group 'prolog)
(defgroup prolog-other nil
"Other Prolog mode options."
:group 'prolog)
(defcustom prolog-indent-width 4
"Level of indentation in Prolog buffers."
:type 'integer
;; User configurable variables
;; General configuration
(defcustom prolog-system nil
"*Prolog interpreter/compiler used.
The value of this variable is nil or a symbol.
If it is a symbol, it determines default values of other configuration
variables with respect to properties of the specified Prolog
Currently recognized symbol values are:
eclipse - Eclipse Prolog
mercury - Mercury
sicstus - SICStus Prolog
swi - SWI Prolog
gnu - GNU Prolog"
:group 'prolog
:type '(choice (const :tag "SICStus" :value sicstus)
(const :tag "SWI Prolog" :value swi)
(const :tag "Default" :value nil)))
(make-variable-buffer-local 'prolog-system)
;; NB: This alist can not be processed in prolog-mode-variables to
;; create a prolog-system-version-i variable since it is needed
;; prior to the call to prolog-mode-variables.
(defcustom prolog-system-version
'((sicstus (3 . 6))
(swi (0 . 0))
(mercury (0 . 0))
(eclipse (3 . 7))
(gnu (0 . 0)))
"*Alist of Prolog system versions.
The version numbers are of the format (Major . Minor)."
:group 'prolog)
(defvar prolog-font-lock-keywords
0 font-lock-keyword-face)
1 font-lock-keyword-face)
(1 font-lock-function-name-face)
(3 font-lock-variable-name-face)))
"Font-lock keywords for Prolog mode.")
(defvar prolog-mode-syntax-table
;; Indentation
(defcustom prolog-indent-width tab-width
"*The indentation width used by the editing buffer."
:group 'prolog-indentation
:type 'integer)
(defcustom prolog-align-comments-flag t
"*Non-nil means automatically align comments when indenting."
:group 'prolog-indentation
:type 'boolean)
(defcustom prolog-indent-mline-comments-flag t
"*Non-nil means indent contents of /* */ comments.
Otherwise leave such lines as they are."
:group 'prolog-indentation
:type 'boolean)
(defcustom prolog-object-end-to-0-flag t
"*Non-nil means indent closing '}' in SICStus object definitions to level 0.
Otherwise indent to `prolog-indent-width'."
:group 'prolog-indentation
:type 'boolean)
(defcustom prolog-left-indent-regexp "\\(;\\|\\*?->\\)"
"*Regexp for character sequences after which next line is indented.
Next line after such a regexp is indented to the opening paranthesis level."
:group 'prolog-indentation
:type 'regexp)
(defcustom prolog-paren-indent-p nil
"*If non-nil, increase indentation for parenthesis expressions.
The second and subsequent line in a parenthesis expression other than
a compound term can either be indented `prolog-paren-indent' to the
right (if this variable is non-nil) or in the same way as for compound
terms (if this variable is nil, default)."
:group 'prolog-indentation
:type 'boolean)
(defcustom prolog-paren-indent 4
"*The indentation increase for parenthesis expressions.
Only used in ( If -> Then ; Else) and ( Disj1 ; Disj2 ) style expressions."
:group 'prolog-indentation
:type 'integer)
(defcustom prolog-parse-mode 'beg-of-clause
"*The parse mode used (decides from which point parsing is done).
Legal values:
'beg-of-line - starts parsing at the beginning of a line, unless the
previous line ends with a backslash. Fast, but has
problems detecting multiline /* */ comments.
'beg-of-clause - starts parsing at the beginning of the current clause.
Slow, but copes better with /* */ comments."
:group 'prolog-indentation
:type '(choice (const :value beg-of-line)
(const :value beg-of-clause)))
;; Font locking
(defcustom prolog-keywords
("use_module" "begin_module" "module_interface" "dynamic"
"external" "export" "dbgcomp" "nodbgcomp" "compile"))
("all" "else" "end_module" "equality" "external" "fail" "func" "if"
"implementation" "import_module" "include_module" "inst" "instance"
"interface" "mode" "module" "not" "pragma" "pred" "some" "then" "true"
"type" "typeclass" "use_module" "where"))
("block" "dynamic" "mode" "module" "multifile" "meta_predicate"
"parallel" "public" "sequential" "volatile"))
("discontiguous" "dynamic" "ensure_loaded" "export" "export_list" "import"
"meta_predicate" "module" "module_transparent" "multifile" "require"
"use_module" "volatile"))
("built_in" "char_conversion" "discontiguous" "dynamic" "ensure_linked"
"ensure_loaded" "foreign" "include" "initialization" "multifile" "op"
"public" "set_prolog_flag"))
("dynamic" "module")))
"*Alist of Prolog keywords which is used for font locking of directives."
:group 'prolog-font-lock
:type 'sexp)
(defcustom prolog-types
("char" "float" "int" "io__state" "string" "univ"))
(t nil))
"*Alist of Prolog types used by font locking."
:group 'prolog-font-lock
:type 'sexp)
(defcustom prolog-mode-specificators
("bound" "di" "free" "ground" "in" "mdi" "mui" "muo" "out" "ui" "uo"))
(t nil))
"*Alist of Prolog mode specificators used by font locking."
:group 'prolog-font-lock
:type 'sexp)
(defcustom prolog-determinism-specificators
("cc_multi" "cc_nondet" "det" "erroneous" "failure" "multi" "nondet"
(t nil))
"*Alist of Prolog determinism specificators used by font locking."
:group 'prolog-font-lock
:type 'sexp)
(defcustom prolog-directives
(t nil))
"*Alist of Prolog source code directives used by font locking."
:group 'prolog-font-lock
:type 'sexp)
;; Keyboard
(defcustom prolog-electric-newline-flag t
"*Non-nil means automatically indent the next line when the user types RET."
:group 'prolog-keyboard
:type 'boolean)
(defcustom prolog-hungry-delete-key-flag nil
"*Non-nil means delete key consumes all preceding spaces."
:group 'prolog-keyboard
:type 'boolean)
(defcustom prolog-electric-dot-flag nil
"*Non-nil means make dot key electric.
Electric dot appends newline or inserts head of a new clause.
If dot is pressed at the end of a line where at least one white space
precedes the point, it inserts a recursive call to the current predicate.
If dot is pressed at the beginning of an empty line, it inserts the head
of a new clause for the current predicate. It does not apply in strings
and comments.
It does not apply in strings and comments."
:group 'prolog-keyboard
:type 'boolean)
(defcustom prolog-electric-dot-full-predicate-template nil
"*If nil, electric dot inserts only the current predicate's name and `('
for recursive calls or new clause heads. Non-nil means to also
insert enough commata to cover the predicate's arity and `)',
and dot and newline for recursive calls."
:group 'prolog-keyboard
:type 'boolean)
(defcustom prolog-electric-underscore-flag nil
"*Non-nil means make underscore key electric.
Electric underscore replaces the current variable with underscore.
If underscore is pressed not on a variable then it behaves as usual."
:group 'prolog-keyboard
:type 'boolean)
(defcustom prolog-electric-tab-flag nil
"*Non-nil means make TAB key electric.
Electric TAB inserts spaces after parentheses, ->, and ;
in ( If -> Then ; Else) and ( Disj1 ; Disj2 ) style expressions."
:group 'prolog-keyboard
:type 'boolean)
(defcustom prolog-electric-if-then-else-flag nil
"*Non-nil makes `(', `>' and `;' electric
to automatically indent if-then-else constructs."
:group 'prolog-keyboard
:type 'boolean)
(defcustom prolog-electric-colon-flag nil
"*Makes `:' electric (inserts `:-' on a new line).
If non-nil, pressing `:' at the end of a line that starts in
the first column (i.e., clause heads) inserts ` :-' and newline."
:group 'prolog-keyboard
:type 'boolean)
(defcustom prolog-electric-dash-flag nil
"*Makes `-' electric (inserts a `-->' on a new line).
If non-nil, pressing `-' at the end of a line that starts in
the first column (i.e., DCG heads) inserts ` -->' and newline."
:group 'prolog-keyboard
:type 'boolean)
(defcustom prolog-old-sicstus-keys-flag nil
"*Non-nil means old SICStus Prolog mode keybindings are used."
:group 'prolog-keyboard
:type 'boolean)
;; Inferior mode
(defcustom prolog-program-name
`(((getenv "EPROLOG") (eval (getenv "EPROLOG")))
(eclipse "eclipse")
(mercury nil)
(sicstus "sicstus")
(swi ,(if (not (executable-find "swipl")) "pl" "swipl"))
(gnu "gprolog")
(t ,(let ((names '("prolog" "gprolog" "swipl" "pl")))
(while (and names
(not (executable-find (car names))))
(setq names (cdr names)))
(or (car names) "prolog"))))
"*Alist of program names for invoking an inferior Prolog with `run-prolog'."
:group 'prolog-inferior
:type 'sexp)
(defcustom prolog-program-switches
'((sicstus ("-i"))
(t nil))
"*Alist of switches given to inferior Prolog run with `run-prolog'."
:group 'prolog-inferior
:type 'sexp)
(defcustom prolog-consult-string
'((eclipse "[%f].")