;;; prolog-indent.el --- Indentation of Prolog code. ;;;**************************************************************************** ;;; $Id: prolog-indent.el,v 0.00 1995/02/24 15:28:23 gerd Exp $ ;;;**************************************************************************** ;;; ;;; Description: ;;; ;;; This file implements additional routines to the prolog mode ;;; supplied with Emacs. The indentation is improved and some ;;; electric keys are activated. ;;; ;;; Installation: ;;; Put the following lines in your .emacs file: ;;; ;;; (require 'prolog-indent) ;;; ;;; This assumes that the file prolog-indent.el can be found on ;;; the load-path: ;;; ;;; (require 'cl) ;;; (setq load-path (adjoin "PROLOG-INDENT-DIRECTORY" load-path)) ;;; ;;; Bugs and Problems: ;;; Comments inside Prolog goals are not supported. ;;; Things might get mixed up for infix operators. ;;; ;;; To do: ;;; ;;; Changes: ;;; ;;; Author: ;;; Gerd Neugebauer ;;; Mainzer Str. 16 ;;; 56321 Rhens (Germany) ;;; Net: gerd@uni-koblenz.de ;;; ;;;**************************************************************************** ;;; LCD Archive Entry: ;;; Not yet. ;;;**************************************************************************** ;;; ;;; Copyright (C) 1995,1996 Gerd Neugebauer ;;; ;;; prolog-indent.el is distributed in the hope that it will be useful, ;;; but WITHOUT ANY WARRANTY. No author or distributor ;;; accepts responsibility to anyone for the consequences of using it ;;; or for whether it serves any particular purpose or works at all, ;;; unless he says so in writing. Refer to the GNU General Public ;;; License for full details. ;;; ;;; Everyone is granted permission to copy, modify and redistribute ;;; prolog-indent.el, but only under the conditions described in the ;;; GNU General Public License. A copy of this license is ;;; supposed to have been given to you along with GNU Emacs so you ;;; can know your rights and responsibilities. It should be in a ;;; file named COPYING. Among other things, the copyright notice ;;; and this notice must be preserved on all copies. ;;; ;;;---------------------------------------------------------------------------- ;;; Load prolog.el if not already loaded. (eval-when-compile (load-library "prolog")) (if (null prolog-mode-map) (load-library "prolog")) (defvar Prolog-prefix-op-regex "\\\\\\+" "Regular expression of a Prolog prefix operator of length 2.") (defvar Prolog-infix1-op-regex "[^:/=]=\\|.[*+]\\|[^*]/\\|[^:]-\\|.^" "Regular expression of a Prolog infix operator") (defvar Prolog-infix2-op-regex "\\(==\\|=<\\|>=\\|<<\\|>>\\|is\\)" "Regular expression of a Prolog infix operator of length 2.") (defvar Prolog-infix3-op-regex "=[:\\\\]=\\|=\\.\\.\\|\\\\==" "Regular expression of a Prolog infix operator of length 3.") (defvar Prolog-ascii-escape-regex "0'." "Regular expression of a Prolog ASCII characters (length 3).") ;;;---------------------------------------------------------------------------- (defun backward-Prolog-goal (&optional fwd) "Move point backward to the beginning of a Prolog goal. This includes compound terms constructed with infix operators of low priority. Some of those operators are built into this routine: + - * / \\+ == =< >= << >> is =.. =:= =\\\\== \\\\=== Comments inside a Prolog goal are not considered! " (if fwd (forward-char fwd)) (Prolog-backward-to-noncomment (point-min)) (forward-char -1) (if (looking-at "!") ; the cut is a goal even if it is no sexp nil (forward-char 1) (backward-sexp 1)) (let ((beg (point))) (Prolog-backward-to-noncomment (point-min)) (or (bobp) (forward-char -1)) (or (bobp) (forward-char -1)) (cond ((looking-at Prolog-prefix-op-regex) ) ((looking-at Prolog-infix2-op-regex) (backward-Prolog-goal)) ((looking-at Prolog-infix1-op-regex) (backward-Prolog-goal 1)) ((looking-at Prolog-ascii-escape-regex) (backward-Prolog-goal)) ( (progn (or (bobp) (forward-char -1)) (looking-at Prolog-infix3-op-regex)) (backward-Prolog-goal)) ( t (goto-char beg)))) (or (bobp) (progn (forward-char -1) (cond ((looking-at "[a-z_A-Z0-9'](") (backward-Prolog-goal 1)) ( t (forward-char 1)))))) ;;;---------------------------------------------------------------------------- (defun Prolog-indent (&optional lines) "Indent current line as Prolog code. With argument, indent any additional lines along with this one." (interactive "p") (if (numberp lines) (let ((fwd (if (> lines 0) 1 -1))) (if (< lines 0) (setq lines (- 0 lines))) (while (> lines 1) (setq lines (- lines 1)) (Prolog-indent-line) (forward-line fwd)))) (Prolog-indent-line) ) ;;;---------------------------------------------------------------------------- (defun Prolog-indent-buffer () "Indent the whole buffer as Prolog code." (interactive) (save-excursion (goto-char (point-min)) (end-of-line) (while (not (eobp)) (Prolog-indent-line) (forward-line 1) (end-of-line) ))) ;;;---------------------------------------------------------------------------- (defun Prolog-in-comment-p () "Check whether point is inside a C-style comment." (let ((beg (if (bobp) (point) (save-excursion (beginning-of-line) (search-backward "/*" (point-min) 'move) (point)))) (pos (if (bobp) (point-max) (save-excursion (beginning-of-line) (search-backward "*/" (point-min) 'move) (point))))) (< pos beg))) ;;;---------------------------------------------------------------------------- (defun Prolog-indent-line () "Indent current line as Prolog code." (let (indent pos beg) (if (Prolog-in-comment-p) nil (setq indent (Prolog-indentation-level) pos (- (point-max) (point))) (beginning-of-line) (setq beg (point)) (skip-chars-forward " \t") (if (zerop (- indent (current-column))) nil (delete-region beg (point)) (indent-to indent)) (if (> (- (point-max) pos) (point)) (goto-char (- (point-max) pos))) ))) (defvar Prolog-colon-minus-indent tab-width "Indentation of :- if at the beginning of a line.") (defvar Prolog-body-indent tab-width "Indentation of the body after :- or --> at the end of a line.") (defvar Prolog-then-indent 2 "Indentation of literals after ->") ;;;---------------------------------------------------------------------------- (defun Prolog-indentation-level () "Compute the Prolog indentation level." (save-excursion (beginning-of-line) (skip-chars-forward " \t") (cond ((looking-at "%[^%]") comment-column) ;Small comment starts ((looking-at "%%%") 0) ;Large comment starts ((looking-at "/\\*") 0) ((looking-at "?-") 0) ((looking-at "\\([)}]\\|]\\)") ;Closing parenthesis (forward-char 1) ; is aligned at opening (backward-sexp) (current-column)) ((looking-at ";") (Prolog-backward-to-noncomment (point-min)) (backward-Prolog-goal) (max (- (current-column) prolog-indent-width) 0) ) ((looking-at ":-\\|-->") (Prolog-backward-to-noncomment (point-min)) (cond ((or (bobp) (= (preceding-char) ?.)) 0 ) ( t Prolog-colon-minus-indent))) ((looking-at "->") (Prolog-backward-to-noncomment (point-min)) (backward-Prolog-goal) (+ (current-column) prolog-indent-width)) ((bobp) 0) (t (Prolog-backward-to-noncomment (point-min)) (if (save-excursion (beginning-of-line 1) (skip-chars-forward " \t") (looking-at "%%[^%]")) (current-column) (let ((pos (point))) (skip-chars-backward " \t") (or (bobp) (forward-char -1)) (or (bobp) (forward-char -1)) ;Backward twice (cond ((looking-at ".;") (goto-char pos) (+ -1 (current-column) prolog-indent-width)) ((looking-at ".,") (backward-Prolog-goal 1) (current-column)) ((looking-at "->") (cond ((= (preceding-char) ?-) Prolog-body-indent ) ( t (backward-Prolog-goal) (+ (current-column) Prolog-then-indent)))) ((looking-at "[a-z_A-Z0-9'](") (forward-char 2) (current-column)) ((looking-at ".[({]") (forward-char 1) (+ (current-column) prolog-indent-width)) ((looking-at ":-") Prolog-body-indent) ((looking-at ".[^.]") (goto-char pos) (max (- (current-column) prolog-indent-width) 0)) (t 0 )) )))))) ;;;---------------------------------------------------------------------------- ;;; Taken from the prolog mode by Ken'ichi HANDA (handa@etl.go.jp) (defun Prolog-backward-to-noncomment (lim) (let (opoint stop) (while (not stop) (skip-chars-backward " \t\n\f" lim) (setq opoint (point)) (if (and (>= (point) (+ 2 lim)) (= (preceding-char) ?/) (= (char-after (- (point) 2)) ?*)) (search-backward "/*" lim 'mv) (let ((p (max lim (save-excursion (beginning-of-line) (point))))) (if (nth 4 (parse-partial-sexp p (point))) (search-backward "%" p 'mv) (goto-char opoint) (setq stop t))))))) (defvar Prolog-boc-regexp "^['a-z]") ;;;---------------------------------------------------------------------------- (defun Prolog-beginning-of-clause () "Return the position of the beginning of the clause or nil." (save-excursion (catch 'boc (while t (cond ((null (search-backward-regexp Prolog-boc-regexp (point-min) t)) (throw 'boc nil)) ((not (Prolog-in-comment-p)) (throw 'boc (point)))))))) (defvar Prolog-eoc-regexp "\\.[ \t\f]*$") ;;;---------------------------------------------------------------------------- (defun Prolog-end-of-clause () "Return the position of the beginning of the clause or nil." (save-excursion (catch 'boc (while t (cond ((null (search-forward-regexp Prolog-eoc-regexp (point-max) t)) (throw 'boc nil)) ((not (Prolog-in-comment-p)) (skip-chars-backward " \t\f\n") (throw 'boc (point)))))))) ;;;---------------------------------------------------------------------------- (defun Prolog-indent-region (beg end) (interactive "d\nm") (let (tmp) (if (null end) (message "Mark not set") (if (< end beg) (setq tmp end end beg beg tmp)) (save-excursion (setq end (- (point-max) end)) (goto-char beg) (Prolog-indent-line) (forward-line 1) (beginning-of-line) (while (> (- (point-max) (point)) end) (Prolog-indent-line) (forward-line 1) (beginning-of-line)))))) ;;;---------------------------------------------------------------------------- (defun Prolog-indent-clause () (interactive) (let ((beg (Prolog-beginning-of-clause)) (end (Prolog-end-of-clause))) (if (and beg end) (Prolog-indent-region beg end)))) ;;;---------------------------------------------------------------------------- (defun Prolog-fill-paragraph (&optional arg) (interactive) (if (Prolog-in-comment-p) (fill-paragraph arg) (Prolog-indent-clause))) (defvar Prolog-electric t "Variable indicating if the Prolog electric characters should be active.") ;;;---------------------------------------------------------------------------- ;;; Taken from the prolog mode by Ken'ichi HANDA (handa@etl.go.jp) ;;; Modified (defun Prolog-electic-char (arg) "Insert character and correct line's indentation." (interactive "P") (if (or arg (not Prolog-electric)) (self-insert-command (prefix-numeric-value arg)) (progn (self-insert-command (prefix-numeric-value arg)) (Prolog-indent-line)))) ;;;---------------------------------------------------------------------------- ;;; Activate some additional keys (define-key prolog-mode-map "(" 'Prolog-electic-char ) (define-key prolog-mode-map ")" 'Prolog-electic-char ) (define-key prolog-mode-map "{" 'Prolog-electic-char ) (define-key prolog-mode-map "}" 'Prolog-electic-char ) (define-key prolog-mode-map ";" 'Prolog-electic-char ) (define-key prolog-mode-map "-" 'Prolog-electic-char ) (define-key prolog-mode-map ">" 'Prolog-electic-char ) (define-key prolog-mode-map "\t" 'Prolog-indent ) (define-key prolog-mode-map "\M-q" 'Prolog-fill-paragraph ) ;;;---------------------------------------------------------------------------- (defun prolog-indent-line (&optional arg) (interactive "P") (Prolog-indent (prefix-numeric-value arg))) (provide 'prolog-indent)