]> code.delx.au - gnu-emacs-elpa/blob - packages/ediprolog/ediprolog.el
Merge commit '8d8c459d7757cf5774f11be9147d7a54f5f9bbd7'
[gnu-emacs-elpa] / packages / ediprolog / ediprolog.el
1 ;;; ediprolog.el --- Emacs Does Interactive Prolog
2
3 ;; Copyright (C) 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
4
5 ;; Author: Markus Triska <markus.triska@gmx.at>
6 ;; Keywords: languages, processes
7 ;; Version: 1.0
8
9 ;; This file is free software; you can redistribute it and/or modify
10 ;; it under the terms of the GNU General Public License as published by
11 ;; the Free Software Foundation; either version 3, or (at your option)
12 ;; any later version.
13
14 ;; This file is distributed in the hope that it will be useful,
15 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
16 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 ;; GNU General Public License for more details.
18
19 ;; You should have received a copy of the GNU General Public License
20 ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
21
22 ;;; Commentary:
23
24 ;; These definitions let you interact with SWI-Prolog in all buffers.
25 ;; You can consult Prolog programs and evaluate embedded queries.
26
27 ;; Installation
28 ;; ============
29 ;;
30 ;; Copy ediprolog.el to your load-path and add to your .emacs:
31 ;;
32 ;; (require 'ediprolog)
33 ;; (global-set-key [f10] 'ediprolog-dwim)
34 ;;
35 ;; Restart Emacs and customize ediprolog with
36 ;;
37 ;; M-x customize-group RET ediprolog RET
38 ;;
39
40 ;; Usage
41 ;; =====
42 ;;
43 ;; The central function is `ediprolog-dwim' (Do What I Mean), which is
44 ;; bound to F10 by the snippet above. Depending on the content at
45 ;; point, `ediprolog-dwim' does the "appropriate" thing: If point is
46 ;; on a query, F10 sends the query to a Prolog process, and you
47 ;; interact with the process in the current buffer as on a terminal.
48 ;; Queries start with "?-" or ":-", possibly preceded by "%" and
49 ;; whitespace. An example of a query is (without leading ";;"):
50 ;;
51 ;; %?- member(X, [a,b,c]).
52 ;;
53 ;; If you press F10 when point is on that query, you get:
54 ;;
55 ;; %?- member(X, [a,b,c]).
56 ;; %@ X = a ;
57 ;; %@ X = b ;
58 ;; %@ X = c ;
59 ;; %@ false.
60 ;;
61 ;; When waiting for output of the Prolog process, you can press C-g to
62 ;; unblock Emacs and continue with other work. To resume interaction
63 ;; with the Prolog process, use M-x ediprolog-toplevel RET.
64
65 ;; If you press F10 when point is NOT on a query, the buffer content
66 ;; is consulted in the Prolog process, and point is moved to the first
67 ;; error (if any).
68
69 ;; For convenience, the most recent interactions with the Prolog
70 ;; process are logged in the buffer "*ediprolog-history*".
71
72 ;; Use M-x ediprolog-localize RET to make any Prolog process started
73 ;; in the current buffer buffer-local. This way, you can run distinct
74 ;; processes simultaneously. Revert with M-x ediprolog-unlocalize RET.
75
76 ;; `ediprolog-dwim' with prefix arguments has special meanings:
77 ;;
78 ;; C-0 F10 kill Prolog process
79 ;; C-1 F10 always consult buffer (even when point is on a query)
80 ;; C-2 F10 always consult buffer, using a new process
81 ;; C-7 F10 equivalent to `ediprolog-toplevel'
82 ;; C-u F10 first consult buffer, then evaluate query (if any)
83 ;; C-u C-u F10 like C-u F10, with a new process
84
85 ;; Tested with SWI-Prolog 5.6.55 + Emacs 21.2, 22.3 and 23.0.92.2.
86
87 ;;; Code:
88
89 (defconst ediprolog-version "0.9yb")
90
91 (defgroup ediprolog nil
92 "Transparent interaction with SWI-Prolog."
93 :group 'languages
94 :group 'processes)
95
96 (defcustom ediprolog-program
97 (or (executable-find "swipl") (executable-find "pl") "swipl")
98 "Program name of the Prolog executable."
99 :group 'ediprolog
100 :type 'string)
101
102 (defcustom ediprolog-program-switches nil
103 "List of switches passed to the Prolog process. Example:
104 '(\"-G128M\" \"-O\")"
105 :group 'ediprolog
106 :type '(repeat string))
107
108 (defcustom ediprolog-prefix "%@ "
109 "String to prepend when inserting output from the Prolog
110 process into the buffer."
111 :group 'ediprolog
112 :type 'string)
113
114 (defcustom ediprolog-max-history 80000
115 "Maximal size of history buffers storing recent interactions, or
116 nil to never truncate the history."
117 :group 'ediprolog
118 :type 'sexp)
119
120 (defvar ediprolog-process nil "A Prolog process.")
121
122 (defvar ediprolog-temp-buffer nil
123 "Buffer that temporarily saves process output ")
124
125 (defvar ediprolog-seen-prompt nil
126 "Whether a prompt was (recently) emitted by the Prolog process.")
127
128 (defvar ediprolog-read-term nil
129 "Whether the Prolog process waits for the user to enter a term.")
130
131 (defvar ediprolog-indent-prefix ""
132 "Any whitespace occurring before the most recently executed query.")
133
134 (defvar ediprolog-temp-file nil
135 "File name of a temporary file used for consulting the buffer.")
136
137 (defvar ediprolog-prompt "?ediprolog- "
138 "Prompt used in the Prolog session. It must differ from the
139 default Prolog prompt.")
140
141 (defvar ediprolog-consult-buffer "*ediprolog-consult*"
142 "Buffer used to display consult output.")
143
144 (defvar ediprolog-consult-window nil
145 "Window used to show consult output.")
146
147 (defvar ediprolog-history-buffer nil
148 "Buffer that stores recent interactions.")
149
150 (defvar ediprolog-interrupted nil
151 "True iff waiting for the previous query was interrupted with C-g.")
152
153 (defmacro ediprolog-wait-for-prompt-after (&rest forms)
154 "Evaluate FORMS and wait for prompt."
155 `(progn
156 (setq ediprolog-seen-prompt nil)
157 (ediprolog-ensure-buffer "temp")
158 (with-current-buffer ediprolog-temp-buffer
159 (let (buffer-read-only)
160 (erase-buffer)))
161 ;; execute forms with default-directory etc. from invocation buffer
162 ,@forms
163 (unless (process-filter ediprolog-process)
164 (set-process-filter ediprolog-process 'ediprolog-wait-for-prompt-filter))
165 (while (not ediprolog-seen-prompt)
166 ;; Wait for output/sentinel and update consult window, if any.
167 ;; As `accept-process-output' does not run the sentinel in
168 ;; Emacs <= 23.1, we use `sit-for' to do both. However,
169 ;; `sit-for' returns immediately if keyboard input is
170 ;; available, so we must discard input.
171 (discard-input)
172 (sit-for 0.1))))
173
174 (defmacro ediprolog-remember-interruption (form)
175 "Set `ediprolog-interrupted' if evaluation of FORM was interrupted."
176 `(condition-case nil
177 ,form
178 (quit (setq ediprolog-interrupted t))))
179
180 ;; Only the sentinel can reliably detect if no more output follows -
181 ;; even if process-status is 'exit, further output can still follow.
182 (defun ediprolog-sentinel (proc str)
183 (when (buffer-live-p (process-buffer proc))
184 (with-current-buffer (process-buffer proc)
185 (let ((status (with-temp-buffer
186 (insert str)
187 (while (search-backward "\n" nil t)
188 (replace-match ""))
189 (buffer-string))))
190 (ediprolog-log
191 (format "%s: %s.\n"
192 (substring (current-time-string) 4 -5) status) "green" t))
193 (when (string-match "^\\(?:finished\n\\|exited abnormally\\|killed\n\\)"
194 str)
195 (setq ediprolog-seen-prompt t)))))
196
197 (defun ediprolog-ensure-buffer (name)
198 (let ((str (format "*ediprolog-%s*" name))
199 (var (intern (format "ediprolog-%s-buffer" name))))
200 (unless (buffer-live-p (symbol-value var))
201 (set var (generate-new-buffer str))
202 (with-current-buffer (symbol-value var)
203 (buffer-disable-undo)
204 (setq buffer-read-only t)))))
205
206 (defun ediprolog-log (str &optional col nl)
207 (ediprolog-ensure-buffer "history")
208 (with-current-buffer ediprolog-history-buffer
209 (let (buffer-read-only)
210 (goto-char (point-max))
211 (let ((s (format "%s%s" (if (and nl (not (bolp))) "\n" "") str)))
212 (insert (if col (propertize s 'face `(:background ,col)) s)))
213 (let ((size (- (point-max) (point-min))))
214 (when (and ediprolog-max-history
215 (> size ediprolog-max-history))
216 ;; delete older half of the (possibly narrowed) history
217 (delete-region (point-min) (+ (point-min) (/ size 2))))))))
218
219 (defun ediprolog-run-prolog ()
220 "Start a Prolog process."
221 (let ((args (cons ediprolog-program ediprolog-program-switches)))
222 (ediprolog-log (format "%s: starting: %S\n"
223 (substring (current-time-string) 4 -5) args)
224 "green" t)
225 (condition-case nil
226 (ediprolog-wait-for-prompt-after
227 (setq ediprolog-process
228 (apply #'start-process "ediprolog" (current-buffer) args))
229 (set-process-sentinel ediprolog-process 'ediprolog-sentinel)
230 (ediprolog-send-string
231 (format "'$set_prompt'('%s').\n" ediprolog-prompt)))
232 ((error quit)
233 (ediprolog-log "No prompt found." "red" t)
234 (error "No prompt from: %s" ediprolog-program)))))
235
236 (defun ediprolog-kill-prolog ()
237 "Kill the Prolog process and run the process sentinel."
238 (when (ediprolog-running)
239 (delete-process ediprolog-process)))
240
241 (defun ediprolog-show-consult-output (str)
242 (with-current-buffer (get-buffer-create ediprolog-consult-buffer)
243 (setq buffer-read-only t)
244 (let (buffer-read-only)
245 (erase-buffer)
246 (insert str)
247 (goto-char (point-min))
248 ;; remove normal consult status lines, which start with "%"
249 (while (re-search-forward "^[\t ]*%.*\n" nil t)
250 (delete-region (match-beginning 0) (match-end 0))))
251 (setq str (buffer-string)))
252 ;; show consult output in a separate window unless it is a prefix of
253 ;; success (i.e., consulted without errors), or still an incomplete
254 ;; line that starts with a comment character
255 (unless (or (string-match "^[\t ]*\\(?:%.*\\)?\\'" str)
256 (let ((success "true."))
257 (and (<= (length str) (length success))
258 (string= str (substring success 0 (length str))))))
259 (setq ediprolog-consult-window (display-buffer ediprolog-consult-buffer))
260 (set-window-dedicated-p ediprolog-consult-window t)
261 (fit-window-to-buffer ediprolog-consult-window (/ (frame-height) 2))))
262
263 (defun ediprolog-consult-filter (proc str)
264 "Filter used when consulting a file, showing consult output."
265 (with-current-buffer (ediprolog-temp-buffer proc)
266 (goto-char (point-max))
267 (let (buffer-read-only)
268 (insert str))
269 (with-current-buffer (process-buffer proc)
270 (ediprolog-log str))
271 (when (re-search-backward
272 (format "^%s" (regexp-quote ediprolog-prompt)) nil t)
273 (with-current-buffer (process-buffer proc)
274 (setq ediprolog-seen-prompt t)))
275 (skip-chars-backward "\n")
276 (ediprolog-show-consult-output (buffer-substring (point-min) (point)))))
277
278 (defun ediprolog-wait-for-prompt-filter (proc str)
279 "Filter that only waits until prompt appears."
280 (with-current-buffer (ediprolog-temp-buffer proc)
281 (goto-char (point-max))
282 (let (buffer-read-only)
283 (insert str))
284 (with-current-buffer (process-buffer proc)
285 (ediprolog-log str))
286 (when (re-search-backward
287 (format "^%s" (regexp-quote ediprolog-prompt)) nil t)
288 (with-current-buffer (process-buffer proc)
289 (setq ediprolog-seen-prompt t)))))
290
291 \f
292 ;;;###autoload
293 (defun ediprolog-dwim (&optional arg)
294 "Load current buffer into Prolog or post query (Do What I Mean).
295 If invoked on a line starting with `:-' or `?-', possibly
296 preceded by `%' and whitespace, call `ediprolog-interact' with
297 the query as argument. Otherwise, call `ediprolog-consult'.
298
299 With prefix argument 0, kill the Prolog process. With prefix 1,
300 equivalent to `ediprolog-consult'. With prefix 2, equivalent to
301 `ediprolog-consult' with a new Prolog process. With prefix 7,
302 equivalent to `ediprolog-toplevel'. With just C-u, first call
303 `ediprolog-consult' and then, if point is on a query, call
304 `ediprolog-interact' with it as argument. Analogously, C-u C-u
305 for `ediprolog-consult' with a new process. With other prefix
306 arguments, equivalent to `ediprolog-remove-interactions'."
307 (interactive "P")
308 (cond ((eq arg 0)
309 (unless (ediprolog-running)
310 (error "No Prolog process running"))
311 (ediprolog-kill-prolog)
312 (message "Prolog process killed."))
313 ((eq arg 1) (ediprolog-consult))
314 ((eq arg 2) (ediprolog-consult t))
315 ((eq arg 7)
316 (unless (ediprolog-more-solutions)
317 (error "No query in progress"))
318 (ediprolog-toplevel))
319 ((equal arg '(4)) (ediprolog-consult) (ediprolog-query))
320 ((equal arg '(16)) (ediprolog-consult t) (ediprolog-query))
321 ((null arg) (unless (ediprolog-query) (ediprolog-consult)))
322 (t (ediprolog-remove-interactions))))
323
324 (defun ediprolog-process-ready ()
325 "Error if the previous query is still in progress."
326 (when (and ediprolog-interrupted
327 (ediprolog-running)
328 (ediprolog-more-solutions))
329 (error "Previous query still in progress, see `ediprolog-toplevel'"))
330 (setq ediprolog-interrupted nil))
331
332 (defun ediprolog-query ()
333 "If point is on a query, send it to the process and start interaction."
334 (ediprolog-process-ready)
335 (when (and (not (and transient-mark-mode mark-active))
336 (save-excursion
337 (beginning-of-line)
338 (looking-at "\\([\t ]*\\)%*[\t ]*[:?]-")))
339 ;; whitespace preceding the query is the indentation level
340 (setq ediprolog-indent-prefix (match-string 1))
341 (let* ((from (goto-char (match-end 0)))
342 (to (if (re-search-forward "\\.[\t ]*\\(?:%.*\\)?$" nil t)
343 ;; omit trailing whitespace
344 (+ (point) (skip-chars-backward "\t "))
345 (error "Missing `.' at the end of this query")))
346 (query (buffer-substring-no-properties from to)))
347 (end-of-line)
348 (insert "\n" ediprolog-indent-prefix ediprolog-prefix)
349 (ediprolog-interact
350 (format "%s\n" (mapconcat #'identity
351 ;; `%' can precede each query line
352 (split-string query "\n[ \t%]*") " "))))
353 t))
354
355 ;;;###autoload
356 (defun ediprolog-interact (query)
357 "Send QUERY to Prolog process and interact as on a terminal.
358
359 You can use \\[keyboard-quit] to unblock Emacs in the case of
360 longer-running queries. When the query completes and the toplevel
361 asks for input, use \\[ediprolog-toplevel] to resume interaction
362 with the Prolog process."
363 (unless (ediprolog-running)
364 (ediprolog-run-prolog))
365 (set-marker (process-mark ediprolog-process) (point))
366 (set-process-buffer ediprolog-process (current-buffer))
367 (set-process-filter ediprolog-process 'ediprolog-interact-filter)
368 (ediprolog-ensure-buffer "temp")
369 (with-current-buffer ediprolog-temp-buffer
370 (let (buffer-read-only)
371 (erase-buffer)))
372 (setq ediprolog-seen-prompt nil
373 ediprolog-read-term nil)
374 (ediprolog-send-string query)
375 (ediprolog-toplevel))
376
377 (defun ediprolog-send-string (str)
378 "Send string to Prolog process and log it."
379 (ediprolog-log str "cyan")
380 (process-send-string ediprolog-process str))
381
382 (defun ediprolog-toplevel ()
383 "Start or resume Prolog toplevel interaction in the buffer.
384
385 You can use this function if you have previously quit (with
386 \\[keyboard-quit]) waiting for a longer-running query and now
387 want to resume interaction with the toplevel."
388 (interactive)
389 (when ediprolog-process
390 (select-window (display-buffer (process-buffer ediprolog-process))))
391 (ediprolog-remember-interruption
392 (while (ediprolog-more-solutions)
393 (let (str
394 char)
395 ;; poll for user input; meanwhile, process output can arrive
396 (while (and (ediprolog-more-solutions) (null str))
397 (goto-char (process-mark ediprolog-process))
398 (if ediprolog-read-term
399 (progn
400 (setq str (concat (read-string "Input: ") "\n"))
401 (ediprolog-insert-at-marker
402 str ediprolog-indent-prefix ediprolog-prefix)
403 (setq ediprolog-read-term nil))
404 (condition-case nil
405 (when (setq char (if (>= emacs-major-version 22)
406 (read-char nil nil 0.1)
407 (with-timeout (0.1 nil)
408 (read-char))))
409 ;; char-to-string might still yield an error (C-0 etc.)
410 (setq str (char-to-string char)))
411 (error
412 (message "Non-character key")
413 ;; non-character keys must not remain in the input
414 ;; buffer, lest `read-char' return immediately
415 (discard-input)))))
416 (when (ediprolog-more-solutions)
417 (if (eq char ?\C-c) ; char can be nil too
418 ;; sending C-c directly yields strange SWI buffering
419 (interrupt-process ediprolog-process)
420 (ediprolog-send-string str)))))))
421
422 ;;;###autoload
423 (defun ediprolog-remove-interactions ()
424 "Remove all lines starting with `ediprolog-prefix' from buffer.
425
426 In transient mark mode, the function operates on the region if it
427 is active."
428 (interactive)
429 (save-excursion
430 (save-restriction
431 (when (and transient-mark-mode mark-active)
432 (narrow-to-region (region-beginning) (region-end)))
433 (goto-char (point-min))
434 (flush-lines (concat "^[\t ]*" (regexp-quote ediprolog-prefix)))))
435 (message "Interactions removed."))
436
437 \f
438 ;;;###autoload
439 (defun ediprolog-consult (&optional new-process)
440 "Buffer is loaded into a Prolog process. If NEW-PROCESS is
441 non-nil, start a new process. Otherwise use the existing process,
442 if any. In case of errors, point is moved to the position of the
443 first error, and the mark is left at the previous position.
444
445 In transient mark mode, the function operates on the region if it
446 is active."
447 (interactive)
448 (when (string= (buffer-name) ediprolog-consult-buffer)
449 (error "Cannot consult the consult buffer"))
450 (when (window-live-p ediprolog-consult-window)
451 (condition-case nil
452 ;; deleting the window can still raise an error, if the window
453 ;; was the only window in the frame and the consult buffer was
454 ;; killed (and it thus displays a different buffer now)
455 (delete-window ediprolog-consult-window)
456 (error nil)))
457 (when (buffer-live-p ediprolog-consult-buffer)
458 (bury-buffer ediprolog-consult-buffer))
459 (when new-process
460 (ediprolog-kill-prolog))
461 (unless (ediprolog-running)
462 (ediprolog-run-prolog))
463 (ediprolog-process-ready)
464 (set-process-buffer ediprolog-process (current-buffer))
465 (unless ediprolog-temp-file
466 (setq ediprolog-temp-file (make-temp-file "ediprolog")))
467 (let ((start (if (and transient-mark-mode mark-active)
468 (region-beginning) (point-min)))
469 (end (if (and transient-mark-mode mark-active)
470 (region-end) (point-max))))
471 (write-region start end ediprolog-temp-file nil 'silent))
472 (set-process-filter ediprolog-process 'ediprolog-consult-filter)
473 (ediprolog-remember-interruption
474 (ediprolog-wait-for-prompt-after
475 (ediprolog-send-string (format "['%s'].\n" ediprolog-temp-file))))
476 (message "%s consulted." (if (and transient-mark-mode mark-active)
477 "Region" "Buffer"))
478 ;; go to line of the first error, if any
479 (let ((line (with-current-buffer ediprolog-temp-buffer
480 (when (save-excursion
481 (goto-char (point-min))
482 (re-search-forward "^ERROR.*?:\\([0-9]+\\)" nil t))
483 (string-to-number (match-string 1))))))
484 (when line
485 (if (and transient-mark-mode mark-active)
486 (when (fboundp 'line-number-at-pos)
487 (goto-line (+ (line-number-at-pos (region-beginning)) line -1)))
488 (goto-line line)))))
489
490 (defun ediprolog-running ()
491 "True iff `ediprolog-process' is a running process."
492 (and (processp ediprolog-process)
493 (eq (process-status ediprolog-process) 'run)))
494
495 (defun ediprolog-more-solutions ()
496 "True iff there could be more solutions from the process."
497 (not ediprolog-seen-prompt))
498
499 (defun ediprolog-interact-filter (proc string)
500 "Insert output from the process and update the state."
501 (when (and (buffer-live-p (ediprolog-temp-buffer proc))
502 (buffer-live-p (process-buffer proc)))
503 (let (str)
504 (with-current-buffer (ediprolog-temp-buffer proc)
505 (goto-char (point-max))
506 (let (buffer-read-only)
507 (insert string))
508 (with-current-buffer (process-buffer proc)
509 (ediprolog-log string))
510 ;; read a term from the user?
511 (when (re-search-backward "^|: $" nil t)
512 (with-current-buffer (process-buffer proc)
513 (setq ediprolog-read-term t))
514 (setq str (buffer-string))
515 (let (buffer-read-only)
516 (erase-buffer)))
517 ;; check for prompt
518 (goto-char (point-max))
519 (when (re-search-backward
520 (format "^%s" (regexp-quote ediprolog-prompt)) nil t)
521 (with-current-buffer (process-buffer proc)
522 (setq ediprolog-seen-prompt t))
523 ;; ignore further output due to accidental user input (C-j,
524 ;; C-m, etc.) while the query was running
525 (set-process-filter proc 'ediprolog-ignore-filter)
526 (skip-chars-backward "\n")
527 (setq str (buffer-substring (point-min) (point))))
528 (unless str
529 (goto-char (point-max))
530 ;; delay final line if it can still be completed to prompt
531 (let ((l (buffer-substring (line-beginning-position) (point))))
532 (when (and (<= (length l) (length ediprolog-prompt))
533 (string= l (substring ediprolog-prompt 0 (length l))))
534 (goto-char (line-beginning-position))))
535 ;; delay emitting newlines until we are sure no prompt
536 ;; follows; one or two newlines can precede a prompt
537 (let ((d (abs (skip-chars-backward "\n"))))
538 (when (> d 2)
539 (forward-char (- d 2))))
540 (setq str (buffer-substring (point-min) (point)))
541 (let (buffer-read-only)
542 (delete-region (point-min) (point))))
543 (when str
544 (with-temp-buffer
545 ;; precede each line with ediprolog prefices
546 (insert str)
547 (goto-char (point-min))
548 (while (search-forward "\n" nil t)
549 (replace-match
550 (format "\n%s%s" (with-current-buffer (process-buffer proc)
551 ediprolog-indent-prefix) ediprolog-prefix)))
552 (setq str (buffer-string)))
553 (with-current-buffer (process-buffer proc)
554 (let ((near (<= (abs (- (point) (process-mark proc))) 1)))
555 (ediprolog-insert-at-marker str)
556 (when near
557 ;; catch up with output if point was reasonably close
558 (goto-char (process-mark proc))))))))))
559
560
561 (defun ediprolog-insert-at-marker (&rest args)
562 "Insert strings ARGS at marker and update the marker."
563 (save-excursion
564 (goto-char (process-mark ediprolog-process))
565 (end-of-line)
566 (apply #'insert args)
567 (set-marker (process-mark ediprolog-process) (point))))
568
569 (defun ediprolog-ignore-filter (proc str)
570 "Log and then ignore all process output."
571 (with-current-buffer (process-buffer proc)
572 (ediprolog-log str "gray")))
573
574 (defun ediprolog-temp-buffer (proc)
575 (with-current-buffer (process-buffer proc)
576 ;; temp buffer can be buffer local
577 ediprolog-temp-buffer))
578
579 (defun ediprolog-map-variables (func)
580 "Call FUNC with all ediprolog variables that can become buffer-local."
581 (mapc func '(ediprolog-process
582 ediprolog-program
583 ediprolog-program-switches
584 ediprolog-temp-buffer
585 ediprolog-history-buffer
586 ediprolog-seen-prompt
587 ediprolog-interrupted
588 ediprolog-read-term
589 ediprolog-indent-prefix
590 ediprolog-temp-file)))
591
592 ;;;###autoload
593 (defun ediprolog-localize ()
594 "After `ediprolog-localize', any Prolog process started from
595 this buffer becomes buffer-local."
596 (interactive)
597 (unless (local-variable-p 'ediprolog-process)
598 (ediprolog-map-variables #'make-local-variable)
599 (setq ediprolog-temp-file nil
600 ediprolog-process nil
601 ediprolog-history-buffer nil
602 ediprolog-temp-buffer nil)))
603
604 (defun ediprolog-unlocalize ()
605 "Revert the effect of `ediprolog-localize'."
606 (interactive)
607 (when (local-variable-p 'ediprolog-process)
608 (ediprolog-kill-prolog)
609 (ediprolog-map-variables #'kill-local-variable)))
610
611 (provide 'ediprolog)
612
613 ;;; ediprolog.el ends here