1;;; prolog.el --- major mode for editing and running Prolog under Emacs 2 3;; Copyright (C) 1986, 1987, 2001, 2002, 2003, 2004, 2005, 2006, 2007 4;; Free Software Foundation, Inc. 5 6;; Author: Masanobu UMEDA <umerin@mse.kyutech.ac.jp> 7;; Keywords: languages 8 9;; This file is part of GNU Emacs. 10 11;; GNU Emacs is free software; you can redistribute it and/or modify 12;; it under the terms of the GNU General Public License as published by 13;; the Free Software Foundation; either version 2, or (at your option) 14;; any later version. 15 16;; GNU Emacs is distributed in the hope that it will be useful, 17;; but WITHOUT ANY WARRANTY; without even the implied warranty of 18;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19;; GNU General Public License for more details. 20 21;; You should have received a copy of the GNU General Public License 22;; along with GNU Emacs; see the file COPYING. If not, write to the 23;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 24;; Boston, MA 02110-1301, USA. 25 26;;; Commentary: 27 28;; This package provides a major mode for editing Prolog. It knows 29;; about Prolog syntax and comments, and can send regions to an inferior 30;; Prolog interpreter process. Font locking is tuned towards GNU Prolog. 31 32;;; Code: 33 34(defvar comint-prompt-regexp) 35 36 37(defgroup prolog nil 38 "Major mode for editing and running Prolog under Emacs." 39 :link '(custom-group-link :tag "Font Lock Faces group" font-lock-faces) 40 :group 'languages) 41 42 43(defcustom prolog-program-name 44 (let ((names '("prolog" "gprolog" "swipl"))) 45 (while (and names 46 (not (executable-find (car names)))) 47 (setq names (cdr names))) 48 (or (car names) "prolog")) 49 "Program name for invoking an inferior Prolog with `run-prolog'." 50 :type 'string 51 :group 'prolog) 52 53(defcustom prolog-consult-string "reconsult(user).\n" 54 "(Re)Consult mode (for C-Prolog and Quintus Prolog). " 55 :type 'string 56 :group 'prolog) 57 58(defcustom prolog-compile-string "compile(user).\n" 59 "Compile mode (for Quintus Prolog)." 60 :type 'string 61 :group 'prolog) 62 63(defcustom prolog-eof-string "end_of_file.\n" 64 "String that represents end of file for Prolog. 65When nil, send actual operating system end of file." 66 :type 'string 67 :group 'prolog) 68 69(defcustom prolog-indent-width 4 70 "Level of indentation in Prolog buffers." 71 :type 'integer 72 :group 'prolog) 73 74(defvar prolog-font-lock-keywords 75 '(("\\(#[<=]=>\\|:-\\)\\|\\(#=\\)\\|\\(#[#<>\\/][=\\/]*\\|!\\)" 76 0 font-lock-keyword-face) 77 ("\\<\\(is\\|write\\|nl\\|read_\\sw+\\)\\>" 78 1 font-lock-keyword-face) 79 ("^\\(\\sw+\\)\\s-*\\((\\(.+\\))\\)*" 80 (1 font-lock-function-name-face) 81 (3 font-lock-variable-name-face))) 82 "Font-lock keywords for Prolog mode.") 83 84(defvar prolog-mode-syntax-table 85 (let ((table (make-syntax-table))) 86 (modify-syntax-entry ?_ "w" table) 87 (modify-syntax-entry ?\\ "\\" table) 88 (modify-syntax-entry ?/ ". 14" table) 89 (modify-syntax-entry ?* ". 23" table) 90 (modify-syntax-entry ?+ "." table) 91 (modify-syntax-entry ?- "." table) 92 (modify-syntax-entry ?= "." table) 93 (modify-syntax-entry ?% "<" table) 94 (modify-syntax-entry ?\n ">" table) 95 (modify-syntax-entry ?< "." table) 96 (modify-syntax-entry ?> "." table) 97 (modify-syntax-entry ?\' "\"" table) 98 table)) 99 100(defvar prolog-mode-abbrev-table nil) 101(define-abbrev-table 'prolog-mode-abbrev-table ()) 102 103(defun prolog-mode-variables () 104 (make-local-variable 'paragraph-separate) 105 (setq paragraph-separate (concat "%%\\|$\\|" page-delimiter)) ;'%%..' 106 (make-local-variable 'paragraph-ignore-fill-prefix) 107 (setq paragraph-ignore-fill-prefix t) 108 (make-local-variable 'imenu-generic-expression) 109 (setq imenu-generic-expression '((nil "^\\sw+" 0))) 110 (make-local-variable 'indent-line-function) 111 (setq indent-line-function 'prolog-indent-line) 112 (make-local-variable 'comment-start) 113 (setq comment-start "%") 114 (make-local-variable 'comment-start-skip) 115 (setq comment-start-skip "\\(?:%+\\|/\\*+\\)[ \t]*") 116 (make-local-variable 'comment-end-skip) 117 (setq comment-end-skip "[ \t]*\\(\n\\|\\*+/\\)") 118 (make-local-variable 'comment-column) 119 (setq comment-column 48)) 120 121(defvar prolog-mode-map 122 (let ((map (make-sparse-keymap))) 123 (define-key map "\e\C-x" 'prolog-consult-region) 124 (define-key map "\C-c\C-l" 'inferior-prolog-load-file) 125 (define-key map "\C-c\C-z" 'switch-to-prolog) 126 map)) 127 128(easy-menu-define prolog-mode-menu prolog-mode-map "Menu for Prolog mode." 129 ;; Mostly copied from scheme-mode's menu. 130 ;; Not tremendously useful, but it's a start. 131 '("Prolog" 132 ["Indent line" indent-according-to-mode t] 133 ["Indent region" indent-region t] 134 ["Comment region" comment-region t] 135 ["Uncomment region" uncomment-region t] 136 "--" 137 ["Run interactive Prolog session" run-prolog t] 138 )) 139 140;;;###autoload 141(defun prolog-mode () 142 "Major mode for editing Prolog code for Prologs. 143Blank lines and `%%...' separate paragraphs. `%'s start comments. 144Commands: 145\\{prolog-mode-map} 146Entry to this mode calls the value of `prolog-mode-hook' 147if that value is non-nil." 148 (interactive) 149 (kill-all-local-variables) 150 (use-local-map prolog-mode-map) 151 (set-syntax-table prolog-mode-syntax-table) 152 (setq major-mode 'prolog-mode) 153 (setq mode-name "Prolog") 154 (prolog-mode-variables) 155 (set (make-local-variable 'comment-add) 1) 156 ;; font lock 157 (setq font-lock-defaults '(prolog-font-lock-keywords 158 nil nil nil 159 beginning-of-line)) 160 (run-mode-hooks 'prolog-mode-hook)) 161 162(defun prolog-indent-line () 163 "Indent current line as Prolog code. 164With argument, indent any additional lines of the same clause 165rigidly along with this one (not yet)." 166 (interactive "p") 167 (let ((indent (prolog-indent-level)) 168 (pos (- (point-max) (point)))) 169 (beginning-of-line) 170 (indent-line-to indent) 171 (if (> (- (point-max) pos) (point)) 172 (goto-char (- (point-max) pos))))) 173 174(defun prolog-indent-level () 175 "Compute Prolog indentation level." 176 (save-excursion 177 (beginning-of-line) 178 (skip-chars-forward " \t") 179 (cond 180 ((looking-at "%%%") 0) ;Large comment starts 181 ((looking-at "%[^%]") comment-column) ;Small comment starts 182 ((bobp) 0) ;Beginning of buffer 183 (t 184 (let ((empty t) ind more less) 185 (if (looking-at ")") 186 (setq less t) ;Find close 187 (setq less nil)) 188 ;; See previous indentation 189 (while empty 190 (forward-line -1) 191 (beginning-of-line) 192 (if (bobp) 193 (setq empty nil) 194 (skip-chars-forward " \t") 195 (if (not (or (looking-at "%[^%]") (looking-at "\n"))) 196 (setq empty nil)))) 197 (if (bobp) 198 (setq ind 0) ;Beginning of buffer 199 (setq ind (current-column))) ;Beginning of clause 200 ;; See its beginning 201 (if (looking-at "%%[^%]") 202 ind 203 ;; Real prolog code 204 (if (looking-at "(") 205 (setq more t) ;Find open 206 (setq more nil)) 207 ;; See its tail 208 (end-of-prolog-clause) 209 (or (bobp) (forward-char -1)) 210 (cond ((looking-at "[,(;>]") 211 (if (and more (looking-at "[^,]")) 212 (+ ind prolog-indent-width) ;More indentation 213 (max tab-width ind))) ;Same indentation 214 ((looking-at "-") tab-width) ;TAB 215 ((or less (looking-at "[^.]")) 216 (max (- ind prolog-indent-width) 0)) ;Less indentation 217 (t 0)) ;No indentation 218 ))) 219 ))) 220 221(defun end-of-prolog-clause () 222 "Go to end of clause in this line." 223 (beginning-of-line 1) 224 (let* ((eolpos (save-excursion (end-of-line) (point)))) 225 (if (re-search-forward comment-start-skip eolpos 'move) 226 (goto-char (match-beginning 0))) 227 (skip-chars-backward " \t"))) 228 229;;; 230;;; Inferior prolog mode 231;;; 232(defvar inferior-prolog-mode-map 233 (let ((map (make-sparse-keymap))) 234 ;; This map will inherit from `comint-mode-map' when entering 235 ;; inferior-prolog-mode. 236 (define-key map [remap self-insert-command] 237 'inferior-prolog-self-insert-command) 238 map)) 239 240(defvar inferior-prolog-mode-syntax-table prolog-mode-syntax-table) 241(defvar inferior-prolog-mode-abbrev-table prolog-mode-abbrev-table) 242 243(define-derived-mode inferior-prolog-mode comint-mode "Inferior Prolog" 244 "Major mode for interacting with an inferior Prolog process. 245 246The following commands are available: 247\\{inferior-prolog-mode-map} 248 249Entry to this mode calls the value of `prolog-mode-hook' with no arguments, 250if that value is non-nil. Likewise with the value of `comint-mode-hook'. 251`prolog-mode-hook' is called after `comint-mode-hook'. 252 253You can send text to the inferior Prolog from other buffers using the commands 254`process-send-region', `process-send-string' and \\[prolog-consult-region]. 255 256Commands: 257Tab indents for Prolog; with argument, shifts rest 258 of expression rigidly with the current line. 259Paragraphs are separated only by blank lines and '%%'. 260'%'s start comments. 261 262Return at end of buffer sends line as input. 263Return not at end copies rest of line to end and sends it. 264\\[comint-kill-input] and \\[backward-kill-word] are kill commands, imitating normal Unix input editing. 265\\[comint-interrupt-subjob] interrupts the shell or its current subjob if any. 266\\[comint-stop-subjob] stops. \\[comint-quit-subjob] sends quit signal." 267 (setq comint-prompt-regexp "^| [ ?][- ] *") 268 (prolog-mode-variables)) 269 270(defvar inferior-prolog-buffer nil) 271 272(defun inferior-prolog-run (&optional name) 273 (with-current-buffer (make-comint "prolog" (or name prolog-program-name)) 274 (inferior-prolog-mode) 275 (setq-default inferior-prolog-buffer (current-buffer)) 276 (make-local-variable 'inferior-prolog-buffer) 277 (when (and name (not (equal name prolog-program-name))) 278 (set (make-local-variable 'prolog-program-name) name)) 279 (set (make-local-variable 'inferior-prolog-flavor) 280 ;; Force re-detection. 281 (let* ((proc (get-buffer-process (current-buffer))) 282 (pmark (and proc (marker-position (process-mark proc))))) 283 (cond 284 ((null pmark) (1- (point-min))) 285 ;; The use of insert-before-markers in comint.el together with 286 ;; the potential use of comint-truncate-buffer in the output 287 ;; filter, means that it's difficult to reliably keep track of 288 ;; the buffer position where the process's output started. 289 ;; If possible we use a marker at "start - 1", so that 290 ;; insert-before-marker at `start' won't shift it. And if not, 291 ;; we fall back on using a plain integer. 292 ((> pmark (point-min)) (copy-marker (1- pmark))) 293 (t (1- pmark))))) 294 (add-hook 'comint-output-filter-functions 295 'inferior-prolog-guess-flavor nil t))) 296 297(defun inferior-prolog-process (&optional dontstart) 298 (or (and (buffer-live-p inferior-prolog-buffer) 299 (get-buffer-process inferior-prolog-buffer)) 300 (unless dontstart 301 (inferior-prolog-run) 302 ;; Try again. 303 (inferior-prolog-process)))) 304 305(defvar inferior-prolog-flavor 'unknown 306 "Either a symbol or a buffer position offset by one. 307If a buffer position, the flavor has not been determined yet and 308it is expected that the process's output has been or will 309be inserted at that position plus one.") 310 311(defun inferior-prolog-guess-flavor (&optional ignored) 312 (save-excursion 313 (goto-char (1+ inferior-prolog-flavor)) 314 (setq inferior-prolog-flavor 315 (cond 316 ((looking-at "GNU Prolog") 'gnu) 317 ((looking-at "Welcome to SWI-Prolog") 'swi) 318 ((looking-at ".*\n") 'unknown) ;There's at least one line. 319 (t inferior-prolog-flavor)))) 320 (when (symbolp inferior-prolog-flavor) 321 (remove-hook 'comint-output-filter-functions 322 'inferior-prolog-guess-flavor t) 323 (if (eq inferior-prolog-flavor 'gnu) 324 (set (make-local-variable 'comint-process-echoes) t)))) 325 326;;;###autoload 327(defalias 'run-prolog 'switch-to-prolog) 328;;;###autoload 329(defun switch-to-prolog (&optional name) 330 "Run an inferior Prolog process, input and output via buffer *prolog*. 331With prefix argument \\[universal-prefix], prompt for the program to use." 332 (interactive 333 (list (when current-prefix-arg 334 (let ((proc (inferior-prolog-process 'dontstart))) 335 (if proc 336 (if (yes-or-no-p "Kill current process before starting new one? ") 337 (kill-process proc) 338 (error "Abort"))) 339 (read-string "Run Prolog: " prolog-program-name))))) 340 (unless (inferior-prolog-process 'dontstart) 341 (inferior-prolog-run name)) 342 (pop-to-buffer inferior-prolog-buffer)) 343 344(defun inferior-prolog-self-insert-command () 345 "Insert the char in the buffer or pass it directly to the process." 346 (interactive) 347 (let* ((proc (get-buffer-process (current-buffer))) 348 (pmark (and proc (marker-position (process-mark proc))))) 349 (if (and (eq inferior-prolog-flavor 'gnu) 350 pmark 351 (null current-prefix-arg) 352 (eobp) 353 (eq (point) pmark) 354 (save-excursion 355 (goto-char (- pmark 3)) 356 (looking-at " \\? "))) 357 (comint-send-string proc (string last-command-char)) 358 (call-interactively 'self-insert-command)))) 359 360(defun prolog-consult-region (compile beg end) 361 "Send the region to the Prolog process made by \"M-x run-prolog\". 362If COMPILE (prefix arg) is not nil, use compile mode rather than consult mode." 363 (interactive "P\nr") 364 (let ((proc (inferior-prolog-process))) 365 (comint-send-string proc 366 (if compile prolog-compile-string 367 prolog-consult-string)) 368 (comint-send-region proc beg end) 369 (comint-send-string proc "\n") ;May be unnecessary 370 (if prolog-eof-string 371 (comint-send-string proc prolog-eof-string) 372 (with-current-buffer (process-buffer proc) 373 (comint-send-eof))))) ;Send eof to prolog process. 374 375(defun prolog-consult-region-and-go (compile beg end) 376 "Send the region to the inferior Prolog, and switch to *prolog* buffer. 377If COMPILE (prefix arg) is not nil, use compile mode rather than consult mode." 378 (interactive "P\nr") 379 (prolog-consult-region compile beg end) 380 (pop-to-buffer inferior-prolog-buffer)) 381 382(defun inferior-prolog-load-file () 383 "Pass the current buffer's file to the inferior prolog process." 384 (interactive) 385 (save-buffer) 386 (let ((file buffer-file-name) 387 (proc (inferior-prolog-process))) 388 (with-current-buffer (process-buffer proc) 389 (comint-send-string proc (concat "['" (file-relative-name file) "'].\n")) 390 (pop-to-buffer (current-buffer))))) 391 392(provide 'prolog) 393 394;; arch-tag: f3ec6748-1272-4ab6-8826-c50cb1607636 395;;; prolog.el ends here 396