1 ;;; ==================================================================
2 ;;; File: haskell.el ;;;
4 ;;; Author: A. Satish Pai ;;;
5 ;;; Maria M. Gutierrez ;;;
6 ;;; Dan Rabin (Jul-1991) ;;;
7 ;;; ==================================================================
9 ;;; Description: Haskell mode for GNU Emacs.
11 ;;; Related files: comint.el
17 ;;; Known bugs / problems
18 ;;; - the haskell editing mode (indentation, etc) is still missing.
19 ;;; - the handling for errors from haskell needs to be rethought.
20 ;;; - general cleanup of code.
25 ;;; ==================================================================
26 ;;; Haskell mode for editing files, and an Inferior Haskell mode to
27 ;;; run a Haskell process. This file contains stuff snarfed and
28 ;;; modified from tea.el, scheme.el, etc. This file may be freely
29 ;;; modified; however, if you have any bug-corrections or useful
30 ;;; improvements, I'd appreciate it if you sent me the mods so that
31 ;;; I can merge them into the version I maintain.
33 ;;; The inferior Haskell mode requires comint.el.
35 ;;; You might want to add this to your .emacs to go automagically
36 ;;; into Haskell mode while finding .hs files.
38 ;;; (setq auto-mode-alist
39 ;;; (cons '("\\.hs$" . haskell-mode)
40 ;;; auto-mode-alist)_)
42 ;;; To use this file, set up your .emacs to autoload this file for
43 ;;; haskell-mode. For example:
45 ;;; (autoload 'haskell-mode "$HASKELL/emacs-tools/haskell.elc"
46 ;;; "Load Haskell mode" t)
48 ;;; (autoload 'run-mode "$HASKELL/emacs-tools/haskell.elc"
49 ;;; "Load Haskell mode" t)
51 ;;; [Note: The path name given above is Yale specific!! Modify as
53 ;;; ================================================================
55 ;;; Announce your existence to the world at large.
60 ;;; Load these other files.
62 (require 'comint) ; Olin Shivers' comint mode is the substratum
67 ;;; ================================================================
68 ;;; Declare a bunch of variables.
69 ;;; ================================================================
72 ;;; User settable (via M-x set-variable and M-x edit-options)
74 (defvar haskell-program-name (getenv "HASKELLPROG")
75 "*Program invoked by the haskell command.")
77 (defvar haskell-auto-create-process t
78 "*If not nil, create a Haskell process automatically when required to evaluate or compile Haskell code.")
80 (defvar haskell-auto-switch-input t
81 "*If not nil, jump to *haskell* buffer automatically on input request.")
83 (defvar haskell-ask-before-saving t
84 "*If not nil, ask before saving random haskell-mode buffers.")
86 (defvar haskell-initial-printers '("interactive")
87 "*Printers to set when starting a new Haskell process.")
90 ;;; Pad/buffer Initialization variables
92 (defvar *haskell-buffer* "*haskell*"
93 "Name of the haskell process buffer")
95 (defvar haskell-main-pad "\*Main-pad\*"
96 "Scratch pad associated with module Main")
98 (defvar haskell-main-module "Main")
101 (defvar *last-loaded* nil)
102 (defvar *last-module* haskell-main-module)
103 (defvar *last-pad* haskell-main-pad)
106 ;;; These are used for haskell-tutorial mode.
108 (defvar *ht-source-file* "$HASKELL/progs/tutorial/tutorial.lhs")
109 (defvar *ht-temp-buffer* nil)
110 (defvar *ht-file-buffer* "Haskell-Tutorial-Master")
114 ;;; ================================================================
115 ;;; Haskell editing mode stuff
116 ;;; ================================================================
118 ;;; Leave this place alone...
119 ;;; The definitions below have been pared down to the bare
120 ;;; minimum; they will be restored later.
124 ;;; Keymap for Haskell mode
125 (defvar haskell-mode-map (make-sparse-keymap)
126 "Keymap used for haskell-mode")
128 (defun haskell-establish-key-bindings (keymap)
129 (define-key keymap "\C-ce" 'haskell-eval)
130 (define-key keymap "\C-cr" 'haskell-run)
131 (define-key keymap "\C-ct" 'haskell-report-type)
132 (define-key keymap "\C-cm" 'haskell-run-main)
133 (define-key keymap "\C-c\C-r" 'haskell-run-file)
134 (define-key keymap "\C-cp" 'haskell-get-pad)
135 (define-key keymap "\C-c\C-o" 'haskell-optimizers)
136 (define-key keymap "\C-c\C-p" 'haskell-printers)
137 (define-key keymap "\C-cc" 'haskell-compile)
138 (define-key keymap "\C-cl" 'haskell-load)
139 (define-key keymap "\C-ch" 'haskell-switch)
140 (define-key keymap "\C-c\C-k" 'haskell-kill)
141 (define-key keymap "\C-c:" 'haskell-command)
142 (define-key keymap "\C-cq" 'haskell-exit)
143 (define-key keymap "\C-ci" 'haskell-interrupt)
144 (define-key keymap "\C-cu" 'haskell-edit-unit))
147 (haskell-establish-key-bindings haskell-mode-map)
150 (defvar haskell-mode-syntax-table nil
151 "Syntax table used for haskell-mode")
153 (if haskell-mode-syntax-table
155 (setq haskell-mode-syntax-table (standard-syntax-table)))
157 ;;; Command for invoking the Haskell mode
158 (defun haskell-mode nil
159 "Major mode for editing Haskell code to run in Emacs
160 The following commands are available:
163 A Haskell process can be fired up with \"M-x haskell\".
165 Customization: Entry to this mode runs the hooks that are the value of variable
170 There are 3 types of windows associated with Haskell mode. They are:
171 *haskell*: which is the process window.
172 Pad: which are buffers available for each module. It is here
173 where you want to test things before preserving them in a
174 file. Pads are always associated with a module.
175 When issuing a command:
176 The pad and its associated module are sent to the Haskell
177 process prior to the execution of the command.
178 .hs: These are the files where Haskell programs live. They
179 have .hs as extension.
180 When issuing a command:
181 The file is sent to the Haskell process prior to the
182 execution of the command.
186 Each command behaves differently according to the type of the window in which
187 the cursor is positioned when the command is issued .
189 haskell-eval: \\[haskell-eval]
190 Always promts user for a Haskell expression to be evaluated. If in a
191 .hs file buffer, then the cursor tells which module is the current
192 module and the pad for that module (if any) gets loaded as well.
194 haskell-run: \\[haskell-run]
195 Always queries for a variable of type Dialogue to be evaluated.
197 haskell-run-main: \\[haskell-run-main]
198 Run Dialogue named main in the current module.
200 haskell-report-type: \\[haskell-report-type]
201 Like haskell-eval, but prints the type of the expression without
204 haskell-mode: \\[haskell-mode]
205 Puts the current buffer in haskell mode.
207 haskell-compile: \\[haskell-compile]
208 Compiles file in current buffer.
210 haskell-load: \\[haskell-load]
211 Loads file in current buffer.
213 haskell-run-file: \\[haskell-run-file]
214 Runs file in the current buffer.
216 haskell-pad: \\[haskell-pad]
217 Creates a scratch pad for the current module.
219 haskell-optimizers: \\[haskell-optimizers]
220 Shows the list of available optimizers. Commands for turning them on/off.
222 haskell-printers: \\[haskell-printers]
223 Shows the list of available printers. Commands for turning them on/off.
225 haskell-command: \\[haskell-command]
226 Prompts for a command to be sent to the command interface. You don't
227 need to put the : before the command.
229 haskell-quit: \\[haskell-quit]
230 Terminates the haskell process.
232 haskell-switch: \\[haskell-switch]
233 Switches to the inferior Haskell buffer (*haskell*) and positions the
234 cursor at the end of the buffer.
236 haskell-kill: \\[haskell-kill]
237 Kill the current contents of the *haskell* buffer.
239 haskell-interrupt: \\[haskell-interrupt]
240 Interrupts haskell process and resets it.
242 haskell-edit-unit: \\[haskell-edit-unit]
243 Edit the .hu file for the unit containing this file.
246 (kill-all-local-variables)
247 (use-local-map haskell-mode-map)
248 (setq major-mode 'haskell-mode)
249 (setq mode-name "Haskell")
250 (make-local-variable 'indent-line-function)
251 (setq indent-line-function 'indent-relative-maybe)
252 ;(setq local-abbrev-table haskell-mode-abbrev-table)
253 (set-syntax-table haskell-mode-syntax-table)
254 ;(setq tab-stop-list haskell-tab-stop-list) ;; save old list??
255 (run-hooks 'haskell-mode-hook))
259 ;;;================================================================
260 ;;; Inferior Haskell stuff
261 ;;;================================================================
264 (defvar inferior-haskell-mode-map (full-copy-sparse-keymap comint-mode-map))
266 (haskell-establish-key-bindings inferior-haskell-mode-map)
267 (define-key inferior-haskell-mode-map "\C-m" 'haskell-send-input)
269 (defvar haskell-source-modes '(haskell-mode)
270 "*Used to determine if a buffer contains Haskell source code.
271 If it's loaded into a buffer that is in one of these major modes,
272 it's considered a Haskell source file.")
274 (defvar haskell-prompt-pattern "^[A-Z]\\([A-Z]\\|[a-z]\\|[0-9]\\)*>\\s-*"
275 "Regular expression capturing the Haskell system prompt.")
277 (defvar haskell-prompt-ring ()
278 "Keeps track of input to haskell process from the minibuffer")
280 (defun inferior-haskell-mode-variables ()
284 ;;; INFERIOR-HASKELL-MODE (adapted from comint.el)
286 (defun inferior-haskell-mode ()
287 "Major mode for interacting with an inferior Haskell process.
289 The following commands are available:
290 \\{inferior-haskell-mode-map}
292 A Haskell process can be fired up with \"M-x haskell\".
294 Customization: Entry to this mode runs the hooks on comint-mode-hook and
295 inferior-haskell-mode-hook (in that order).
297 You can send text to the inferior Haskell process from other buffers containing
303 There are 3 types of windows in the inferior-haskell-mode. They are:
304 *haskell*: which is the process window.
305 Pad: which are buffers available for each module. It is here
306 where you want to test things before preserving them in a
307 file. Pads are always associated with a module.
308 When issuing a command:
309 The pad and its associated module are sent to the Haskell
310 process prior to the execution of the command.
311 .hs: These are the files where Haskell programs live. They
312 have .hs as extension.
313 When issuing a command:
314 The file is sent to the Haskell process prior to the
315 execution of the command.
319 Each command behaves differently according to the type of the window in which
320 the cursor is positioned when the command is issued.
322 haskell-eval: \\[haskell-eval]
323 Always promts user for a Haskell expression to be evaluated. If in a
324 .hs file, then the cursor tells which module is the current module and
325 the pad for that module (if any) gets loaded as well.
327 haskell-run: \\[haskell-run]
328 Always queries for a variable of type Dialogue to be evaluated.
330 haskell-run-main: \\[haskell-run-main]
331 Run Dialogue named main.
333 haskell-report-type: \\[haskell-report-type]
334 Like haskell-eval, but prints the type of the expression without
337 haskell-mode: \\[haskell-mode]
338 Puts the current buffer in haskell mode.
340 haskell-compile: \\[haskell-compile]
341 Compiles file in current buffer.
343 haskell-load: \\[haskell-load]
344 Loads file in current buffer.
346 haskell-run-file: \\[haskell-run-file]
347 Runs file in the current buffer.
349 haskell-pad: \\[haskell-pad]
350 Creates a scratch pad for the current module.
352 haskell-optimizers: \\[haskell-optimizers]
353 Shows the list of available optimizers. Commands for turning them on/off.
355 haskell-printers: \\[haskell-printers]
356 Shows the list of available printers. Commands for turning them on/off.
358 haskell-command: \\[haskell-command]
359 Prompts for a command to be sent to the command interface. You don't
360 need to put the : before the command.
362 haskell-quit: \\[haskell-quit]
363 Terminates the haskell process.
365 haskell-switch: \\[haskell-switch]
366 Switches to the inferior Haskell buffer (*haskell*) and positions the
367 cursor at the end of the buffer.
369 haskell-kill: \\[haskell-kill]
370 Kill the current contents of the *haskell* buffer.
372 haskell-interrupt: \\[haskell-interrupt]
373 Interrupts haskell process and resets it.
375 haskell-edit-unit: \\[haskell-edit-unit]
376 Edit the .hu file for the unit containing this file.
378 The usual comint functions are also available. In particular, the
379 following are all available:
381 comint-bol: Beginning of line, but skip prompt. Bound to C-a by default.
382 comint-delchar-or-maybe-eof: Delete char, unless at end of buffer, in
383 which case send EOF to process. Bound to C-d by default.
385 Note however, that the default keymap bindings provided shadow some of
386 the default comint mode bindings, so that you may want to bind them
387 to your choice of keys.
389 Comint mode's dynamic completion of filenames in the buffer is available.
390 (Q.v. comint-dynamic-complete, comint-dynamic-list-completions.)
392 If you accidentally suspend your process, use \\[comint-continue-subjob]
397 (setq comint-prompt-regexp haskell-prompt-pattern)
398 ;; Customise in inferior-haskell-mode-hook
399 (inferior-haskell-mode-variables)
400 (setq major-mode 'inferior-haskell-mode)
401 (setq mode-name "Inferior Haskell")
402 (setq mode-line-process '(": %s : busy"))
403 (use-local-map inferior-haskell-mode-map)
404 (setq comint-input-filter 'haskell-input-filter)
405 (setq comint-input-sentinel 'ignore)
406 (setq comint-get-old-input 'haskell-get-old-input)
407 (run-hooks 'inferior-haskell-mode-hook)
408 ;Do this after the hook so the user can mung INPUT-RING-SIZE w/his hook.
409 ;The test is so we don't lose history if we run comint-mode twice in
411 (setq haskell-prompt-ring (make-ring input-ring-size)))
414 (defun haskell-input-filter (str)
415 "Don't save whitespace."
416 (not (string-match "\\s *" str)))
420 ;;; ==================================================================
422 ;;; ==================================================================
425 ;;; This keeps track of the status of the haskell process.
427 ;;; busy -- The process is busy.
428 ;;; ready -- The process is ready for a command.
429 ;;; input -- The process is waiting for input.
430 ;;; debug -- The process is in the debugger.
432 (defvar *haskell-status* 'busy
433 "Status of the haskell process")
435 (defun set-haskell-status (value)
436 (setq *haskell-status* value)
437 (haskell-update-mode-line))
439 (defun get-haskell-status ()
442 (defun haskell-update-mode-line ()
444 (set-buffer *haskell-buffer*)
445 (cond ((eq *haskell-status* 'ready)
446 (setq mode-line-process '(": %s: ready")))
447 ((eq *haskell-status* 'input)
448 (setq mode-line-process '(": %s: input")))
449 ((eq *haskell-status* 'busy)
450 (setq mode-line-process '(": %s: busy")))
451 ((eq *haskell-status* 'debug)
452 (setq mode-line-process '(": %s: debug")))
454 (haskell-mode-error "Confused about status of haskell process!")))
455 ;; Yes, this is the officially sanctioned technique for forcing
456 ;; a redisplay of the mode line.
457 (set-buffer-modified-p (buffer-modified-p))))
460 (defun haskell-send-to-process (string)
461 (process-send-string "haskell" string)
462 (process-send-string "haskell" "\n"))
466 ;;; ==================================================================
467 ;;; Handle input in haskell process buffer; history commands.
468 ;;; ==================================================================
470 (defun haskell-get-old-input ()
471 "Get old input text from Haskell process buffer."
473 (if (re-search-forward haskell-prompt-pattern (point-max) 'move)
474 (goto-char (match-beginning 0)))
475 (cond ((re-search-backward haskell-prompt-pattern (point-min) t)
477 (let ((temp (point)))
479 (buffer-substring temp (point)))))))
482 (defun haskell-send-input ()
483 "Send input to Haskell while in the process buffer"
485 (if (eq (get-haskell-status) 'debug)
487 (haskell-send-input-aux)))
489 (defun haskell-send-input-aux ()
490 ;; Note that the input string does not include its terminal newline.
491 (let ((proc (get-buffer-process (current-buffer))))
493 (haskell-mode-error "Current buffer has no process!")
494 (let* ((pmark (process-mark proc))
495 (pmark-val (marker-position pmark))
496 (input (if (>= (point) pmark-val)
497 (buffer-substring pmark (point))
498 (let ((copy (funcall comint-get-old-input)))
503 (if (funcall comint-input-filter input)
504 (ring-insert input-ring input))
505 (funcall comint-input-sentinel input)
506 (set-marker (process-mark proc) (point))
507 (set-marker comint-last-input-end (point))
508 (haskell-send-to-process input)))))
512 ;;; ==================================================================
513 ;;; Minibuffer input stuff
514 ;;; ==================================================================
516 ;;; Haskell input history retrieval commands (taken from comint.el)
517 ;;; M-p -- previous input M-n -- next input
519 (defvar haskell-minibuffer-local-map nil
520 "Local map for minibuffer when in Haskell")
522 (if haskell-minibuffer-local-map
525 (setq haskell-minibuffer-local-map
526 (full-copy-sparse-keymap minibuffer-local-map))
528 (define-key haskell-minibuffer-local-map "\ep" 'haskell-previous-input)
529 (define-key haskell-minibuffer-local-map "\en" 'haskell-next-input)
532 (defun haskell-previous-input (arg)
533 "Cycle backwards through input history."
535 (let ((len (ring-length haskell-prompt-ring)))
537 (message "Empty input ring.")
540 (cond ((eq last-command 'haskell-previous-input)
541 (delete-region (mark) (point))
544 (setq input-ring-index
547 (push-mark (point))))
548 (setq input-ring-index (comint-mod (+ input-ring-index arg) len))
549 (insert (ring-ref haskell-prompt-ring input-ring-index))
550 (setq this-command 'haskell-previous-input))
553 (defun haskell-next-input (arg)
554 "Cycle forwards through input history."
556 (haskell-previous-input (- arg)))
558 (defvar haskell-last-input-match ""
559 "Last string searched for by Haskell input history search, for defaulting.
560 Buffer local variable.")
562 (defun haskell-previous-input-matching (str)
563 "Searches backwards through input history for substring match"
564 (interactive (let ((s (read-from-minibuffer
565 (format "Command substring (default %s): "
566 haskell-last-input-match))))
567 (list (if (string= s "") haskell-last-input-match s))))
568 (setq haskell-last-input-match str) ; update default
569 (let ((str (regexp-quote str))
570 (len (ring-length haskell-prompt-ring))
572 (while (and (<= n len)
573 (not (string-match str (ring-ref haskell-prompt-ring n))))
575 (cond ((<= n len) (haskell-previous-input (+ n 1)))
576 (t (haskell-mode-error "Not found.")))))
579 ;;; Actually read an expression from the minibuffer using the new keymap.
581 (defun haskell-get-expression (prompt)
582 (let ((exp (read-from-minibuffer prompt nil haskell-minibuffer-local-map)))
583 (ring-insert haskell-prompt-ring exp)
588 ;;; ==================================================================
589 ;;; Handle output from Haskell process
590 ;;; ==================================================================
592 ;;; The haskell process produces output with embedded control codes.
593 ;;; These control codes are used to keep track of what kind of input
594 ;;; the haskell process is expecting. Ordinary output is just displayed.
596 ;;; This is kind of complicated because control sequences can be broken
597 ;;; across multiple batches of text received from the haskell process.
598 ;;; If the string ends in the middle of a control sequence, save it up
599 ;;; for the next call.
601 (defvar *haskell-saved-output* nil)
603 ;;; On the Next, there is some kind of race condition that causes stuff
604 ;;; sent to the Haskell subprocess before it has really started to be lost.
605 ;;; The point of this variable is to force the Emacs side to wait until
606 ;;; Haskell has started and printed out its banner before sending it
607 ;;; anything. See start-haskell below.
609 (defvar *haskell-process-alive* nil)
611 (defun haskell-output-filter (process str)
612 "Filter for output from Yale Haskell command interface"
614 ;;(let ((buffer (get-buffer-create "haskell-output")))
616 ;; (set-buffer buffer)
618 (setq *haskell-process-alive* t)
624 ;; If there was saved output from last time, glue it in front of the
625 ;; newly received input.
626 (if *haskell-saved-output*
628 (setq str (concat *haskell-saved-output* str))
629 (setq *haskell-saved-output* nil)))
630 ;; Loop, looking for complete command sequences.
631 ;; Set next to point to the first one.
632 ;; start points to first character to be processed.
634 (string-match *haskell-message-match-regexp*
636 ;; Display any intervening ordinary text.
637 (if (not (eq next start))
638 (haskell-display-output (substring str start next)))
639 ;; Now dispatch on the particular command sequence found.
640 ;; Handler functions are called with the string and start index
641 ;; as arguments, and should return the index of the "next"
643 (let ((end (match-end 0)))
644 (haskell-handle-message str next)
646 ;; Look to see whether the string ends with an incomplete
648 ;; If so, save the tail of the string for next time.
650 (string-match *haskell-message-prefix-regexp* str start))
651 (eq (match-end 0) (length str)))
652 (setq *haskell-saved-output* (substring str next))
653 (setq next (length str)))
654 ;; Display any leftover ordinary text.
655 (if (not (eq next start))
656 (haskell-display-output (substring str start next))))
657 (store-match-data data))))
659 (defvar *haskell-message-match-regexp*
662 (defvar *haskell-message-prefix-regexp*
663 "E\\(M\\(A\\(C\\(S\\(:.*\\)?\\)?\\)?\\)?\\)?")
665 (defvar *haskell-message-dispatch*
666 '(("EMACS:debug\n" . haskell-got-debug)
667 ("EMACS:busy\n" . haskell-got-busy)
668 ("EMACS:input\n" . haskell-got-input)
669 ("EMACS:ready\n" . haskell-got-ready)
670 ("EMACS:printers .*\n" . haskell-got-printers)
671 ("EMACS:optimizers .*\n" . haskell-got-optimizers)
672 ("EMACS:message .*\n" . haskell-got-message)
673 ("EMACS:error\n" . haskell-got-error)
676 (defun haskell-handle-message (str idx)
677 (let ((list *haskell-message-dispatch*)
679 (while (and list (null fn))
680 (if (eq (string-match (car (car list)) str idx) idx)
681 (setq fn (cdr (car list)))
682 (setq list (cdr list))))
684 (haskell-mode-error "Garbled message from Haskell!")
685 (let ((end (match-end 0)))
686 (funcall fn str idx end)
690 (defun haskell-message-data (string start end)
691 (let ((real-start (+ (string-match " " string start) 1))
692 (real-end (- end 1)))
693 (substring string real-start real-end)))
695 (defun haskell-got-debug (string start end)
697 (message "In the debugger!")
698 (set-haskell-status 'debug))
700 (defun haskell-got-busy (string start end)
701 (set-haskell-status 'busy))
703 (defun haskell-got-input (string start end)
704 (if haskell-auto-switch-input
708 (set-haskell-status 'input)
709 (message "Waiting for input..."))
711 (defun haskell-got-ready (string start end)
712 (set-haskell-status 'ready))
714 (defun haskell-got-printers (string start end)
715 (haskell-printers-update (haskell-message-data string start end)))
717 (defun haskell-got-optimizers (string start end)
718 (haskell-optimizers-update (haskell-message-data string start end)))
720 (defun haskell-got-message (string start end)
721 (message "%s" (haskell-message-data string start end)))
723 (defun haskell-got-error (string start end)
725 (message "Haskell error."))
728 ;;; Displays output at end of given buffer.
729 ;;; This function only ensures that the output is visible, without
730 ;;; selecting the buffer in which it is displayed.
731 ;;; Note that just using display-buffer instead of all this rigamarole
732 ;;; won't work; you need to temporarily select the window containing
733 ;;; the *haskell-buffer*, or else the display won't be scrolled to show
735 ;;; *** This should really position the window in the buffer so that
736 ;;; *** the point is on the last line of the window.
738 (defun haskell-display-output (str)
739 (let ((window (selected-window)))
742 (pop-to-buffer *haskell-buffer*)
743 (haskell-display-output-aux str))
744 (select-window window))))
746 (defun haskell-display-output-aux (str)
747 (haskell-move-marker)
749 (haskell-move-marker))
753 ;;; ==================================================================
754 ;;; Interactive commands
755 ;;; ==================================================================
761 ;;; This is the function that fires up the inferior haskell process.
764 "Run an inferior Haskell process with input and output via buffer *haskell*.
765 Takes the program name from the variable haskell-program-name.
766 Runs the hooks from inferior-haskell-mode-hook
767 (after the comint-mode-hook is run).
768 \(Type \\[describe-mode] in the process buffer for a list of commands.)"
770 (if (not (haskell-process-exists-p))
773 (defun start-haskell ()
774 (message "Starting haskell subprocess...")
775 ;; Kill old haskell process. Normally this routine is only called
776 ;; after checking haskell-process-exists-p, but things can get
777 ;; screwed up if you rename the *haskell* buffer while leaving the
778 ;; old process running. This forces it to get rid of the old process
779 ;; and start a new one.
780 (if (get-process "haskell")
781 (delete-process "haskell"))
782 (let ((haskell-buffer
785 (or haskell-program-name
786 (haskell-mode-error "Haskell-program-name undefined!"))
790 (set-buffer haskell-buffer)
791 (inferior-haskell-mode))
792 (haskell-session-init)
793 ;; Wait for process to get started before sending it anything
794 ;; to avoid race condition on NeXT.
795 (setq *haskell-process-alive* nil)
796 (while (not *haskell-process-alive*)
798 (haskell-send-to-process ":(use-emacs-interface)")
799 (haskell-printers-set haskell-initial-printers nil)
800 (display-buffer haskell-buffer))
801 (message "Starting haskell subprocess... Done."))
804 (defun haskell-process-exists-p ()
805 (let ((haskell-buffer (get-buffer *haskell-buffer*)))
806 (and haskell-buffer (comint-check-proc haskell-buffer))))
810 ;;; Initialize things on the emacs side, and tell haskell that it's
811 ;;; talking to emacs.
813 (defun haskell-session-init ()
814 (set-haskell-status 'busy)
815 (setq *last-loaded* nil)
816 (setq *last-module* haskell-main-module)
817 (setq *last-pad* haskell-main-pad)
818 (setq *haskell-saved-output* nil)
819 (haskell-create-main-pad)
820 (set-process-filter (get-process "haskell") 'haskell-output-filter)
824 (defun haskell-create-main-pad ()
825 (let ((buffer (get-buffer-create haskell-main-pad)))
829 (haskell-record-pad-mapping
830 haskell-main-pad haskell-main-module nil)
834 ;;; Called from evaluation and compilation commands to start up a Haskell
835 ;;; process if none is already in progress.
837 (defun haskell-maybe-create-process ()
838 (cond ((haskell-process-exists-p)
840 (haskell-auto-create-process
843 (haskell-mode-error "No Haskell process!"))))
848 ;;; ------------------------------------------------------------------
850 ;;; This always puts the pad buffer in the "other" window.
851 ;;; Having it wipe out the .hs file window is clearly the wrong
854 (defun haskell-get-pad ()
855 "Creates a new scratch pad for the current module.
856 Signals an error if the current buffer is not a .hs file."
858 (let ((fname (buffer-file-name)))
860 (do-get-pad fname (current-buffer))
861 (haskell-mode-error "Not in a .hs buffer!"))))
864 (defun do-get-pad (fname buff)
865 (let* ((mname (or (haskell-get-modname buff)
866 (read-no-blanks-input "Scratch pad for module? " nil)))
867 (pname (haskell-lookup-pad mname fname))
869 ;; Generate the base name of the pad buffer, then create the
870 ;; buffer. The actual name of the pad buffer may be something
871 ;; else because of name collisions.
874 (setq pname (format "*%s-pad*" mname))
875 (setq pbuff (generate-new-buffer pname))
876 (setq pname (buffer-name pbuff))
877 (haskell-record-pad-mapping pname mname fname)
879 (setq pbuff (get-buffer pname)))
880 ;; Make sure the pad buffer is in haskell mode.
881 (pop-to-buffer pbuff)
887 ;;; ------------------------------------------------------------------
889 (defun haskell-switch ()
890 "Switches to \*haskell\* buffer."
892 (haskell-maybe-create-process)
893 (pop-to-buffer *haskell-buffer*)
895 (goto-char (point-max)))
900 ;;; ------------------------------------------------------------------
902 (defun haskell-kill ()
903 "Kill contents of *haskell* buffer. \\[haskell-kill]"
906 (set-buffer *haskell-buffer*)
907 (beginning-of-buffer)
908 (let ((mark (point)))
910 (kill-region mark (point)))))
915 ;;; ------------------------------------------------------------------
917 (defun haskell-command (str)
918 "Format STRING as a haskell command and send it to haskell process. \\[haskell-command]"
919 (interactive "sHaskell command: ")
920 (haskell-send-to-process (format ":%s" str)))
923 ;;; HASKELL-EVAL and HASKELL-RUN
924 ;;; ------------------------------------------------------------------
926 (defun haskell-eval ()
927 "Evaluate expression in current module. \\[haskell-eval]"
929 (haskell-maybe-create-process)
930 (haskell-eval-aux (haskell-get-expression "Haskell expression: ")
933 (defun haskell-run ()
934 "Run Haskell Dialogue in current module"
936 (haskell-maybe-create-process)
937 (haskell-eval-aux (haskell-get-expression "Haskell dialogue: ")
940 (defun haskell-run-main ()
941 "Run Dialogue named main in current module"
943 (haskell-maybe-create-process)
944 (haskell-eval-aux "main" "emacs-run"))
946 (defun haskell-report-type ()
947 "Print the type of the expression."
949 (haskell-maybe-create-process)
950 (haskell-eval-aux (haskell-get-expression "Haskell expression: ")
951 "emacs-report-type"))
953 (defun haskell-eval-aux (exp fn)
954 (cond ((equal *haskell-buffer* (buffer-name))
955 ;; In the *haskell* buffer.
956 (let* ((pname *last-pad*)
957 (mname *last-module*)
958 (fname *last-loaded*))
959 (haskell-eval-aux-aux exp pname mname fname fn)))
962 (let* ((fname (buffer-file-name))
963 (mname (haskell-get-modname (current-buffer)))
964 (pname (haskell-lookup-pad mname fname)))
965 (haskell-eval-aux-aux exp pname mname fname fn)))
968 (let* ((pname (buffer-name (current-buffer)))
969 (mname (haskell-get-module-from-pad pname))
970 (fname (haskell-get-file-from-pad pname)))
971 (haskell-eval-aux-aux exp pname mname fname fn)))
974 (defun haskell-eval-aux-aux (exp pname mname fname fn)
975 (haskell-save-modified-source-files fname)
976 (haskell-send-to-process (format ":(%s" fn))
977 (haskell-send-to-process
978 (prin1-to-string exp))
979 (haskell-send-to-process
980 (prin1-to-string (or pname fname "interactive")))
981 (haskell-send-to-process
983 (if (and pname (get-buffer pname))
988 (haskell-send-to-process
989 (format "'|%s|" mname))
990 (haskell-send-to-process
992 (prin1-to-string (haskell-maybe-get-unit-file-name fname))
994 (haskell-send-to-process ")")
995 (setq *last-pad* pname)
996 (setq *last-module* mname)
997 (setq *last-loaded* fname))
1001 ;;; HASKELL-RUN-FILE, HASKELL-LOAD, HASKELL-COMPILE
1002 ;;; ------------------------------------------------------------------
1004 (defun haskell-run-file ()
1005 "Runs Dialogue named main in current file."
1007 (haskell-maybe-create-process)
1008 (let ((fname (haskell-get-file-to-operate-on)))
1009 (haskell-save-modified-source-files fname)
1010 (haskell-send-to-process ":(emacs-run-file")
1011 (haskell-send-to-process (prin1-to-string fname))
1012 (haskell-send-to-process ")")))
1014 (defun haskell-load ()
1015 "Load current file."
1017 (haskell-maybe-create-process)
1018 (let ((fname (haskell-get-file-to-operate-on)))
1019 (haskell-save-modified-source-files fname)
1020 (haskell-send-to-process ":(emacs-load-file")
1021 (haskell-send-to-process (prin1-to-string fname))
1022 (haskell-send-to-process ")")))
1024 (defun haskell-compile ()
1025 "Compile current file."
1027 (haskell-maybe-create-process)
1028 (let ((fname (haskell-get-file-to-operate-on)))
1029 (haskell-save-modified-source-files fname)
1030 (haskell-send-to-process ":(emacs-compile-file")
1031 (haskell-send-to-process (prin1-to-string fname))
1032 (haskell-send-to-process ")")))
1035 (defun haskell-get-file-to-operate-on ()
1036 (cond ((equal *haskell-buffer* (buffer-name))
1037 ;; When called from the haskell process buffer, prompt for a file.
1038 (call-interactively 'haskell-get-file/prompt))
1040 ;; When called from a .hs file buffer, use the unit file
1041 ;; associated with it, if there is one.
1042 (haskell-maybe-get-unit-file-name (buffer-file-name)))
1044 ;; When called from a pad, use the file that the module the
1045 ;; pad belongs to lives in.
1046 (haskell-maybe-get-unit-file-name
1047 (haskell-get-file-from-pad (buffer-name (current-buffer)))))))
1049 (defun haskell-get-file/prompt (filename)
1050 (interactive "fHaskell file: ")
1051 (haskell-run-file-aux filename))
1056 ;;; ------------------------------------------------------------------
1058 (defun haskell-exit ()
1059 "Quit the haskell process."
1061 (cond ((not (haskell-process-exists-p))
1062 (message "No process currently running."))
1063 ((y-or-n-p "Do you really want to quit Haskell? ")
1064 (haskell-send-to-process ":quit")
1065 ;; If we were running the tutorial, mark the temp buffer as unmodified
1066 ;; so we don't get asked about saving it later.
1067 (if (and *ht-temp-buffer*
1068 (get-buffer *ht-temp-buffer*))
1070 (set-buffer *ht-temp-buffer*)
1071 (set-buffer-modified-p nil)))
1072 ;; Try to remove the haskell output buffer from the screen.
1073 (bury-buffer *haskell-buffer*)
1074 (replace-buffer-in-windows *haskell-buffer*))
1079 ;;; HASKELL-INTERRUPT
1080 ;;; ------------------------------------------------------------------
1082 (defun haskell-interrupt ()
1083 "Interrupt the haskell process."
1085 (if (haskell-process-exists-p)
1086 (haskell-send-to-process "\C-c")))
1090 ;;; HASKELL-EDIT-UNIT
1091 ;;; ------------------------------------------------------------------
1093 (defun haskell-edit-unit ()
1094 "Edit the .hu file."
1096 (let ((fname (buffer-file-name)))
1098 (let ((find-file-not-found-hooks (list 'haskell-new-unit))
1099 (file-not-found nil)
1100 (units-fname (haskell-get-unit-file-name fname)))
1101 (find-file-other-window units-fname)
1102 ;; If creating a new file, initialize it to contain the name
1103 ;; of the haskell source file.
1107 (if (string= (file-name-directory fname)
1108 (file-name-directory units-fname))
1109 (file-name-nondirectory fname)
1112 (haskell-mode-error "Not in a .hs buffer!"))))
1114 (defun haskell-new-unit ()
1115 (setq file-not-found t))
1118 ;;; Look for a comment like "-- unit:" at top of file.
1119 ;;; If not found, assume unit file has same name as the buffer but
1120 ;;; a .hu extension.
1122 (defun haskell-get-unit-file-name (fname)
1123 (or (haskell-get-unit-file-name-from-file fname)
1124 (concat (haskell-strip-file-extension fname) ".hu")))
1126 (defun haskell-maybe-get-unit-file-name (fname)
1127 (or (haskell-get-unit-file-name-from-file fname)
1128 (haskell-strip-file-extension fname)))
1130 (defun haskell-get-unit-file-name-from-file (fname)
1131 (let ((buffer (get-file-buffer fname)))
1134 (beginning-of-buffer)
1135 (if (re-search-forward "-- unit:[ \t]*" (point-max) t)
1136 (let ((beg (match-end 0)))
1138 (buffer-substring beg (point)))
1145 ;;; ==================================================================
1146 ;;; Support for printers/optimizers menus
1147 ;;; ==================================================================
1149 ;;; This code was adapted from the standard buff-menu.el code.
1151 (defvar haskell-menu-mode-map nil "")
1153 (if (not haskell-menu-mode-map)
1155 (setq haskell-menu-mode-map (make-keymap))
1156 (suppress-keymap haskell-menu-mode-map t)
1157 (define-key haskell-menu-mode-map "m" 'hm-mark)
1158 (define-key haskell-menu-mode-map "u" 'hm-unmark)
1159 (define-key haskell-menu-mode-map "x" 'hm-exit)
1160 (define-key haskell-menu-mode-map "q" 'hm-exit)
1161 (define-key haskell-menu-mode-map " " 'next-line)
1162 (define-key haskell-menu-mode-map "\177" 'hm-backup-unmark)
1163 (define-key haskell-menu-mode-map "?" 'describe-mode)))
1165 ;; Printers Menu mode is suitable only for specially formatted data.
1167 (put 'haskell-menu-mode 'mode-class 'special)
1169 (defun haskell-menu-mode ()
1170 "Major mode for editing Haskell flags.
1171 Each line describes a flag.
1172 Letters do not insert themselves; instead, they are commands.
1173 m -- mark flag (turn it on)
1174 u -- unmark flag (turn it off)
1175 x -- exit; tell the Haskell process to update the flags, then leave menu.
1176 q -- exit; same as x.
1177 Precisely,\\{haskell-menu-mode-map}"
1178 (kill-all-local-variables)
1179 (use-local-map haskell-menu-mode-map)
1180 (setq truncate-lines t)
1181 (setq buffer-read-only t)
1182 (setq major-mode 'haskell-menu-mode)
1183 (setq mode-name "Haskell Flags Menu")
1184 ;; These are all initialized elsewhere
1185 (make-local-variable 'hm-current-flags)
1186 (make-local-variable 'hm-request-fn)
1187 (make-local-variable 'hm-update-fn)
1188 (run-hooks 'haskell-menu-mode-hook))
1191 (defun haskell-menu (help-file buffer request-fn update-fn)
1192 (haskell-maybe-create-process)
1193 (if (get-buffer buffer)
1195 (pop-to-buffer buffer)
1196 (goto-char (point-min)))
1198 (pop-to-buffer buffer)
1199 (insert-file-contents help-file)
1201 (setq hm-request-fn request-fn)
1202 (setq hm-update-fn update-fn)
1205 (message "m = mark; u = unmark; x = execute; q = quit; ? = more help."))
1209 ;;; A line that starts with *hm-marked* is a menu item turned on.
1210 ;;; A line that starts with *hm-unmarked* is turned off.
1211 ;;; A line that starts with anything else is just random text and is
1212 ;;; ignored by commands that deal with menu items.
1214 (defvar *hm-marked* " on")
1215 (defvar *hm-unmarked* " ")
1216 (defvar *hm-marked-regexp* " on \\w")
1217 (defvar *hm-unmarked-regexp* " \\w")
1220 "Mark flag to be turned on."
1223 (cond ((looking-at *hm-marked-regexp*)
1225 ((looking-at *hm-unmarked-regexp*)
1226 (let ((buffer-read-only nil))
1227 (delete-char (length *hm-unmarked*))
1228 (insert *hm-marked*)
1237 (cond ((looking-at *hm-unmarked-regexp*)
1239 ((looking-at *hm-marked-regexp*)
1240 (let ((buffer-read-only nil))
1241 (delete-char (length *hm-marked*))
1242 (insert *hm-unmarked*)
1247 (defun hm-backup-unmark ()
1248 "Move up and unmark."
1255 ;;; Actually make the changes.
1258 "Update flags, then leave menu."
1263 (defun hm-execute ()
1264 "Tell haskell process to tweak flags."
1267 (goto-char (point-min))
1268 (let ((flags-on nil)
1270 (while (not (eq (point) (point-max)))
1271 (cond ((looking-at *hm-unmarked-regexp*)
1272 (setq flags-off (cons (hm-flag) flags-off)))
1273 ((looking-at *hm-marked-regexp*)
1274 (setq flags-on (cons (hm-flag) flags-on)))
1278 (funcall hm-update-fn flags-on flags-off))))
1283 "Make the menu go away."
1284 (bury-buffer (current-buffer))
1285 (replace-buffer-in-windows (current-buffer)))
1291 (let ((beg (point)))
1292 ;; End of flag name marked by tab or two spaces.
1293 (re-search-forward "\t\\| ")
1294 (buffer-substring beg (match-beginning 0)))))
1297 ;;; Update the menu to mark only those items currently turned on.
1299 (defun hm-mark-current ()
1300 (funcall hm-request-fn)
1302 (goto-char (point-min))
1303 (while (not (eq (point) (point-max)))
1304 (cond ((and (looking-at *hm-unmarked-regexp*)
1305 (hm-item-currently-on-p (hm-flag)))
1307 ((and (looking-at *hm-marked-regexp*)
1308 (not (hm-item-currently-on-p (hm-flag))))
1311 (forward-line 1))))))
1314 ;;; See if a menu item is turned on.
1316 (defun hm-item-currently-on-p (item)
1317 (member-string= item hm-current-flags))
1319 (defun member-string= (item list)
1322 ((string= item (car list))
1325 (member-string= item (cdr list)))))
1329 ;;; Make the menu for printers.
1331 (defvar *haskell-printers-help*
1332 (concat (getenv "HASKELL") "/emacs-tools/printer-help.txt")
1333 "Help file for printers.")
1335 (defvar *haskell-printers-buffer* "*Haskell printers*")
1337 (defun haskell-printers ()
1338 "Set printers interactively."
1341 *haskell-printers-help*
1342 *haskell-printers-buffer*
1343 'haskell-printers-inquire
1344 'haskell-printers-set))
1346 (defun haskell-printers-inquire ()
1347 (setq hm-current-flags t)
1348 (haskell-send-to-process ":(emacs-send-printers)")
1349 (while (eq hm-current-flags t)
1352 (defun haskell-printers-update (data)
1353 (setq hm-current-flags (read data)))
1355 (defun haskell-printers-set (flags-on flags-off)
1356 (haskell-send-to-process ":(emacs-set-printers '")
1357 (haskell-send-to-process (prin1-to-string flags-on))
1358 (haskell-send-to-process ")"))
1361 ;;; Equivalent stuff for the optimizers menu
1363 (defvar *haskell-optimizers-help*
1364 (concat (getenv "HASKELL") "/emacs-tools/optimizer-help.txt")
1365 "Help file for optimizers.")
1367 (defvar *haskell-optimizers-buffer* "*Haskell optimizers*")
1369 (defun haskell-optimizers ()
1370 "Set optimizers interactively."
1373 *haskell-optimizers-help*
1374 *haskell-optimizers-buffer*
1375 'haskell-optimizers-inquire
1376 'haskell-optimizers-set))
1378 (defun haskell-optimizers-inquire ()
1379 (setq hm-current-flags t)
1380 (haskell-send-to-process ":(emacs-send-optimizers)")
1381 (while (eq hm-current-flags t)
1384 (defun haskell-optimizers-update (data)
1385 (setq hm-current-flags (read data)))
1387 (defun haskell-optimizers-set (flags-on flags-off)
1388 (haskell-send-to-process ":(emacs-set-optimizers '")
1389 (haskell-send-to-process (prin1-to-string flags-on))
1390 (haskell-send-to-process ")"))
1394 ;;; ==================================================================
1395 ;;; Random utilities
1396 ;;; ==================================================================
1399 ;;; Keep track of the association between pads, modules, and files.
1400 ;;; The global variable is a list of (pad-buffer-name module-name file-name)
1403 (defvar *haskell-pad-mappings* ()
1404 "Associates pads with their corresponding module and file.")
1406 (defun haskell-record-pad-mapping (pname mname fname)
1407 (setq *haskell-pad-mappings*
1408 (cons (list pname mname fname) *haskell-pad-mappings*)))
1410 (defun haskell-get-module-from-pad (pname)
1411 (car (cdr (assoc pname *haskell-pad-mappings*))))
1413 (defun haskell-get-file-from-pad (pname)
1414 (car (cdr (cdr (assoc pname *haskell-pad-mappings*)))))
1416 (defun haskell-lookup-pad (mname fname)
1417 (let ((pname (haskell-lookup-pad-aux mname fname *haskell-pad-mappings*)))
1418 (if (and pname (get-buffer pname))
1422 (defun haskell-lookup-pad-aux (mname fname list)
1425 ((and (equal mname (car (cdr (car list))))
1426 (equal fname (car (cdr (cdr (car list))))))
1429 (haskell-lookup-pad-aux mname fname (cdr list)))))
1433 ;;; Save any modified .hs and .hu files.
1434 ;;; Yes, the two set-buffer calls really seem to be necessary. It seems
1435 ;;; that y-or-n-p makes emacs forget we had temporarily selected some
1436 ;;; other buffer, and if you just do save-buffer directly it will end
1437 ;;; up trying to save the current buffer instead. The built-in
1438 ;;; save-some-buffers function has this problem....
1440 (defun haskell-save-modified-source-files (filename)
1441 (let ((buffers (buffer-list))
1444 (let ((buffer (car buffers)))
1445 (if (and (buffer-modified-p buffer)
1448 (and buffer-file-name
1449 (haskell-source-file-p buffer-file-name)
1451 (or (null haskell-ask-before-saving)
1452 (and filename (string= buffer-file-name filename))
1454 (format "Save file %s? " buffer-file-name))))))
1458 (setq buffers (cdr buffers)))
1461 (message "(No files need saving)"))))
1463 (defun haskell-source-file-p (filename)
1464 (or (string-match "\\.hs$" filename)
1465 (string-match "\\.lhs$" filename)
1466 (string-match "\\.hi$" filename)
1467 (string-match "\\.hu$" filename)))
1471 ;;; Buffer utilities
1473 (defun haskell-move-marker ()
1474 "Moves the marker and point to the end of buffer"
1475 (set-marker comint-last-input-end (point-max))
1476 (set-marker (process-mark (get-process "haskell")) (point-max))
1477 (goto-char (point-max)))
1481 ;;; Extract the name of the module the point is in, from the given buffer.
1483 (defvar *haskell-re-module-hs* "^module\\s *")
1484 (defvar *haskell-re-module-lhs* "^>\\s *module\\s *")
1485 (defvar *haskell-re-modname* "[A-Z]\\([a-z]\\|[A-Z]\\|[0-9]\\|'\\|_\\)*")
1487 (defun haskell-get-modname (buff)
1488 "Get module name in BUFFER that point is in."
1491 (let ((regexp (if (haskell-lhs-filename-p (buffer-file-name))
1492 *haskell-re-module-lhs*
1493 *haskell-re-module-hs*)))
1494 (if (or (looking-at regexp)
1495 (re-search-backward regexp (point-min) t)
1496 (re-search-forward regexp (point-max) t))
1498 (goto-char (match-end 0))
1499 (if (looking-at *haskell-re-modname*)
1500 (buffer-substring (match-beginning 0) (match-end 0))
1501 (haskell-mode-error "Module name not found!!")))
1505 ;;; Strip file extensions.
1506 ;;; Only strip off extensions we know about; e.g.
1507 ;;; "foo.hs" -> "foo" but "foo.bar" -> "foo.bar".
1509 (defvar *haskell-filename-regexp* "\\(.*\\)\\.\\(hs\\|lhs\\)$")
1511 (defun haskell-strip-file-extension (filename)
1512 "Strip off the extension from a filename."
1513 (if (string-match *haskell-filename-regexp* filename)
1514 (substring filename (match-beginning 1) (match-end 1))
1518 ;;; Is this a .lhs filename?
1520 (defun haskell-lhs-filename-p (filename)
1521 (string-match ".*\\.lhs$" filename))
1524 ;;; Haskell mode error
1526 (defun haskell-mode-error (msg)
1527 "Show MSG in message line as an error from the haskell mode."
1528 (error (concat "Haskell mode: " msg)))
1532 ;;; ==================================================================
1533 ;;; User customization
1534 ;;; ==================================================================
1536 (defvar haskell-load-hook nil
1537 "This hook is run when haskell is loaded in.
1538 This is a good place to put key bindings."
1541 (run-hooks 'haskell-load-hook)
1546 ;;;======================================================================
1547 ;;; Tutorial mode setup
1548 ;;;======================================================================
1550 ;;; Set up additional key bindings for tutorial mode.
1552 (defvar ht-mode-map (make-sparse-keymap))
1554 (haskell-establish-key-bindings ht-mode-map)
1555 (define-key ht-mode-map "\C-c\C-f" 'ht-next-page)
1556 (define-key ht-mode-map "\C-c\C-b" 'ht-prev-page)
1557 (define-key ht-mode-map "\C-c\C-l" 'ht-restore-page)
1558 (define-key ht-mode-map "\C-c?" 'describe-mode)
1560 (defun haskell-tutorial-mode ()
1561 "Major mode for running the Haskell tutorial.
1562 You can use these commands:
1565 (kill-all-local-variables)
1566 (use-local-map ht-mode-map)
1567 (setq major-mode 'haskell-tutorial-mode)
1568 (setq mode-name "Haskell Tutorial")
1569 (set-syntax-table haskell-mode-syntax-table)
1570 (run-hooks 'haskell-mode-hook))
1573 (defun haskell-tutorial ()
1574 "Run the haskell tutorial."
1579 (haskell-maybe-create-process)
1580 (haskell-send-to-process ":(emacs-set-printers '(interactive))")
1584 ;;; Load the tutorial file into a read-only buffer. Do not display this
1587 (defun ht-load-tutorial ()
1588 (let ((buffer (get-buffer *ht-file-buffer*)))
1592 (beginning-of-buffer))
1594 (set-buffer (setq buffer (get-buffer-create *ht-file-buffer*)))
1595 (let ((fname (substitute-in-file-name *ht-source-file*)))
1596 (if (file-readable-p fname)
1597 (ht-load-tutorial-aux fname)
1598 (call-interactively 'ht-load-tutorial-aux)))))))
1600 (defun ht-load-tutorial-aux (filename)
1601 (interactive "fTutorial file: ")
1602 (insert-file filename)
1603 (set-buffer-modified-p nil)
1604 (setq buffer-read-only t)
1605 (beginning-of-buffer))
1608 ;;; Create a buffer to use for messing about with each page of the tutorial.
1609 ;;; Put the buffer into haskell-tutorial-mode.
1611 (defun ht-make-buffer ()
1612 (find-file (concat "/tmp/" (make-temp-name "ht") ".lhs"))
1613 (setq *ht-temp-buffer* (buffer-name))
1614 (haskell-tutorial-mode))
1617 ;;; Commands for loading text into the tutorial pad buffer
1619 (defun ht-next-page ()
1620 "Go to the next tutorial page."
1622 (if (ht-goto-next-page)
1626 (defun ht-goto-next-page ()
1627 (let ((buff (current-buffer)))
1630 (set-buffer *ht-file-buffer*)
1631 (search-forward "\C-l" nil t))
1632 (set-buffer buff))))
1634 (defun ht-prev-page ()
1635 "Go to the previous tutorial page."
1637 (if (ht-goto-prev-page)
1641 (defun ht-goto-prev-page ()
1642 (let ((buff (current-buffer)))
1645 (set-buffer *ht-file-buffer*)
1646 (search-backward "\C-l" nil t))
1647 (set-buffer buff))))
1649 (defun ht-goto-page (arg)
1650 "Go to the tutorial page specified as the argument."
1651 (interactive "sGo to page: ")
1652 (if (ht-searchfor-page (format "Page: %s " arg))
1656 (defun ht-goto-section (arg)
1657 "Go to the tutorial section specified as the argument."
1658 (interactive "sGo to section: ")
1659 (if (ht-searchfor-page (format "Section: %s " arg))
1663 (defun ht-searchfor-page (search-string)
1664 (let ((buff (current-buffer)))
1667 (set-buffer *ht-file-buffer*)
1668 (let ((point (point)))
1669 (beginning-of-buffer)
1670 (if (search-forward search-string nil t)
1675 (set-buffer buff))))
1677 (defun ht-restore-page ()
1679 (let ((old-point (point)))
1681 (goto-char old-point)))
1683 (defun ht-display-page ()
1684 (set-buffer *ht-file-buffer*)
1686 (if (search-backward "\C-l" nil t)
1688 (beginning-of-buffer))
1691 (if (search-forward "\C-l" nil t)
1695 (text (buffer-substring beg end)))
1696 (set-buffer *ht-temp-buffer*)
1699 (beginning-of-buffer)))
1703 ;;;======================================================================
1705 ;;;======================================================================
1707 ;;; This only works in Emacs version 19, so it's in a separate file for now.
1709 (if (featurep 'menu-bar)
1710 (load-library "haskell-menu"))