]> code.delx.au - gnu-emacs/blobdiff - lisp/progmodes/prolog.el
Port run-prolog EMACS to SWI-Prolog 7.2.3
[gnu-emacs] / lisp / progmodes / prolog.el
index 2d95345b531182c56800de51618a012c6188aedc..212a5fa69abaa27ed641d16502b193aa466588a9 100644 (file)
@@ -1,6 +1,6 @@
 ;;; prolog.el --- major mode for Prolog (and Mercury) -*- lexical-binding:t -*-
 
 ;;; prolog.el --- major mode for Prolog (and Mercury) -*- lexical-binding:t -*-
 
-;; Copyright (C) 1986-1987, 1997-1999, 2002-2003, 2011-2015 Free
+;; Copyright (C) 1986-1987, 1997-1999, 2002-2003, 2011-2016 Free
 ;; Software Foundation, Inc.
 
 ;; Authors: Emil Åström <emil_astrom(at)hotmail(dot)com>
 ;; Software Foundation, Inc.
 
 ;; Authors: Emil Åström <emil_astrom(at)hotmail(dot)com>
 ;; all the bells and whistles one would expect, including syntax
 ;; highlighting and auto indentation.  It can also send regions to an
 ;; inferior Prolog process.
 ;; 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:
-;;
-;; (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)
+;; Some settings you may wish to use:
+
 ;; (setq prolog-system 'swi)  ; optional, the system you are using;
 ;;                            ; see `prolog-system' below for possible values
 ;; (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))
+;; (setq auto-mode-alist (append '(("\\.pl\\'" . prolog-mode)
+;;                                 ("\\.m\\'" . mercury-mode))
 ;;                                auto-mode-alist))
 ;;
 ;;                                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
+;; The last 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
 ;; 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
@@ -98,8 +80,8 @@
 ;; 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
 ;; 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
+;; EPROLOG to a shell command to invoke the prolog process.
+;; 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.).
 ;;
 ;; `prolog-program-name' (in the group `prolog-inferior') and provide
 ;; a full path for your Prolog system (swi, scitus, etc.).
 ;;
 ;;   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.
 ;;   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.
+;  [The above comment dates from 2011.]
 
 ;; Changelog:
 
 
 ;; Changelog:
 
 ;; Version 0.1.35:
 ;;  o  Minor font-lock bug fixes.
 
 ;; Version 0.1.35:
 ;;  o  Minor font-lock bug fixes.
 
-;;; TODO:
-
-;; Replace ":type 'sexp" with more precise Custom types.
 \f
 ;;; Code:
 
 \f
 ;;; Code:
 
@@ -367,6 +347,7 @@ The version numbers are of the format (Major . Minor)."
   :type '(repeat (list (symbol :tag "System")
                        (cons :tag "Version numbers" (integer :tag "Major")
                              (integer :tag "Minor"))))
   :type '(repeat (list (symbol :tag "System")
                        (cons :tag "Version numbers" (integer :tag "Major")
                              (integer :tag "Minor"))))
+  :risky t
   :group 'prolog)
 
 ;; Indentation
   :group 'prolog)
 
 ;; Indentation
@@ -402,11 +383,11 @@ Only used in ( If -> Then ; Else) and ( Disj1 ; Disj2 ) style expressions."
 (defcustom prolog-parse-mode 'beg-of-clause
   "The parse mode used (decides from which point parsing is done).
 Legal values:
 (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."
+`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."
   :version "24.1"
   :group 'prolog-indentation
   :type '(choice (const :value beg-of-line)
   :version "24.1"
   :group 'prolog-indentation
   :type '(choice (const :value beg-of-line)
@@ -440,7 +421,13 @@ Legal values:
   "Alist of Prolog keywords which is used for font locking of directives."
   :version "24.1"
   :group 'prolog-font-lock
   "Alist of Prolog keywords which is used for font locking of directives."
   :version "24.1"
   :group 'prolog-font-lock
-  :type 'sexp)
+  ;; Note that "(repeat string)" also allows "nil" (repeat-count 0).
+  ;; This gets processed by prolog-find-value-by-system, which
+  ;; allows both the car and the cdr to be a list to eval.
+  ;; Though the latter must have the form '(eval ...)'.
+  ;; Of course, none of this is documented...
+  :type '(repeat (list (choice symbol sexp) (choice (repeat string) sexp)))
+  :risky t)
 
 (defcustom prolog-types
   '((mercury
 
 (defcustom prolog-types
   '((mercury
@@ -449,7 +436,8 @@ Legal values:
   "Alist of Prolog types used by font locking."
   :version "24.1"
   :group 'prolog-font-lock
   "Alist of Prolog types used by font locking."
   :version "24.1"
   :group 'prolog-font-lock
-  :type 'sexp)
+  :type '(repeat (list (choice symbol sexp) (choice (repeat string) sexp)))
+  :risky t)
 
 (defcustom prolog-mode-specificators
   '((mercury
 
 (defcustom prolog-mode-specificators
   '((mercury
@@ -458,7 +446,8 @@ Legal values:
   "Alist of Prolog mode specificators used by font locking."
   :version "24.1"
   :group 'prolog-font-lock
   "Alist of Prolog mode specificators used by font locking."
   :version "24.1"
   :group 'prolog-font-lock
-  :type 'sexp)
+  :type '(repeat (list (choice symbol sexp) (choice (repeat string) sexp)))
+  :risky t)
 
 (defcustom prolog-determinism-specificators
   '((mercury
 
 (defcustom prolog-determinism-specificators
   '((mercury
@@ -468,7 +457,8 @@ Legal values:
   "Alist of Prolog determinism specificators used by font locking."
   :version "24.1"
   :group 'prolog-font-lock
   "Alist of Prolog determinism specificators used by font locking."
   :version "24.1"
   :group 'prolog-font-lock
-  :type 'sexp)
+  :type '(repeat (list (choice symbol sexp) (choice (repeat string) sexp)))
+  :risky t)
 
 (defcustom prolog-directives
   '((mercury
 
 (defcustom prolog-directives
   '((mercury
@@ -477,7 +467,8 @@ Legal values:
   "Alist of Prolog source code directives used by font locking."
   :version "24.1"
   :group 'prolog-font-lock
   "Alist of Prolog source code directives used by font locking."
   :version "24.1"
   :group 'prolog-font-lock
-  :type 'sexp)
+  :type '(repeat (list (choice symbol sexp) (choice (repeat string) sexp)))
+  :risky t)
 
 
 ;; Keyboard
 
 
 ;; Keyboard
@@ -563,7 +554,9 @@ the first column (i.e., DCG heads) inserts ` -->' and newline."
          (or (car names) "prolog"))))
   "Alist of program names for invoking an inferior Prolog with `run-prolog'."
   :group 'prolog-inferior
          (or (car names) "prolog"))))
   "Alist of program names for invoking an inferior Prolog with `run-prolog'."
   :group 'prolog-inferior
-  :type 'sexp)
+  :type '(alist :key-type (choice symbol sexp)
+                :value-type (group (choice string (const nil) sexp)))
+  :risky t)
 (defun prolog-program-name ()
   (prolog-find-value-by-system prolog-program-name))
 
 (defun prolog-program-name ()
   (prolog-find-value-by-system prolog-program-name))
 
@@ -573,7 +566,8 @@ the first column (i.e., DCG heads) inserts ` -->' and newline."
   "Alist of switches given to inferior Prolog run with `run-prolog'."
   :version "24.1"
   :group 'prolog-inferior
   "Alist of switches given to inferior Prolog run with `run-prolog'."
   :version "24.1"
   :group 'prolog-inferior
-  :type 'sexp)
+  :type '(repeat (list (choice symbol sexp) (choice (repeat string) sexp)))
+  :risky t)
 (defun prolog-program-switches ()
   (prolog-find-value-by-system prolog-program-switches))
 
 (defun prolog-program-switches ()
   (prolog-find-value-by-system prolog-program-switches))
 
@@ -596,7 +590,10 @@ Some parts of the string are replaced:
      region of a buffer, in which case it is the number of lines before
      the region."
   :group 'prolog-inferior
      region of a buffer, in which case it is the number of lines before
      the region."
   :group 'prolog-inferior
-  :type 'sexp)
+  :type '(alist :key-type (choice symbol sexp)
+                :value-type (group (choice string (const nil) sexp)))
+  :risky t)
+
 (defun prolog-consult-string ()
   (prolog-find-value-by-system prolog-consult-string))
 
 (defun prolog-consult-string ()
   (prolog-find-value-by-system prolog-consult-string))
 
@@ -621,15 +618,22 @@ Some parts of the string are replaced:
 If `prolog-program-name' is non-nil, it is a string sent to a Prolog process.
 If `prolog-program-name' is nil, it is an argument to the `compile' function."
   :group 'prolog-inferior
 If `prolog-program-name' is non-nil, it is a string sent to a Prolog process.
 If `prolog-program-name' is nil, it is an argument to the `compile' function."
   :group 'prolog-inferior
-  :type 'sexp)
+  :type '(alist :key-type (choice symbol sexp)
+                :value-type (group (choice string (const nil) sexp)))
+  :risky t)
+
 (defun prolog-compile-string ()
   (prolog-find-value-by-system prolog-compile-string))
 
 (defcustom prolog-eof-string "end_of_file.\n"
 (defun prolog-compile-string ()
   (prolog-find-value-by-system prolog-compile-string))
 
 (defcustom prolog-eof-string "end_of_file.\n"
-  "Alist of strings that represent end of file for prolog.
-nil means send actual operating system end of file."
+  "String or alist of strings that represent end of file for prolog.
+If nil, send actual operating system end of file."
   :group 'prolog-inferior
   :group 'prolog-inferior
-  :type 'sexp)
+  :type '(choice string
+                 (const nil)
+                 (alist :key-type (choice symbol sexp)
+                        :value-type (group (choice string (const nil) sexp))))
+  :risky t)
 
 (defcustom prolog-prompt-regexp
   '((eclipse "^[a-zA-Z0-9()]* *\\?- \\|^\\[[a-zA-Z]* [0-9]*\\]:")
 
 (defcustom prolog-prompt-regexp
   '((eclipse "^[a-zA-Z0-9()]* *\\?- \\|^\\[[a-zA-Z]* [0-9]*\\]:")
@@ -640,7 +644,10 @@ nil means send actual operating system end of file."
   "Alist of prompts of the prolog system command line."
   :version "24.1"
   :group 'prolog-inferior
   "Alist of prompts of the prolog system command line."
   :version "24.1"
   :group 'prolog-inferior
-  :type 'sexp)
+  :type '(alist :key-type (choice symbol sexp)
+                :value-type (group (choice string (const nil) sexp)))
+  :risky t)
+
 (defun prolog-prompt-regexp ()
   (prolog-find-value-by-system prolog-prompt-regexp))
 
 (defun prolog-prompt-regexp ()
   (prolog-find-value-by-system prolog-prompt-regexp))
 
@@ -649,7 +656,9 @@ nil means send actual operating system end of file."
 ;;     (t "^|: +"))
 ;;   "Alist of regexps matching the prompt when consulting `user'."
 ;;   :group 'prolog-inferior
 ;;     (t "^|: +"))
 ;;   "Alist of regexps matching the prompt when consulting `user'."
 ;;   :group 'prolog-inferior
-;;   :type 'sexp)
+;;   :type '(alist :key-type (choice symbol sexp)
+;;                :value-type (group (choice string (const nil) sexp)))
+;;   :risky t)
 
 (defcustom prolog-debug-on-string "debug.\n"
   "Predicate for enabling debug mode."
 
 (defcustom prolog-debug-on-string "debug.\n"
   "Predicate for enabling debug mode."
@@ -840,6 +849,8 @@ This is really kludgy, and unneeded (i.e. obsolete) in Emacs>=24."
 
 (require 'smie)
 
 
 (require 'smie)
 
+(defconst prolog-operator-chars "-\\\\#&*+./:<=>?@\\^`~")
+
 (defun prolog-smie-forward-token ()
   ;; FIXME: Add support for 0'<char>, if needed after adding it to
   ;; syntax-propertize-functions.
 (defun prolog-smie-forward-token ()
   ;; FIXME: Add support for 0'<char>, if needed after adding it to
   ;; syntax-propertize-functions.
@@ -848,7 +859,7 @@ This is really kludgy, and unneeded (i.e. obsolete) in Emacs>=24."
    (point)
    (progn (cond
            ((looking-at "[!;]") (forward-char 1))
    (point)
    (progn (cond
            ((looking-at "[!;]") (forward-char 1))
-           ((not (zerop (skip-chars-forward "#&*+-./:<=>?@\\^`~"))))
+           ((not (zerop (skip-chars-forward prolog-operator-chars))))
            ((not (zerop (skip-syntax-forward "w_'"))))
            ;; In case of non-ASCII punctuation.
            ((not (zerop (skip-syntax-forward ".")))))
            ((not (zerop (skip-syntax-forward "w_'"))))
            ;; In case of non-ASCII punctuation.
            ((not (zerop (skip-syntax-forward ".")))))
@@ -861,8 +872,8 @@ This is really kludgy, and unneeded (i.e. obsolete) in Emacs>=24."
   (buffer-substring-no-properties
    (point)
    (progn (cond
   (buffer-substring-no-properties
    (point)
    (progn (cond
-           ((memq (char-before) '(?! ?\;)) (forward-char -1))
-           ((not (zerop (skip-chars-backward "#&*+-./:<=>?@\\^`~"))))
+           ((memq (char-before) '(?! ?\; ?\,)) (forward-char -1))
+           ((not (zerop (skip-chars-backward prolog-operator-chars))))
            ((not (zerop (skip-syntax-backward "w_'"))))
            ;; In case of non-ASCII punctuation.
            ((not (zerop (skip-syntax-backward ".")))))
            ((not (zerop (skip-syntax-backward "w_'"))))
            ;; In case of non-ASCII punctuation.
            ((not (zerop (skip-syntax-backward ".")))))
@@ -875,12 +886,21 @@ This is really kludgy, and unneeded (i.e. obsolete) in Emacs>=24."
   ;; manual uses precedence levels in the opposite sense (higher
   ;; numbers bind less tightly) than SMIE, so we use negative numbers.
   '(("." -10000 -10000)
   ;; manual uses precedence levels in the opposite sense (higher
   ;; numbers bind less tightly) than SMIE, so we use negative numbers.
   '(("." -10000 -10000)
+    ("?-" nil -1200)
     (":-" -1200 -1200)
     ("-->" -1200 -1200)
     (":-" -1200 -1200)
     ("-->" -1200 -1200)
+    ("discontiguous" nil -1150)
+    ("dynamic" nil -1150)
+    ("meta_predicate" nil -1150)
+    ("module_transparent" nil -1150)
+    ("multifile" nil -1150)
+    ("public" nil -1150)
+    ("|" -1105 -1105)
     (";" -1100 -1100)
     (";" -1100 -1100)
+    ("*->" -1050 -1050)
     ("->" -1050 -1050)
     ("," -1000 -1000)
     ("->" -1050 -1050)
     ("," -1000 -1000)
-    ("\\+" -900 -900)
+    ("\\+" nil -900)
     ("=" -700 -700)
     ("\\=" -700 -700)
     ("=.." -700 -700)
     ("=" -700 -700)
     ("\\=" -700 -700)
     ("=.." -700 -700)
@@ -922,15 +942,71 @@ This is really kludgy, and unneeded (i.e. obsolete) in Emacs>=24."
 (defun prolog-smie-rules (kind token)
   (pcase (cons kind token)
     (`(:elem . basic) prolog-indent-width)
 (defun prolog-smie-rules (kind token)
   (pcase (cons kind token)
     (`(:elem . basic) prolog-indent-width)
+    ;; The list of arguments can never be on a separate line!
+    (`(:list-intro . ,_) t)
+    ;; When we don't know how to indent an empty line, assume the most
+    ;; likely token will be ";".
+    (`(:elem . empty-line-token) ";")
     (`(:after . ".") '(column . 0)) ;; To work around smie-closer-alist.
     ;; Allow indentation of if-then-else as:
     ;;    (   test
     (`(:after . ".") '(column . 0)) ;; To work around smie-closer-alist.
     ;; Allow indentation of if-then-else as:
     ;;    (   test
-    ;;     -> thenrule
-    ;;     ;  elserule
+    ;;    ->  thenrule
+    ;;      elserule
     ;;    )
     (`(:before . ,(or `"->" `";"))
     ;;    )
     (`(:before . ,(or `"->" `";"))
-     (and (smie-rule-bolp) (smie-rule-parent-p "(") (smie-rule-parent 1)))
-    (`(:after . ,(or `":-" `"->" `"-->")) prolog-indent-width)))
+     (and (smie-rule-bolp) (smie-rule-parent-p "(") (smie-rule-parent 0)))
+    (`(:after . ,(or `"->" `"*->"))
+     ;; We distinguish
+     ;;
+     ;;     (a ->
+     ;;          b;
+     ;;      c)
+     ;; and
+     ;;     (    a ->
+     ;;          b
+     ;;     ;    c)
+     ;;
+     ;; based on the space between the open paren and the "a".
+     (unless (and (smie-rule-parent-p "(" ";")
+                  (save-excursion
+                    (smie-indent-forward-token)
+                    (smie-backward-sexp 'halfsexp)
+                    (if (smie-rule-parent-p "(")
+                        (not (eq (char-before) ?\())
+                      (smie-indent-backward-token)
+                      (smie-rule-bolp))))
+       prolog-indent-width))
+    (`(:after . ";")
+     ;; Align with same-line comment as in:
+     ;;   ;   %% Toto
+     ;;       foo
+     (and (smie-rule-bolp)
+          (looking-at ";[ \t]*\\(%\\)")
+          (let ((offset (- (save-excursion (goto-char (match-beginning 1))
+                                           (current-column))
+                           (current-column))))
+            ;; Only do it for small offsets, since the comment may actually be
+            ;; an "end-of-line" comment at comment-column!
+            (if (<= offset prolog-indent-width) offset))))
+    (`(:after . ",")
+     ;; Special indent for:
+     ;;    foopredicate(x) :- !,
+     ;;        toto.
+     (and (eq (char-before) ?!)
+          (save-excursion
+            (smie-indent-backward-token) ;Skip !
+            (equal ":-" (car (smie-indent-backward-token))))
+          (smie-rule-parent prolog-indent-width)))
+    (`(:after . ":-")
+     (if (bolp)
+         (save-excursion
+           (smie-indent-forward-token)
+           (skip-chars-forward " \t")
+           (if (eolp)
+               prolog-indent-width
+             (min prolog-indent-width (current-column))))
+       prolog-indent-width))
+    (`(:after . "-->") prolog-indent-width)))
 
 \f
 ;;-------------------------------------------------------------------
 
 \f
 ;;-------------------------------------------------------------------
@@ -953,6 +1029,8 @@ VERSION is of the format (Major . Minor)"
 
 (define-abbrev-table 'prolog-mode-abbrev-table ())
 
 
 (define-abbrev-table 'prolog-mode-abbrev-table ())
 
+;; Because this can `eval' its arguments, any variable that gets
+;; processed by it should be marked as :risky.
 (defun prolog-find-value-by-system (alist)
   "Get value from ALIST according to `prolog-system'."
   (let ((system (or prolog-system
 (defun prolog-find-value-by-system (alist)
   "Get value from ALIST according to `prolog-system'."
   (let ((system (or prolog-system
@@ -1005,7 +1083,7 @@ VERSION is of the format (Major . Minor)"
   (setq-local comment-start "%")
   (setq-local comment-end "")
   (setq-local comment-add 1)
   (setq-local comment-start "%")
   (setq-local comment-end "")
   (setq-local comment-add 1)
-  (setq-local comment-start-skip "\\(?:/\\*+ *\\|%%+ *\\)")
+  (setq-local comment-start-skip "\\(?:/\\*+ *\\|%+ *\\)")
   (setq-local parens-require-spaces nil)
   ;; Initialize Prolog system specific variables
   (dolist (var '(prolog-keywords prolog-types prolog-mode-specificators
   (setq-local parens-require-spaces nil)
   ;; Initialize Prolog system specific variables
   (dolist (var '(prolog-keywords prolog-types prolog-mode-specificators
@@ -1121,6 +1199,9 @@ Commands:
   (dolist (ar prolog-align-rules) (add-to-list 'align-rules-list ar))
   (add-hook 'post-self-insert-hook #'prolog-post-self-insert nil t)
   ;; `imenu' entry moved to the appropriate hook for consistency.
   (dolist (ar prolog-align-rules) (add-to-list 'align-rules-list ar))
   (add-hook 'post-self-insert-hook #'prolog-post-self-insert nil t)
   ;; `imenu' entry moved to the appropriate hook for consistency.
+  (when prolog-electric-dot-flag
+    (setq-local electric-indent-chars
+                (cons ?\. electric-indent-chars)))
 
   ;; Load SICStus debugger if suitable
   (if (and (eq prolog-system 'sicstus)
 
   ;; Load SICStus debugger if suitable
   (if (and (eq prolog-system 'sicstus)
@@ -1209,7 +1290,7 @@ using the commands `send-region', `send-string' and \\[prolog-consult-region].
 Commands:
 Tab indents for Prolog; with argument, shifts rest
  of expression rigidly with the current line.
 Commands:
 Tab indents for Prolog; with argument, shifts rest
  of expression rigidly with the current line.
-Paragraphs are separated only by blank lines and '%%'. '%'s start comments.
+Paragraphs are separated only by blank lines and `%%'. `%'s start comments.
 
 Return at end of buffer sends line as input.
 Return not at end copies rest of line to end and sends it.
 
 Return at end of buffer sends line as input.
 Return not at end copies rest of line to end and sends it.
@@ -1293,8 +1374,20 @@ the variable `prolog-prompt-regexp'."
       ()
     (with-current-buffer (get-buffer-create "*prolog*")
       (prolog-inferior-mode)
       ()
     (with-current-buffer (get-buffer-create "*prolog*")
       (prolog-inferior-mode)
-      (apply 'make-comint-in-buffer "prolog" (current-buffer)
-             (prolog-program-name) nil (prolog-program-switches))
+
+      ;; The "INFERIOR=yes" hack is for SWI-Prolog 7.2.3 and earlier,
+      ;; which assumes it is running under Emacs if either INFERIOR=yes or
+      ;; if EMACS is set to a nonempty value.  The EMACS setting is
+      ;; obsolescent, so set INFERIOR.  Newer versions of SWI-Prolog should
+      ;; know about INSIDE_EMACS (which replaced EMACS) and should not need
+      ;; this hack.
+      (let ((process-environment
+            (if (getenv "INFERIOR")
+                process-environment
+              (cons "INFERIOR=yes" process-environment))))
+       (apply 'make-comint-in-buffer "prolog" (current-buffer)
+              (prolog-program-name) nil (prolog-program-switches)))
+
       (unless prolog-system
         ;; Setup auto-detection.
         (setq-local
       (unless prolog-system
         ;; Setup auto-detection.
         (setq-local
@@ -2060,7 +2153,7 @@ Argument BOUND is a buffer position limiting searching."
 (defun prolog-find-unmatched-paren ()
   "Return the column of the last unmatched left parenthesis."
   (save-excursion
 (defun prolog-find-unmatched-paren ()
   "Return the column of the last unmatched left parenthesis."
   (save-excursion
-    (goto-char (or (car (nth 9 (syntax-ppss))) (point-min)))
+    (goto-char (or (nth 1 (syntax-ppss)) (point-min)))
     (current-column)))
 
 
     (current-column)))
 
 
@@ -2078,6 +2171,7 @@ whitespace characters, parentheses, or then/else branches."
   (when prolog-electric-if-then-else-flag
     (save-excursion
       (let ((regexp (concat "(\\|" prolog-left-indent-regexp))
   (when prolog-electric-if-then-else-flag
     (save-excursion
       (let ((regexp (concat "(\\|" prolog-left-indent-regexp))
+            (pos (point))
             level)
         (beginning-of-line)
         (skip-chars-forward " \t")
             level)
         (beginning-of-line)
         (skip-chars-forward " \t")
@@ -2087,6 +2181,9 @@ whitespace characters, parentheses, or then/else branches."
         ;;             prolog-paren-indent))
 
         ;; work on all subsequent "->", "(", ";"
         ;;             prolog-paren-indent))
 
         ;; work on all subsequent "->", "(", ";"
+        (and (looking-at regexp)
+             (= pos (match-end 0))
+             (indent-according-to-mode))
         (while (looking-at regexp)
           (goto-char (match-end 0))
           (setq level (+ (prolog-find-unmatched-paren) prolog-paren-indent))
         (while (looking-at regexp)
           (goto-char (match-end 0))
           (setq level (+ (prolog-find-unmatched-paren) prolog-paren-indent))
@@ -2267,6 +2364,7 @@ In effect it sets the `fill-prefix' when inside comments and then calls
     (swi prolog-help-online)
     (t prolog-help-online))
   "Alist for the name of the function for finding help on a predicate.")
     (swi prolog-help-online)
     (t prolog-help-online))
   "Alist for the name of the function for finding help on a predicate.")
+(put 'prolog-help-function 'risky-local-variable t)
 
 (defun prolog-help-on-predicate ()
   "Invoke online help on the atom under cursor."
 
 (defun prolog-help-on-predicate ()
   "Invoke online help on the atom under cursor."
@@ -2305,7 +2403,7 @@ In effect it sets the `fill-prefix' when inside comments and then calls
     (pop-to-buffer nil)
     (Info-goto-node prolog-info-predicate-index)
     (if (not (re-search-forward str nil t))
     (pop-to-buffer nil)
     (Info-goto-node prolog-info-predicate-index)
     (if (not (re-search-forward str nil t))
-        (error (format "Help on predicate `%s' not found." predicate)))
+        (error "Help on predicate `%s' not found." predicate))
 
     (setq oldp (point))
     (if (re-search-forward str nil t)
 
     (setq oldp (point))
     (if (re-search-forward str nil t)
@@ -2357,7 +2455,7 @@ This function is only available when `prolog-system' is set to `swi'."
 (defun prolog-atom-under-point ()
   "Return the atom under or left to the point."
   (save-excursion
 (defun prolog-atom-under-point ()
   "Return the atom under or left to the point."
   (save-excursion
-    (let ((nonatom_chars "[](){},\. \t\n")
+    (let ((nonatom_chars "[](){},. \t\n")
           start)
       (skip-chars-forward (concat "^" nonatom_chars))
       (skip-chars-backward nonatom_chars)
           start)
       (skip-chars-forward (concat "^" nonatom_chars))
       (skip-chars-backward nonatom_chars)
@@ -2524,6 +2622,8 @@ and end of list building."
   (goto-char (point-max))
 )
 
   (goto-char (point-max))
 )
 
+(declare-function pltrace-on "ext:pltrace" ())
+
 (defun prolog-enable-sicstus-sd ()
   "Enable the source level debugging facilities of SICStus 3.7 and later."
   (interactive)
 (defun prolog-enable-sicstus-sd ()
   "Enable the source level debugging facilities of SICStus 3.7 and later."
   (interactive)
@@ -2534,21 +2634,22 @@ and end of list building."
       (progn
         ;; If there is a *prolog* buffer, then call pltrace-on
         (if (get-buffer "*prolog*")
       (progn
         ;; If there is a *prolog* buffer, then call pltrace-on
         (if (get-buffer "*prolog*")
-            ;; Avoid compilation warnings by using eval
-            (eval '(pltrace-on)))
+            (pltrace-on))
         (setq prolog-use-sicstus-sd t)
         )))
 
         (setq prolog-use-sicstus-sd t)
         )))
 
+(declare-function pltrace-off "ext:pltrace" (&optional remove-process-filter))
+
 (defun prolog-disable-sicstus-sd ()
   "Disable the source level debugging facilities of SICStus 3.7 and later."
   (interactive)
 (defun prolog-disable-sicstus-sd ()
   "Disable the source level debugging facilities of SICStus 3.7 and later."
   (interactive)
+  (require 'pltrace)
   (setq prolog-use-sicstus-sd nil)
   ;; Remove the hook
   (remove-hook 'prolog-inferior-mode-hook 'pltrace-on)
   ;; If there is a *prolog* buffer, then call pltrace-off
   (if (get-buffer "*prolog*")
   (setq prolog-use-sicstus-sd nil)
   ;; Remove the hook
   (remove-hook 'prolog-inferior-mode-hook 'pltrace-on)
   ;; If there is a *prolog* buffer, then call pltrace-off
   (if (get-buffer "*prolog*")
-      ;; Avoid compile warnings by using eval
-      (eval '(pltrace-off))))
+      (pltrace-off)))
 
 (defun prolog-toggle-sicstus-sd ()
   ;; FIXME: Use define-minor-mode.
 
 (defun prolog-toggle-sicstus-sd ()
   ;; FIXME: Use define-minor-mode.
@@ -2826,10 +2927,10 @@ objects (relevant only if `prolog-system' is set to `sicstus')."
                   (eq prolog-system 'sicstus)
                   (prolog-in-object))
              (format
                   (eq prolog-system 'sicstus)
                   (prolog-in-object))
              (format
-              "^\\(%s\\|%s\\|[^\n\'\"%%]\\)*&[ \t]*\\(\\|%%.*\\)$\\|[ \t]*}"
+              "^\\(%s\\|%s\\|[^\n'\"%%]\\)*&[ \t]*\\(\\|%%.*\\)$\\|[ \t]*}"
               prolog-quoted-atom-regexp prolog-string-regexp)
            (format
               prolog-quoted-atom-regexp prolog-string-regexp)
            (format
-            "^\\(%s\\|%s\\|[^\n\'\"%%]\\)*\\.[ \t]*\\(\\|%%.*\\)$"
+            "^\\(%s\\|%s\\|[^\n'\"%%]\\)*\\.[ \t]*\\(\\|%%.*\\)$"
             prolog-quoted-atom-regexp prolog-string-regexp))
          nil t)
         (if (and (nth 8 (syntax-ppss))
             prolog-quoted-atom-regexp prolog-string-regexp))
          nil t)
         (if (and (nth 8 (syntax-ppss))
@@ -2975,7 +3076,7 @@ Return the final point or nil if no such a beginning was found."
   (let* ((pinfo (prolog-clause-info))
          (predname (nth 0 pinfo))
          (arity (nth 1 pinfo)))
   (let* ((pinfo (prolog-clause-info))
          (predname (nth 0 pinfo))
          (arity (nth 1 pinfo)))
-    (message (format "%s/%d" predname arity))))
+    (message "%s/%d" predname arity)))
 
 (defun prolog-insert-predicate-template ()
   "Insert the template for the current clause."
 
 (defun prolog-insert-predicate-template ()
   "Insert the template for the current clause."