1 ;;; ==================================================================
2 ;;; File: haskell.el ;;;
4 ;;; Author: A. Satish Pai ;;;
5 ;;; Maria M. Gutierrez ;;;
6 ;;; Dan Rabin (Jul-1991) ;;;
7 ;;; ==================================================================
8 ;;; Time-stamp: <Sat Oct 7 1995 17:48:39 Stardate: [-31]6403.50 hwloidl>
9 ;;; ==================================================================
11 ;;; extended by Manuel M.T. Chakravarty with rudimentary editing features
12 ;;; (including better syntax table) and support for the font-lock-mode;
13 ;;; changes are marked with !chak!
15 ;;; using this mode on a 19.x Emacs running under a window system automagically
16 ;;; applies the font-lock-mode; this feature can be switched off by setting
17 ;;; `haskell-auto-font-lock' to `nil'
19 ;;; Description: Haskell mode for GNU Emacs.
21 ;;; Related files: comint.el
27 ;;; Known bugs / problems
28 ;;; - the haskell editing mode (indentation, etc) is still missing.
29 ;;; - the handling for errors from haskell needs to be rethought.
30 ;;; - general cleanup of code.
35 ;;; ==================================================================
36 ;;; Haskell mode for editing files, and an Inferior Haskell mode to
37 ;;; run a Haskell process. This file contains stuff snarfed and
38 ;;; modified from tea.el, scheme.el, etc. This file may be freely
39 ;;; modified; however, if you have any bug-corrections or useful
40 ;;; improvements, I'd appreciate it if you sent me the mods so that
41 ;;; I can merge them into the version I maintain.
43 ;;; The inferior Haskell mode requires comint.el.
45 ;;; You might want to add this to your .emacs to go automagically
46 ;;; into Haskell mode while finding .hs files.
48 ;;; (setq auto-mode-alist
49 ;;; (cons '("\\.hs$" . haskell-mode)
50 ;;; auto-mode-alist)_)
52 ;;; To use this file, set up your .emacs to autoload this file for
53 ;;; haskell-mode. For example:
55 ;;; (autoload 'haskell-mode "$HASKELL/emacs-tools/haskell.elc"
56 ;;; "Load Haskell mode" t)
58 ;;; (autoload 'run-mode "$HASKELL/emacs-tools/haskell.elc"
59 ;;; "Load Haskell mode" t)
61 ;;; [Note: The path name given above is Yale specific!! Modify as
63 ;;; ================================================================
65 ;;; Announce your existence to the world at large.
70 ;;; Load these other files.
72 (require 'comint) ; Olin Shivers' comint mode is the substratum
76 (if (and window-system (string-match "19." emacs-version))
81 ;;; ================================================================
82 ;;; Declare a bunch of variables.
83 ;;; ================================================================
86 ;;; User settable (via M-x set-variable and M-x edit-options)
88 (defvar haskell-program-name (getenv "HASKELLPROG")
89 "*Program invoked by the haskell command.")
91 (defvar haskell-auto-create-process t
92 "*If not nil, create a Haskell process automatically when required to evaluate or compile Haskell code.")
94 (defvar haskell-auto-switch-input t
95 "*If not nil, jump to *haskell* buffer automatically on input request.")
97 (defvar haskell-ask-before-saving t
98 "*If not nil, ask before saving random haskell-mode buffers.")
100 (defvar haskell-initial-printers '("interactive")
101 "*Printers to set when starting a new Haskell process.")
104 ;;; Pad/buffer Initialization variables
106 (defvar *haskell-buffer* "*haskell*"
107 "Name of the haskell process buffer")
109 (defvar haskell-main-pad "\*Main-pad\*"
110 "Scratch pad associated with module Main")
112 (defvar haskell-main-module "Main")
115 (defvar *last-loaded* nil)
116 (defvar *last-module* haskell-main-module)
117 (defvar *last-pad* haskell-main-pad)
120 ;;; These are used for haskell-tutorial mode.
122 (defvar *ht-source-file* "$HASKELL/progs/tutorial/tutorial.lhs")
123 (defvar *ht-temp-buffer* nil)
124 (defvar *ht-file-buffer* "Haskell-Tutorial-Master")
126 ;;; !chak! variables for font-lock-mode support
129 (defvar haskell-auto-font-lock t
130 "Use font-lock-mode by default.")
132 (defvar haskell-font-lock-keywords
134 "\\bcase\\b" "\\bclass\\b" "\\bdata\\b" "\\bdefault\\b" "\\bderiving\\b"
135 "\\belse\\b" "\\bhiding\\b" "\\bif\\b" "\\bimport\\b" "\\bin\\b"
136 "\\binfix\\b" "\\binfixl\\b" "\\binfixr\\b" "\\binstance\\b"
137 "\\binterface\\b" "\\blet\\b" "\\bmodule\\b" "\\bof\\b" "\\brenaming\\b"
138 "\\bthen\\b" "\\bto\\b" "\\btype\\b" "\\bwhere\\b"
139 ;'("\\S_\\(\\.\\.\\|::\\|=>\\|=\\|@\\||\\|~\\|-\\|<-\\|->\\)\\S_" . 1)
140 '("\\bdata\\b\\s *\\(\\w+\\)\\(\\w\\|\\s \\)*=[^>]" 1 font-lock-type-face)
141 '("\\bdata\\b\\(\\s \\|(\\|)\\|\\w\\)*=>\\s *\n?\\s *\\(\\w+\\)" 2
143 '("\\btype\\b\\s *\\(\\w+\\)" 1 font-lock-type-face)
144 '("\\(\\w+\\)\\s *::\\(\\s \\|$\\)" 1 font-lock-function-name-face)
145 '("(\\(\\s_+\\))\\s *::\\(\\s \\|$\\)" 1 font-lock-function-name-face)
146 ; '("\\($\\|[^\\\\]\\)\\('[^\\\\]'\\)" 2 font-lock-string-face t)
147 '("\\('\\([^\\\\]\\|\\\\'\\)'\\)" 1 font-lock-string-face t)
149 "Additional expressions to highlight in Haskell mode.")
153 ;;; ================================================================
154 ;;; Haskell editing mode stuff
155 ;;; ================================================================
157 ;;; Leave this place alone...
158 ;;; The definitions below have been pared down to the bare
159 ;;; minimum; they will be restored later.
163 ;;; Keymap for Haskell mode
164 (defvar haskell-mode-map (make-sparse-keymap)
165 "Keymap used for haskell-mode")
167 (defun haskell-establish-key-bindings (keymap)
168 (define-key keymap "\C-ce" 'haskell-eval)
169 (define-key keymap "\C-cr" 'haskell-run)
170 (define-key keymap "\C-ct" 'haskell-report-type)
171 (define-key keymap "\C-cm" 'haskell-run-main)
172 (define-key keymap "\C-c\C-r" 'haskell-run-file)
173 (define-key keymap "\C-cp" 'haskell-get-pad)
174 (define-key keymap "\C-c\C-o" 'haskell-optimizers)
175 (define-key keymap "\C-c\C-p" 'haskell-printers)
176 (define-key keymap "\C-cc" 'haskell-compile)
177 (define-key keymap "\C-cl" 'haskell-load)
178 (define-key keymap "\C-ch" 'haskell-switch)
179 (define-key keymap "\C-c\C-k" 'haskell-kill)
180 (define-key keymap "\C-c:" 'haskell-command)
181 (define-key keymap "\C-cq" 'haskell-exit)
182 (define-key keymap "\C-ci" 'haskell-interrupt)
183 (define-key keymap "\C-cu" 'haskell-edit-unit))
186 (haskell-establish-key-bindings haskell-mode-map)
189 (defvar haskell-mode-syntax-table nil
190 "Syntax table used for haskell-mode")
192 ;; !chak! taken from lisp-mode
194 (defvar haskell-mode-abbrev-table nil
195 "Abbrev table used for the haskell-mode")
197 ;; !chak! took syntax table from haskell mode distributed with GHC and modified
198 ;; it; we treat numbers as parts of words and operators as elements of
199 ;; the syntactic class `_'
201 (if haskell-mode-syntax-table
204 (setq haskell-mode-syntax-table (make-syntax-table))
206 (modify-syntax-entry i "." haskell-mode-syntax-table)
209 (modify-syntax-entry i "w" haskell-mode-syntax-table)
212 (modify-syntax-entry i "." haskell-mode-syntax-table)
215 (modify-syntax-entry i "w" haskell-mode-syntax-table)
218 (modify-syntax-entry i "." haskell-mode-syntax-table)
221 (modify-syntax-entry i "w" haskell-mode-syntax-table)
224 (modify-syntax-entry i "." haskell-mode-syntax-table)
226 (modify-syntax-entry ? " " haskell-mode-syntax-table)
227 (modify-syntax-entry ?\t " " haskell-mode-syntax-table)
228 (modify-syntax-entry ?\n ">" haskell-mode-syntax-table)
229 (modify-syntax-entry ?\f ">" haskell-mode-syntax-table)
230 (modify-syntax-entry ?! "_" haskell-mode-syntax-table)
231 (modify-syntax-entry ?# "_" haskell-mode-syntax-table)
232 (modify-syntax-entry ?$ "_" haskell-mode-syntax-table)
233 (modify-syntax-entry ?% "_" haskell-mode-syntax-table)
234 (modify-syntax-entry ?& "_" haskell-mode-syntax-table)
235 (modify-syntax-entry ?* "_" haskell-mode-syntax-table)
236 (modify-syntax-entry ?+ "_" haskell-mode-syntax-table)
237 (modify-syntax-entry ?. "_" haskell-mode-syntax-table)
238 (modify-syntax-entry ?/ "_" haskell-mode-syntax-table)
239 (modify-syntax-entry ?< "_" haskell-mode-syntax-table)
240 (modify-syntax-entry ?= "_" haskell-mode-syntax-table)
241 (modify-syntax-entry ?> "_" haskell-mode-syntax-table)
242 (modify-syntax-entry ?? "_" haskell-mode-syntax-table)
243 (modify-syntax-entry ?@ "_" haskell-mode-syntax-table)
244 (modify-syntax-entry ?^ "_" haskell-mode-syntax-table)
245 (modify-syntax-entry ?| "_" haskell-mode-syntax-table)
246 (modify-syntax-entry ?~ "_" haskell-mode-syntax-table)
247 (modify-syntax-entry ?\" "\"" haskell-mode-syntax-table)
248 (modify-syntax-entry ?\' "w" haskell-mode-syntax-table)
249 (modify-syntax-entry ?_ "w" haskell-mode-syntax-table)
250 (modify-syntax-entry ?\\ "_" haskell-mode-syntax-table)
251 (modify-syntax-entry ?\( "()" haskell-mode-syntax-table)
252 (modify-syntax-entry ?\) ")(" haskell-mode-syntax-table)
253 (modify-syntax-entry ?\[ "(]" haskell-mode-syntax-table)
254 (modify-syntax-entry ?\] ")[" haskell-mode-syntax-table)
255 (modify-syntax-entry ?{ "(}1" haskell-mode-syntax-table)
256 (modify-syntax-entry ?} "){4" haskell-mode-syntax-table)
257 (modify-syntax-entry ?- "_ 123" haskell-mode-syntax-table)
260 ;; !chak! taken from lisp-mode
262 (define-abbrev-table 'haskell-mode-abbrev-table ())
264 ;; !chak! adapted from lisp-mode
266 (defun haskell-mode-variables (haskell-syntax)
267 (cond (haskell-syntax
268 (set-syntax-table haskell-mode-syntax-table)))
269 (setq local-abbrev-table haskell-mode-abbrev-table)
270 (make-local-variable 'paragraph-start)
271 (setq paragraph-start (concat "^$\\|" page-delimiter))
272 (make-local-variable 'paragraph-separate)
273 (setq paragraph-separate paragraph-start)
274 (make-local-variable 'paragraph-ignore-fill-prefix)
275 (setq paragraph-ignore-fill-prefix t)
276 (make-local-variable 'indent-line-function)
277 (setq indent-line-function 'haskell-indent-line)
278 ; (make-local-variable 'indent-region-function)
279 ; (setq indent-region-function 'haskell-indent-region)
280 (make-local-variable 'parse-sexp-ignore-comments)
281 (setq parse-sexp-ignore-comments t)
282 ; (make-local-variable 'outline-regexp)
283 ; (setq outline-regexp ";;; \\|(....")
284 (make-local-variable 'comment-start)
285 (setq comment-start "--")
286 (make-local-variable 'comment-start-skip)
287 (setq comment-start-skip "-- *")
288 (make-local-variable 'comment-column)
289 (setq comment-column 40)
290 ; (make-local-variable 'comment-indent-function)
291 ; (setq comment-indent-function 'haskell-comment-indent)
292 (make-local-variable 'font-lock-keywords)
293 (setq font-lock-keywords haskell-font-lock-keywords)
298 (defun haskell-indent-line ()
299 "Simple indentation function using `indent-relative'."
303 (delete-horizontal-space)
308 ;;; Command for invoking the Haskell mode
309 (defun haskell-mode nil
310 "Major mode for editing Haskell code to run in Emacs
311 The following commands are available:
314 A Haskell process can be fired up with \"M-x haskell\".
316 Customization: Entry to this mode runs the hooks that are the value of variable
321 There are 3 types of windows associated with Haskell mode. They are:
322 *haskell*: which is the process window.
323 Pad: which are buffers available for each module. It is here
324 where you want to test things before preserving them in a
325 file. Pads are always associated with a module.
326 When issuing a command:
327 The pad and its associated module are sent to the Haskell
328 process prior to the execution of the command.
329 .hs: These are the files where Haskell programs live. They
330 have .hs as extension.
331 When issuing a command:
332 The file is sent to the Haskell process prior to the
333 execution of the command.
337 Each command behaves differently according to the type of the window in which
338 the cursor is positioned when the command is issued .
340 haskell-eval: \\[haskell-eval]
341 Always promts user for a Haskell expression to be evaluated. If in a
342 .hs file buffer, then the cursor tells which module is the current
343 module and the pad for that module (if any) gets loaded as well.
345 haskell-run: \\[haskell-run]
346 Always queries for a variable of type Dialogue to be evaluated.
348 haskell-run-main: \\[haskell-run-main]
349 Run Dialogue named main in the current module.
351 haskell-report-type: \\[haskell-report-type]
352 Like haskell-eval, but prints the type of the expression without
355 haskell-mode: \\[haskell-mode]
356 Puts the current buffer in haskell mode.
358 haskell-compile: \\[haskell-compile]
359 Compiles file in current buffer.
361 haskell-load: \\[haskell-load]
362 Loads file in current buffer.
364 haskell-run-file: \\[haskell-run-file]
365 Runs file in the current buffer.
367 haskell-pad: \\[haskell-pad]
368 Creates a scratch pad for the current module.
370 haskell-optimizers: \\[haskell-optimizers]
371 Shows the list of available optimizers. Commands for turning them on/off.
373 haskell-printers: \\[haskell-printers]
374 Shows the list of available printers. Commands for turning them on/off.
376 haskell-command: \\[haskell-command]
377 Prompts for a command to be sent to the command interface. You don't
378 need to put the : before the command.
380 haskell-quit: \\[haskell-quit]
381 Terminates the haskell process.
383 haskell-switch: \\[haskell-switch]
384 Switches to the inferior Haskell buffer (*haskell*) and positions the
385 cursor at the end of the buffer.
387 haskell-kill: \\[haskell-kill]
388 Kill the current contents of the *haskell* buffer.
390 haskell-interrupt: \\[haskell-interrupt]
391 Interrupts haskell process and resets it.
393 haskell-edit-unit: \\[haskell-edit-unit]
394 Edit the .hu file for the unit containing this file.
397 (kill-all-local-variables)
398 (use-local-map haskell-mode-map)
399 (setq major-mode 'haskell-mode)
400 (setq mode-name "Haskell")
401 (make-local-variable 'indent-line-function)
402 (setq indent-line-function 'indent-relative-maybe)
403 ;(setq local-abbrev-table haskell-mode-abbrev-table)
404 (set-syntax-table haskell-mode-syntax-table)
405 ;(setq tab-stop-list haskell-tab-stop-list) ;; save old list??
406 (haskell-mode-variables t) ; !chak!
407 (cond (haskell-auto-font-lock ; !chak!
408 (font-lock-mode 1) ; !chak!
410 (run-hooks 'haskell-mode-hook))
414 ;;;================================================================
415 ;;; Inferior Haskell stuff
416 ;;;================================================================
419 (defvar inferior-haskell-mode-map (copy-keymap comint-mode-map))
421 (haskell-establish-key-bindings inferior-haskell-mode-map)
422 (define-key inferior-haskell-mode-map "\C-m" 'haskell-send-input)
424 (defvar haskell-source-modes '(haskell-mode)
425 "*Used to determine if a buffer contains Haskell source code.
426 If it's loaded into a buffer that is in one of these major modes,
427 it's considered a Haskell source file.")
429 (defvar haskell-prompt-pattern "^[A-Z]\\([A-Z]\\|[a-z]\\|[0-9]\\)*>\\s-*"
430 "Regular expression capturing the Haskell system prompt.")
432 (defvar haskell-prompt-ring ()
433 "Keeps track of input to haskell process from the minibuffer")
435 (defun inferior-haskell-mode-variables ()
439 ;;; INFERIOR-HASKELL-MODE (adapted from comint.el)
441 (defun inferior-haskell-mode ()
442 "Major mode for interacting with an inferior Haskell process.
444 The following commands are available:
445 \\{inferior-haskell-mode-map}
447 A Haskell process can be fired up with \"M-x haskell\".
449 Customization: Entry to this mode runs the hooks on comint-mode-hook and
450 inferior-haskell-mode-hook (in that order).
452 You can send text to the inferior Haskell process from other buffers containing
458 There are 3 types of windows in the inferior-haskell-mode. They are:
459 *haskell*: which is the process window.
460 Pad: which are buffers available for each module. It is here
461 where you want to test things before preserving them in a
462 file. Pads are always associated with a module.
463 When issuing a command:
464 The pad and its associated module are sent to the Haskell
465 process prior to the execution of the command.
466 .hs: These are the files where Haskell programs live. They
467 have .hs as extension.
468 When issuing a command:
469 The file is sent to the Haskell process prior to the
470 execution of the command.
474 Each command behaves differently according to the type of the window in which
475 the cursor is positioned when the command is issued.
477 haskell-eval: \\[haskell-eval]
478 Always promts user for a Haskell expression to be evaluated. If in a
479 .hs file, then the cursor tells which module is the current module and
480 the pad for that module (if any) gets loaded as well.
482 haskell-run: \\[haskell-run]
483 Always queries for a variable of type Dialogue to be evaluated.
485 haskell-run-main: \\[haskell-run-main]
486 Run Dialogue named main.
488 haskell-report-type: \\[haskell-report-type]
489 Like haskell-eval, but prints the type of the expression without
492 haskell-mode: \\[haskell-mode]
493 Puts the current buffer in haskell mode.
495 haskell-compile: \\[haskell-compile]
496 Compiles file in current buffer.
498 haskell-load: \\[haskell-load]
499 Loads file in current buffer.
501 haskell-run-file: \\[haskell-run-file]
502 Runs file in the current buffer.
504 haskell-pad: \\[haskell-pad]
505 Creates a scratch pad for the current module.
507 haskell-optimizers: \\[haskell-optimizers]
508 Shows the list of available optimizers. Commands for turning them on/off.
510 haskell-printers: \\[haskell-printers]
511 Shows the list of available printers. Commands for turning them on/off.
513 haskell-command: \\[haskell-command]
514 Prompts for a command to be sent to the command interface. You don't
515 need to put the : before the command.
517 haskell-quit: \\[haskell-quit]
518 Terminates the haskell process.
520 haskell-switch: \\[haskell-switch]
521 Switches to the inferior Haskell buffer (*haskell*) and positions the
522 cursor at the end of the buffer.
524 haskell-kill: \\[haskell-kill]
525 Kill the current contents of the *haskell* buffer.
527 haskell-interrupt: \\[haskell-interrupt]
528 Interrupts haskell process and resets it.
530 haskell-edit-unit: \\[haskell-edit-unit]
531 Edit the .hu file for the unit containing this file.
533 The usual comint functions are also available. In particular, the
534 following are all available:
536 comint-bol: Beginning of line, but skip prompt. Bound to C-a by default.
537 comint-delchar-or-maybe-eof: Delete char, unless at end of buffer, in
538 which case send EOF to process. Bound to C-d by default.
540 Note however, that the default keymap bindings provided shadow some of
541 the default comint mode bindings, so that you may want to bind them
542 to your choice of keys.
544 Comint mode's dynamic completion of filenames in the buffer is available.
545 (Q.v. comint-dynamic-complete, comint-dynamic-list-completions.)
547 If you accidentally suspend your process, use \\[comint-continue-subjob]
552 (setq comint-prompt-regexp haskell-prompt-pattern)
553 ;; Customise in inferior-haskell-mode-hook
554 (inferior-haskell-mode-variables)
555 (setq major-mode 'inferior-haskell-mode)
556 (setq mode-name "Inferior Haskell")
557 (setq mode-line-process '(": %s : busy"))
558 (use-local-map inferior-haskell-mode-map)
559 (setq comint-input-filter 'haskell-input-filter)
560 (setq comint-input-sentinel 'ignore)
561 (setq comint-get-old-input 'haskell-get-old-input)
562 (run-hooks 'inferior-haskell-mode-hook)
563 ;Do this after the hook so the user can mung INPUT-RING-SIZE w/his hook.
564 ;The test is so we don't lose history if we run comint-mode twice in
566 (setq haskell-prompt-ring (make-ring comint-input-ring-size)))
569 (defun haskell-input-filter (str)
570 "Don't save whitespace."
571 (not (string-match "\\s *" str)))
575 ;;; ==================================================================
577 ;;; ==================================================================
580 ;;; This keeps track of the status of the haskell process.
582 ;;; busy -- The process is busy.
583 ;;; ready -- The process is ready for a command.
584 ;;; input -- The process is waiting for input.
585 ;;; debug -- The process is in the debugger.
587 (defvar *haskell-status* 'busy
588 "Status of the haskell process")
590 (defun set-haskell-status (value)
591 (setq *haskell-status* value)
592 (haskell-update-mode-line))
594 (defun get-haskell-status ()
597 (defun haskell-update-mode-line ()
599 (set-buffer *haskell-buffer*)
600 (cond ((eq *haskell-status* 'ready)
601 (setq mode-line-process '(": %s: ready")))
602 ((eq *haskell-status* 'input)
603 (setq mode-line-process '(": %s: input")))
604 ((eq *haskell-status* 'busy)
605 (setq mode-line-process '(": %s: busy")))
606 ((eq *haskell-status* 'debug)
607 (setq mode-line-process '(": %s: debug")))
609 (haskell-mode-error "Confused about status of haskell process!")))
610 ;; Yes, this is the officially sanctioned technique for forcing
611 ;; a redisplay of the mode line.
612 (set-buffer-modified-p (buffer-modified-p))))
615 (defun haskell-send-to-process (string)
616 (process-send-string "haskell" string)
617 (process-send-string "haskell" "\n"))
621 ;;; ==================================================================
622 ;;; Handle input in haskell process buffer; history commands.
623 ;;; ==================================================================
625 (defun haskell-get-old-input ()
626 "Get old input text from Haskell process buffer."
628 (if (re-search-forward haskell-prompt-pattern (point-max) 'move)
629 (goto-char (match-beginning 0)))
630 (cond ((re-search-backward haskell-prompt-pattern (point-min) t)
632 (let ((temp (point)))
634 (buffer-substring temp (point)))))))
637 (defun haskell-send-input ()
638 "Send input to Haskell while in the process buffer"
640 (if (eq (get-haskell-status) 'debug)
642 (haskell-send-input-aux)))
644 (defun haskell-send-input-aux ()
645 ;; Note that the input string does not include its terminal newline.
646 (let ((proc (get-buffer-process (current-buffer))))
648 (haskell-mode-error "Current buffer has no process!")
649 (let* ((pmark (process-mark proc))
650 (pmark-val (marker-position pmark))
651 (input (if (>= (point) pmark-val)
652 (buffer-substring pmark (point))
653 (let ((copy (funcall comint-get-old-input)))
658 (if (funcall comint-input-filter input)
659 (ring-insert input-ring input))
660 (funcall comint-input-sentinel input)
661 (set-marker (process-mark proc) (point))
662 (set-marker comint-last-input-end (point))
663 (haskell-send-to-process input)))))
667 ;;; ==================================================================
668 ;;; Minibuffer input stuff
669 ;;; ==================================================================
671 ;;; Haskell input history retrieval commands (taken from comint.el)
672 ;;; M-p -- previous input M-n -- next input
674 (defvar haskell-minibuffer-local-map nil
675 "Local map for minibuffer when in Haskell")
677 (if haskell-minibuffer-local-map
680 (setq haskell-minibuffer-local-map
681 (copy-keymap minibuffer-local-map))
683 (define-key haskell-minibuffer-local-map "\ep" 'haskell-previous-input)
684 (define-key haskell-minibuffer-local-map "\en" 'haskell-next-input)
687 (defun haskell-previous-input (arg)
688 "Cycle backwards through input history."
690 (let ((len (ring-length haskell-prompt-ring)))
692 (message "Empty input ring.")
695 (cond ((eq last-command 'haskell-previous-input)
696 (delete-region (mark) (point))
699 (setq input-ring-index
702 (push-mark (point))))
703 (setq input-ring-index (comint-mod (+ input-ring-index arg) len))
704 (insert (ring-ref haskell-prompt-ring input-ring-index))
705 (setq this-command 'haskell-previous-input))
708 (defun haskell-next-input (arg)
709 "Cycle forwards through input history."
711 (haskell-previous-input (- arg)))
713 (defvar haskell-last-input-match ""
714 "Last string searched for by Haskell input history search, for defaulting.
715 Buffer local variable.")
717 (defun haskell-previous-input-matching (str)
718 "Searches backwards through input history for substring match"
719 (interactive (let ((s (read-from-minibuffer
720 (format "Command substring (default %s): "
721 haskell-last-input-match))))
722 (list (if (string= s "") haskell-last-input-match s))))
723 (setq haskell-last-input-match str) ; update default
724 (let ((str (regexp-quote str))
725 (len (ring-length haskell-prompt-ring))
727 (while (and (<= n len)
728 (not (string-match str (ring-ref haskell-prompt-ring n))))
730 (cond ((<= n len) (haskell-previous-input (+ n 1)))
731 (t (haskell-mode-error "Not found.")))))
734 ;;; Actually read an expression from the minibuffer using the new keymap.
736 (defun haskell-get-expression (prompt)
737 (let ((exp (read-from-minibuffer prompt nil haskell-minibuffer-local-map)))
738 (ring-insert haskell-prompt-ring exp)
743 ;;; ==================================================================
744 ;;; Handle output from Haskell process
745 ;;; ==================================================================
747 ;;; The haskell process produces output with embedded control codes.
748 ;;; These control codes are used to keep track of what kind of input
749 ;;; the haskell process is expecting. Ordinary output is just displayed.
751 ;;; This is kind of complicated because control sequences can be broken
752 ;;; across multiple batches of text received from the haskell process.
753 ;;; If the string ends in the middle of a control sequence, save it up
754 ;;; for the next call.
756 (defvar *haskell-saved-output* nil)
758 ;;; On the Next, there is some kind of race condition that causes stuff
759 ;;; sent to the Haskell subprocess before it has really started to be lost.
760 ;;; The point of this variable is to force the Emacs side to wait until
761 ;;; Haskell has started and printed out its banner before sending it
762 ;;; anything. See start-haskell below.
764 (defvar *haskell-process-alive* nil)
766 (defun haskell-output-filter (process str)
767 "Filter for output from Yale Haskell command interface"
769 ;;(let ((buffer (get-buffer-create "haskell-output")))
771 ;; (set-buffer buffer)
773 (setq *haskell-process-alive* t)
779 ;; If there was saved output from last time, glue it in front of the
780 ;; newly received input.
781 (if *haskell-saved-output*
783 (setq str (concat *haskell-saved-output* str))
784 (setq *haskell-saved-output* nil)))
785 ;; Loop, looking for complete command sequences.
786 ;; Set next to point to the first one.
787 ;; start points to first character to be processed.
789 (string-match *haskell-message-match-regexp*
791 ;; Display any intervening ordinary text.
792 (if (not (eq next start))
793 (haskell-display-output (substring str start next)))
794 ;; Now dispatch on the particular command sequence found.
795 ;; Handler functions are called with the string and start index
796 ;; as arguments, and should return the index of the "next"
798 (let ((end (match-end 0)))
799 (haskell-handle-message str next)
801 ;; Look to see whether the string ends with an incomplete
803 ;; If so, save the tail of the string for next time.
805 (string-match *haskell-message-prefix-regexp* str start))
806 (eq (match-end 0) (length str)))
807 (setq *haskell-saved-output* (substring str next))
808 (setq next (length str)))
809 ;; Display any leftover ordinary text.
810 (if (not (eq next start))
811 (haskell-display-output (substring str start next))))
812 (store-match-data data))))
814 (defvar *haskell-message-match-regexp*
817 (defvar *haskell-message-prefix-regexp*
818 "E\\(M\\(A\\(C\\(S\\(:.*\\)?\\)?\\)?\\)?\\)?")
820 (defvar *haskell-message-dispatch*
821 '(("EMACS:debug\n" . haskell-got-debug)
822 ("EMACS:busy\n" . haskell-got-busy)
823 ("EMACS:input\n" . haskell-got-input)
824 ("EMACS:ready\n" . haskell-got-ready)
825 ("EMACS:printers .*\n" . haskell-got-printers)
826 ("EMACS:optimizers .*\n" . haskell-got-optimizers)
827 ("EMACS:message .*\n" . haskell-got-message)
828 ("EMACS:error\n" . haskell-got-error)
831 (defun haskell-handle-message (str idx)
832 (let ((list *haskell-message-dispatch*)
834 (while (and list (null fn))
835 (if (eq (string-match (car (car list)) str idx) idx)
836 (setq fn (cdr (car list)))
837 (setq list (cdr list))))
839 (haskell-mode-error "Garbled message from Haskell!")
840 (let ((end (match-end 0)))
841 (funcall fn str idx end)
845 (defun haskell-message-data (string start end)
846 (let ((real-start (+ (string-match " " string start) 1))
847 (real-end (- end 1)))
848 (substring string real-start real-end)))
850 (defun haskell-got-debug (string start end)
852 (message "In the debugger!")
853 (set-haskell-status 'debug))
855 (defun haskell-got-busy (string start end)
856 (set-haskell-status 'busy))
858 (defun haskell-got-input (string start end)
859 (if haskell-auto-switch-input
863 (set-haskell-status 'input)
864 (message "Waiting for input..."))
866 (defun haskell-got-ready (string start end)
867 (set-haskell-status 'ready))
869 (defun haskell-got-printers (string start end)
870 (haskell-printers-update (haskell-message-data string start end)))
872 (defun haskell-got-optimizers (string start end)
873 (haskell-optimizers-update (haskell-message-data string start end)))
875 (defun haskell-got-message (string start end)
876 (message "%s" (haskell-message-data string start end)))
878 (defun haskell-got-error (string start end)
879 ; [[!chak! I found that annoying]] (beep)
880 (message "Haskell error."))
883 ;;; Displays output at end of given buffer.
884 ;;; This function only ensures that the output is visible, without
885 ;;; selecting the buffer in which it is displayed.
886 ;;; Note that just using display-buffer instead of all this rigamarole
887 ;;; won't work; you need to temporarily select the window containing
888 ;;; the *haskell-buffer*, or else the display won't be scrolled to show
890 ;;; *** This should really position the window in the buffer so that
891 ;;; *** the point is on the last line of the window.
893 (defun haskell-display-output (str)
894 (let ((window (selected-window)))
897 (pop-to-buffer *haskell-buffer*)
898 (haskell-display-output-aux str))
899 (select-window window))))
901 (defun haskell-display-output-aux (str)
902 (haskell-move-marker)
904 (haskell-move-marker))
908 ;;; ==================================================================
909 ;;; Interactive commands
910 ;;; ==================================================================
916 ;;; This is the function that fires up the inferior haskell process.
919 "Run an inferior Haskell process with input and output via buffer *haskell*.
920 Takes the program name from the variable haskell-program-name.
921 Runs the hooks from inferior-haskell-mode-hook
922 (after the comint-mode-hook is run).
923 \(Type \\[describe-mode] in the process buffer for a list of commands.)"
925 (if (not (haskell-process-exists-p))
928 (defun start-haskell ()
929 (message "Starting haskell subprocess...")
930 ;; Kill old haskell process. Normally this routine is only called
931 ;; after checking haskell-process-exists-p, but things can get
932 ;; screwed up if you rename the *haskell* buffer while leaving the
933 ;; old process running. This forces it to get rid of the old process
934 ;; and start a new one.
935 (if (get-process "haskell")
936 (delete-process "haskell"))
937 (let ((haskell-buffer
940 (or haskell-program-name
941 (haskell-mode-error "Haskell-program-name undefined!"))
945 (set-buffer haskell-buffer)
946 (inferior-haskell-mode))
947 (haskell-session-init)
948 ;; Wait for process to get started before sending it anything
949 ;; to avoid race condition on NeXT.
950 (setq *haskell-process-alive* nil)
951 (while (not *haskell-process-alive*)
953 (haskell-send-to-process ":(use-emacs-interface)")
954 (haskell-printers-set haskell-initial-printers nil)
955 (display-buffer haskell-buffer))
956 (message "Starting haskell subprocess... Done."))
959 (defun haskell-process-exists-p ()
960 (let ((haskell-buffer (get-buffer *haskell-buffer*)))
961 (and haskell-buffer (comint-check-proc haskell-buffer))))
965 ;;; Initialize things on the emacs side, and tell haskell that it's
966 ;;; talking to emacs.
968 (defun haskell-session-init ()
969 (set-haskell-status 'busy)
970 (setq *last-loaded* nil)
971 (setq *last-module* haskell-main-module)
972 (setq *last-pad* haskell-main-pad)
973 (setq *haskell-saved-output* nil)
974 (haskell-create-main-pad)
975 (set-process-filter (get-process "haskell") 'haskell-output-filter)
979 (defun haskell-create-main-pad ()
980 (let ((buffer (get-buffer-create haskell-main-pad)))
984 (haskell-record-pad-mapping
985 haskell-main-pad haskell-main-module nil)
989 ;;; Called from evaluation and compilation commands to start up a Haskell
990 ;;; process if none is already in progress.
992 (defun haskell-maybe-create-process ()
993 (cond ((haskell-process-exists-p)
995 (haskell-auto-create-process
998 (haskell-mode-error "No Haskell process!"))))
1003 ;;; ------------------------------------------------------------------
1005 ;;; This always puts the pad buffer in the "other" window.
1006 ;;; Having it wipe out the .hs file window is clearly the wrong
1009 (defun haskell-get-pad ()
1010 "Creates a new scratch pad for the current module.
1011 Signals an error if the current buffer is not a .hs file."
1013 (let ((fname (buffer-file-name)))
1015 (do-get-pad fname (current-buffer))
1016 (haskell-mode-error "Not in a .hs buffer!"))))
1019 (defun do-get-pad (fname buff)
1020 (let* ((mname (or (haskell-get-modname buff)
1021 (read-no-blanks-input "Scratch pad for module? " nil)))
1022 (pname (haskell-lookup-pad mname fname))
1024 ;; Generate the base name of the pad buffer, then create the
1025 ;; buffer. The actual name of the pad buffer may be something
1026 ;; else because of name collisions.
1029 (setq pname (format "*%s-pad*" mname))
1030 (setq pbuff (generate-new-buffer pname))
1031 (setq pname (buffer-name pbuff))
1032 (haskell-record-pad-mapping pname mname fname)
1034 (setq pbuff (get-buffer pname)))
1035 ;; Make sure the pad buffer is in haskell mode.
1036 (pop-to-buffer pbuff)
1042 ;;; ------------------------------------------------------------------
1044 (defun haskell-switch ()
1045 "Switches to \*haskell\* buffer."
1047 (haskell-maybe-create-process)
1048 (pop-to-buffer *haskell-buffer*)
1050 (goto-char (point-max)))
1055 ;;; ------------------------------------------------------------------
1057 (defun haskell-kill ()
1058 "Kill contents of *haskell* buffer. \\[haskell-kill]"
1061 (set-buffer *haskell-buffer*)
1062 (beginning-of-buffer)
1063 (let ((mark (point)))
1065 (kill-region mark (point)))))
1070 ;;; ------------------------------------------------------------------
1072 (defun haskell-command (str)
1073 "Format STRING as a haskell command and send it to haskell process. \\[haskell-command]"
1074 (interactive "sHaskell command: ")
1075 (haskell-send-to-process (format ":%s" str)))
1078 ;;; HASKELL-EVAL and HASKELL-RUN
1079 ;;; ------------------------------------------------------------------
1081 (defun haskell-eval ()
1082 "Evaluate expression in current module. \\[haskell-eval]"
1084 (haskell-maybe-create-process)
1085 (haskell-eval-aux (haskell-get-expression "Haskell expression: ")
1088 (defun haskell-run ()
1089 "Run Haskell Dialogue in current module"
1091 (haskell-maybe-create-process)
1092 (haskell-eval-aux (haskell-get-expression "Haskell dialogue: ")
1095 (defun haskell-run-main ()
1096 "Run Dialogue named main in current module"
1098 (haskell-maybe-create-process)
1099 (haskell-eval-aux "main" "emacs-run"))
1101 (defun haskell-report-type ()
1102 "Print the type of the expression."
1104 (haskell-maybe-create-process)
1105 (haskell-eval-aux (haskell-get-expression "Haskell expression: ")
1106 "emacs-report-type"))
1108 (defun haskell-eval-aux (exp fn)
1109 (cond ((equal *haskell-buffer* (buffer-name))
1110 ;; In the *haskell* buffer.
1111 (let* ((pname *last-pad*)
1112 (mname *last-module*)
1113 (fname *last-loaded*))
1114 (haskell-eval-aux-aux exp pname mname fname fn)))
1117 (let* ((fname (buffer-file-name))
1118 (mname (haskell-get-modname (current-buffer)))
1119 (pname (haskell-lookup-pad mname fname)))
1120 (haskell-eval-aux-aux exp pname mname fname fn)))
1123 (let* ((pname (buffer-name (current-buffer)))
1124 (mname (haskell-get-module-from-pad pname))
1125 (fname (haskell-get-file-from-pad pname)))
1126 (haskell-eval-aux-aux exp pname mname fname fn)))
1129 (defun haskell-eval-aux-aux (exp pname mname fname fn)
1130 (haskell-save-modified-source-files fname)
1131 (haskell-send-to-process (format ":(%s" fn))
1132 (haskell-send-to-process
1133 (prin1-to-string exp))
1134 (haskell-send-to-process
1135 (prin1-to-string (or pname fname "interactive")))
1136 (haskell-send-to-process
1138 (if (and pname (get-buffer pname))
1143 (haskell-send-to-process
1144 (format "'|%s|" mname))
1145 (haskell-send-to-process
1147 (prin1-to-string (haskell-maybe-get-unit-file-name fname))
1149 (haskell-send-to-process ")")
1150 (setq *last-pad* pname)
1151 (setq *last-module* mname)
1152 (setq *last-loaded* fname))
1156 ;;; HASKELL-RUN-FILE, HASKELL-LOAD, HASKELL-COMPILE
1157 ;;; ------------------------------------------------------------------
1159 (defun haskell-run-file ()
1160 "Runs Dialogue named main in current file."
1162 (haskell-maybe-create-process)
1163 (let ((fname (haskell-get-file-to-operate-on)))
1164 (haskell-save-modified-source-files fname)
1165 (haskell-send-to-process ":(emacs-run-file")
1166 (haskell-send-to-process (prin1-to-string fname))
1167 (haskell-send-to-process ")")))
1169 (defun haskell-load ()
1170 "Load current file."
1172 (haskell-maybe-create-process)
1173 (let ((fname (haskell-get-file-to-operate-on)))
1174 (haskell-save-modified-source-files fname)
1175 (haskell-send-to-process ":(emacs-load-file")
1176 (haskell-send-to-process (prin1-to-string fname))
1177 (haskell-send-to-process ")")))
1179 (defun haskell-compile ()
1180 "Compile current file."
1182 (haskell-maybe-create-process)
1183 (let ((fname (haskell-get-file-to-operate-on)))
1184 (haskell-save-modified-source-files fname)
1185 (haskell-send-to-process ":(emacs-compile-file")
1186 (haskell-send-to-process (prin1-to-string fname))
1187 (haskell-send-to-process ")")))
1190 (defun haskell-get-file-to-operate-on ()
1191 (cond ((equal *haskell-buffer* (buffer-name))
1192 ;; When called from the haskell process buffer, prompt for a file.
1193 (call-interactively 'haskell-get-file/prompt))
1195 ;; When called from a .hs file buffer, use the unit file
1196 ;; associated with it, if there is one.
1197 (haskell-maybe-get-unit-file-name (buffer-file-name)))
1199 ;; When called from a pad, use the file that the module the
1200 ;; pad belongs to lives in.
1201 (haskell-maybe-get-unit-file-name
1202 (haskell-get-file-from-pad (buffer-name (current-buffer)))))))
1204 (defun haskell-get-file/prompt (filename)
1205 (interactive "fHaskell file: ")
1211 ;;; ------------------------------------------------------------------
1213 (defun haskell-exit ()
1214 "Quit the haskell process."
1216 (cond ((not (haskell-process-exists-p))
1217 (message "No process currently running."))
1218 ((y-or-n-p "Do you really want to quit Haskell? ")
1219 (haskell-send-to-process ":quit")
1220 ;; If we were running the tutorial, mark the temp buffer as unmodified
1221 ;; so we don't get asked about saving it later.
1222 (if (and *ht-temp-buffer*
1223 (get-buffer *ht-temp-buffer*))
1225 (set-buffer *ht-temp-buffer*)
1226 (set-buffer-modified-p nil)))
1227 ;; Try to remove the haskell output buffer from the screen.
1228 (bury-buffer *haskell-buffer*)
1229 (replace-buffer-in-windows *haskell-buffer*))
1234 ;;; HASKELL-INTERRUPT
1235 ;;; ------------------------------------------------------------------
1237 (defun haskell-interrupt ()
1238 "Interrupt the haskell process."
1240 (if (haskell-process-exists-p)
1241 (haskell-send-to-process "\C-c")))
1245 ;;; HASKELL-EDIT-UNIT
1246 ;;; ------------------------------------------------------------------
1248 (defun haskell-edit-unit ()
1249 "Edit the .hu file."
1251 (let ((fname (buffer-file-name)))
1253 (let ((find-file-not-found-hooks (list 'haskell-new-unit))
1254 (file-not-found nil)
1255 (units-fname (haskell-get-unit-file-name fname)))
1256 (find-file-other-window units-fname)
1257 ;; If creating a new file, initialize it to contain the name
1258 ;; of the haskell source file.
1262 (if (string= (file-name-directory fname)
1263 (file-name-directory units-fname))
1264 (file-name-nondirectory fname)
1267 (haskell-mode-error "Not in a .hs buffer!"))))
1269 (defun haskell-new-unit ()
1270 (setq file-not-found t))
1273 ;;; Look for a comment like "-- unit:" at top of file.
1274 ;;; If not found, assume unit file has same name as the buffer but
1275 ;;; a .hu extension.
1277 (defun haskell-get-unit-file-name (fname)
1278 (or (haskell-get-unit-file-name-from-file fname)
1279 (concat (haskell-strip-file-extension fname) ".hu")))
1281 (defun haskell-maybe-get-unit-file-name (fname)
1282 (or (haskell-get-unit-file-name-from-file fname)
1283 (haskell-strip-file-extension fname)))
1285 (defun haskell-get-unit-file-name-from-file (fname)
1286 (let ((buffer (get-file-buffer fname)))
1289 (beginning-of-buffer)
1290 (if (re-search-forward "-- unit:[ \t]*" (point-max) t)
1291 (let ((beg (match-end 0)))
1293 (buffer-substring beg (point)))
1300 ;;; ==================================================================
1301 ;;; Support for printers/optimizers menus
1302 ;;; ==================================================================
1304 ;;; This code was adapted from the standard buff-menu.el code.
1306 (defvar haskell-menu-mode-map nil "")
1308 (if (not haskell-menu-mode-map)
1310 (setq haskell-menu-mode-map (make-keymap))
1311 (suppress-keymap haskell-menu-mode-map t)
1312 (define-key haskell-menu-mode-map "m" 'hm-mark)
1313 (define-key haskell-menu-mode-map "u" 'hm-unmark)
1314 (define-key haskell-menu-mode-map "x" 'hm-exit)
1315 (define-key haskell-menu-mode-map "q" 'hm-exit)
1316 (define-key haskell-menu-mode-map " " 'next-line)
1317 (define-key haskell-menu-mode-map "\177" 'hm-backup-unmark)
1318 (define-key haskell-menu-mode-map "?" 'describe-mode)))
1320 ;; Printers Menu mode is suitable only for specially formatted data.
1322 (put 'haskell-menu-mode 'mode-class 'special)
1324 (defun haskell-menu-mode ()
1325 "Major mode for editing Haskell flags.
1326 Each line describes a flag.
1327 Letters do not insert themselves; instead, they are commands.
1328 m -- mark flag (turn it on)
1329 u -- unmark flag (turn it off)
1330 x -- exit; tell the Haskell process to update the flags, then leave menu.
1331 q -- exit; same as x.
1332 Precisely,\\{haskell-menu-mode-map}"
1333 (kill-all-local-variables)
1334 (use-local-map haskell-menu-mode-map)
1335 (setq truncate-lines t)
1336 (setq buffer-read-only t)
1337 (setq major-mode 'haskell-menu-mode)
1338 (setq mode-name "Haskell Flags Menu")
1339 ;; These are all initialized elsewhere
1340 (make-local-variable 'hm-current-flags)
1341 (make-local-variable 'hm-request-fn)
1342 (make-local-variable 'hm-update-fn)
1343 (run-hooks 'haskell-menu-mode-hook))
1346 (defun haskell-menu (help-file buffer request-fn update-fn)
1347 (haskell-maybe-create-process)
1348 (if (get-buffer buffer)
1350 (pop-to-buffer buffer)
1351 (goto-char (point-min)))
1353 (pop-to-buffer buffer)
1354 (insert-file-contents help-file)
1356 (setq hm-request-fn request-fn)
1357 (setq hm-update-fn update-fn)
1360 (message "m = mark; u = unmark; x = execute; q = quit; ? = more help."))
1364 ;;; A line that starts with *hm-marked* is a menu item turned on.
1365 ;;; A line that starts with *hm-unmarked* is turned off.
1366 ;;; A line that starts with anything else is just random text and is
1367 ;;; ignored by commands that deal with menu items.
1369 (defvar *hm-marked* " on")
1370 (defvar *hm-unmarked* " ")
1371 (defvar *hm-marked-regexp* " on \\w")
1372 (defvar *hm-unmarked-regexp* " \\w")
1375 "Mark flag to be turned on."
1378 (cond ((looking-at *hm-marked-regexp*)
1380 ((looking-at *hm-unmarked-regexp*)
1381 (let ((buffer-read-only nil))
1382 (delete-char (length *hm-unmarked*))
1383 (insert *hm-marked*)
1392 (cond ((looking-at *hm-unmarked-regexp*)
1394 ((looking-at *hm-marked-regexp*)
1395 (let ((buffer-read-only nil))
1396 (delete-char (length *hm-marked*))
1397 (insert *hm-unmarked*)
1402 (defun hm-backup-unmark ()
1403 "Move up and unmark."
1410 ;;; Actually make the changes.
1413 "Update flags, then leave menu."
1418 (defun hm-execute ()
1419 "Tell haskell process to tweak flags."
1422 (goto-char (point-min))
1423 (let ((flags-on nil)
1425 (while (not (eq (point) (point-max)))
1426 (cond ((looking-at *hm-unmarked-regexp*)
1427 (setq flags-off (cons (hm-flag) flags-off)))
1428 ((looking-at *hm-marked-regexp*)
1429 (setq flags-on (cons (hm-flag) flags-on)))
1433 (funcall hm-update-fn flags-on flags-off))))
1438 "Make the menu go away."
1439 (bury-buffer (current-buffer))
1440 (replace-buffer-in-windows (current-buffer)))
1446 (let ((beg (point)))
1447 ;; End of flag name marked by tab or two spaces.
1448 (re-search-forward "\t\\| ")
1449 (buffer-substring beg (match-beginning 0)))))
1452 ;;; Update the menu to mark only those items currently turned on.
1454 (defun hm-mark-current ()
1455 (funcall hm-request-fn)
1457 (goto-char (point-min))
1458 (while (not (eq (point) (point-max)))
1459 (cond ((and (looking-at *hm-unmarked-regexp*)
1460 (hm-item-currently-on-p (hm-flag)))
1462 ((and (looking-at *hm-marked-regexp*)
1463 (not (hm-item-currently-on-p (hm-flag))))
1466 (forward-line 1))))))
1469 ;;; See if a menu item is turned on.
1471 (defun hm-item-currently-on-p (item)
1472 (member-string= item hm-current-flags))
1474 (defun member-string= (item list)
1477 ((string= item (car list))
1480 (member-string= item (cdr list)))))
1484 ;;; Make the menu for printers.
1486 (defvar *haskell-printers-help*
1487 (concat (getenv "HASKELL") "/emacs-tools/printer-help.txt")
1488 "Help file for printers.")
1490 (defvar *haskell-printers-buffer* "*Haskell printers*")
1492 (defun haskell-printers ()
1493 "Set printers interactively."
1496 *haskell-printers-help*
1497 *haskell-printers-buffer*
1498 'haskell-printers-inquire
1499 'haskell-printers-set))
1501 (defun haskell-printers-inquire ()
1502 (setq hm-current-flags t)
1503 (haskell-send-to-process ":(emacs-send-printers)")
1504 (while (eq hm-current-flags t)
1507 (defun haskell-printers-update (data)
1508 (setq hm-current-flags (read data)))
1510 (defun haskell-printers-set (flags-on flags-off)
1511 (haskell-send-to-process ":(emacs-set-printers '")
1512 (haskell-send-to-process (prin1-to-string flags-on))
1513 (haskell-send-to-process ")"))
1516 ;;; Equivalent stuff for the optimizers menu
1518 (defvar *haskell-optimizers-help*
1519 (concat (getenv "HASKELL") "/emacs-tools/optimizer-help.txt")
1520 "Help file for optimizers.")
1522 (defvar *haskell-optimizers-buffer* "*Haskell optimizers*")
1524 (defun haskell-optimizers ()
1525 "Set optimizers interactively."
1528 *haskell-optimizers-help*
1529 *haskell-optimizers-buffer*
1530 'haskell-optimizers-inquire
1531 'haskell-optimizers-set))
1533 (defun haskell-optimizers-inquire ()
1534 (setq hm-current-flags t)
1535 (haskell-send-to-process ":(emacs-send-optimizers)")
1536 (while (eq hm-current-flags t)
1539 (defun haskell-optimizers-update (data)
1540 (setq hm-current-flags (read data)))
1542 (defun haskell-optimizers-set (flags-on flags-off)
1543 (haskell-send-to-process ":(emacs-set-optimizers '")
1544 (haskell-send-to-process (prin1-to-string flags-on))
1545 (haskell-send-to-process ")"))
1549 ;;; ==================================================================
1550 ;;; Random utilities
1551 ;;; ==================================================================
1554 ;;; Keep track of the association between pads, modules, and files.
1555 ;;; The global variable is a list of (pad-buffer-name module-name file-name)
1558 (defvar *haskell-pad-mappings* ()
1559 "Associates pads with their corresponding module and file.")
1561 (defun haskell-record-pad-mapping (pname mname fname)
1562 (setq *haskell-pad-mappings*
1563 (cons (list pname mname fname) *haskell-pad-mappings*)))
1565 (defun haskell-get-module-from-pad (pname)
1566 (car (cdr (assoc pname *haskell-pad-mappings*))))
1568 (defun haskell-get-file-from-pad (pname)
1569 (car (cdr (cdr (assoc pname *haskell-pad-mappings*)))))
1571 (defun haskell-lookup-pad (mname fname)
1572 (let ((pname (haskell-lookup-pad-aux mname fname *haskell-pad-mappings*)))
1573 (if (and pname (get-buffer pname))
1577 (defun haskell-lookup-pad-aux (mname fname list)
1580 ((and (equal mname (car (cdr (car list))))
1581 (equal fname (car (cdr (cdr (car list))))))
1584 (haskell-lookup-pad-aux mname fname (cdr list)))))
1588 ;;; Save any modified .hs and .hu files.
1589 ;;; Yes, the two set-buffer calls really seem to be necessary. It seems
1590 ;;; that y-or-n-p makes emacs forget we had temporarily selected some
1591 ;;; other buffer, and if you just do save-buffer directly it will end
1592 ;;; up trying to save the current buffer instead. The built-in
1593 ;;; save-some-buffers function has this problem....
1595 (defun haskell-save-modified-source-files (filename)
1596 (let ((buffers (buffer-list))
1599 (let ((buffer (car buffers)))
1600 (if (and (buffer-modified-p buffer)
1603 (and buffer-file-name
1604 (haskell-source-file-p buffer-file-name)
1606 (or (null haskell-ask-before-saving)
1607 (and filename (string= buffer-file-name filename))
1609 (format "Save file %s? " buffer-file-name))))))
1613 (setq buffers (cdr buffers)))
1616 (message "(No files need saving)"))))
1618 (defun haskell-source-file-p (filename)
1619 (or (string-match "\\.hs$" filename)
1620 (string-match "\\.lhs$" filename)
1621 (string-match "\\.hi$" filename)
1622 (string-match "\\.hu$" filename)))
1626 ;;; Buffer utilities
1628 (defun haskell-move-marker ()
1629 "Moves the marker and point to the end of buffer"
1630 (set-marker comint-last-input-end (point-max))
1631 (set-marker (process-mark (get-process "haskell")) (point-max))
1632 (goto-char (point-max)))
1636 ;;; Extract the name of the module the point is in, from the given buffer.
1638 (defvar *haskell-re-module-hs* "^module\\s *")
1639 (defvar *haskell-re-module-lhs* "^>\\s *module\\s *")
1640 (defvar *haskell-re-modname* "[A-Z]\\([a-z]\\|[A-Z]\\|[0-9]\\|'\\|_\\)*")
1642 (defun haskell-get-modname (buff)
1643 "Get module name in BUFFER that point is in."
1646 (let ((regexp (if (haskell-lhs-filename-p (buffer-file-name))
1647 *haskell-re-module-lhs*
1648 *haskell-re-module-hs*)))
1649 (if (or (looking-at regexp)
1650 (re-search-backward regexp (point-min) t)
1651 (re-search-forward regexp (point-max) t))
1653 (goto-char (match-end 0))
1654 (if (looking-at *haskell-re-modname*)
1655 (buffer-substring (match-beginning 0) (match-end 0))
1656 (haskell-mode-error "Module name not found!!")))
1660 ;;; Strip file extensions.
1661 ;;; Only strip off extensions we know about; e.g.
1662 ;;; "foo.hs" -> "foo" but "foo.bar" -> "foo.bar".
1664 (defvar *haskell-filename-regexp* "\\(.*\\)\\.\\(hs\\|lhs\\)$")
1666 (defun haskell-strip-file-extension (filename)
1667 "Strip off the extension from a filename."
1668 (if (string-match *haskell-filename-regexp* filename)
1669 (substring filename (match-beginning 1) (match-end 1))
1673 ;;; Is this a .lhs filename?
1675 (defun haskell-lhs-filename-p (filename)
1676 (string-match ".*\\.lhs$" filename))
1679 ;;; Haskell mode error
1681 (defun haskell-mode-error (msg)
1682 "Show MSG in message line as an error from the haskell mode."
1683 (error (concat "Haskell mode: " msg)))
1687 ;;; ==================================================================
1688 ;;; User customization
1689 ;;; ==================================================================
1691 (defvar haskell-load-hook nil
1692 "This hook is run when haskell is loaded in.
1693 This is a good place to put key bindings."
1696 (run-hooks 'haskell-load-hook)
1701 ;;;======================================================================
1702 ;;; Tutorial mode setup
1703 ;;;======================================================================
1705 ;;; Set up additional key bindings for tutorial mode.
1707 (defvar ht-mode-map (make-sparse-keymap))
1709 (haskell-establish-key-bindings ht-mode-map)
1710 (define-key ht-mode-map "\C-c\C-f" 'ht-next-page)
1711 (define-key ht-mode-map "\C-c\C-b" 'ht-prev-page)
1712 (define-key ht-mode-map "\C-c\C-l" 'ht-restore-page)
1713 (define-key ht-mode-map "\C-c?" 'describe-mode)
1715 (defun haskell-tutorial-mode ()
1716 "Major mode for running the Haskell tutorial.
1717 You can use these commands:
1720 (kill-all-local-variables)
1721 (use-local-map ht-mode-map)
1722 (setq major-mode 'haskell-tutorial-mode)
1723 (setq mode-name "Haskell Tutorial")
1724 (set-syntax-table haskell-mode-syntax-table)
1725 (run-hooks 'haskell-mode-hook))
1728 (defun haskell-tutorial ()
1729 "Run the haskell tutorial."
1734 (haskell-maybe-create-process)
1735 (haskell-send-to-process ":(emacs-set-printers '(interactive))")
1739 ;;; Load the tutorial file into a read-only buffer. Do not display this
1742 (defun ht-load-tutorial ()
1743 (let ((buffer (get-buffer *ht-file-buffer*)))
1747 (beginning-of-buffer))
1749 (set-buffer (setq buffer (get-buffer-create *ht-file-buffer*)))
1750 (let ((fname (substitute-in-file-name *ht-source-file*)))
1751 (if (file-readable-p fname)
1752 (ht-load-tutorial-aux fname)
1753 (call-interactively 'ht-load-tutorial-aux)))))))
1755 (defun ht-load-tutorial-aux (filename)
1756 (interactive "fTutorial file: ")
1757 (insert-file filename)
1758 (set-buffer-modified-p nil)
1759 (setq buffer-read-only t)
1760 (beginning-of-buffer))
1763 ;;; Create a buffer to use for messing about with each page of the tutorial.
1764 ;;; Put the buffer into haskell-tutorial-mode.
1766 (defun ht-make-buffer ()
1767 (find-file (concat "/tmp/" (make-temp-name "ht") ".lhs"))
1768 (setq *ht-temp-buffer* (buffer-name))
1769 (haskell-tutorial-mode))
1772 ;;; Commands for loading text into the tutorial pad buffer
1774 (defun ht-next-page ()
1775 "Go to the next tutorial page."
1777 (if (ht-goto-next-page)
1781 (defun ht-goto-next-page ()
1782 (let ((buff (current-buffer)))
1785 (set-buffer *ht-file-buffer*)
1786 (search-forward "\C-l" nil t))
1787 (set-buffer buff))))
1789 (defun ht-prev-page ()
1790 "Go to the previous tutorial page."
1792 (if (ht-goto-prev-page)
1796 (defun ht-goto-prev-page ()
1797 (let ((buff (current-buffer)))
1800 (set-buffer *ht-file-buffer*)
1801 (search-backward "\C-l" nil t))
1802 (set-buffer buff))))
1804 (defun ht-goto-page (arg)
1805 "Go to the tutorial page specified as the argument."
1806 (interactive "sGo to page: ")
1807 (if (ht-searchfor-page (format "Page: %s " arg))
1811 (defun ht-goto-section (arg)
1812 "Go to the tutorial section specified as the argument."
1813 (interactive "sGo to section: ")
1814 (if (ht-searchfor-page (format "Section: %s " arg))
1818 (defun ht-searchfor-page (search-string)
1819 (let ((buff (current-buffer)))
1822 (set-buffer *ht-file-buffer*)
1823 (let ((point (point)))
1824 (beginning-of-buffer)
1825 (if (search-forward search-string nil t)
1830 (set-buffer buff))))
1832 (defun ht-restore-page ()
1834 (let ((old-point (point)))
1836 (goto-char old-point)))
1838 (defun ht-display-page ()
1839 (set-buffer *ht-file-buffer*)
1841 (if (search-backward "\C-l" nil t)
1843 (beginning-of-buffer))
1846 (if (search-forward "\C-l" nil t)
1850 (text (buffer-substring beg end)))
1851 (set-buffer *ht-temp-buffer*)
1854 (beginning-of-buffer)))
1858 ;;;======================================================================
1860 ;;;======================================================================
1862 ;;; This only works in Emacs version 19, so it's in a separate file for now.
1864 (if (featurep 'menu-bar)
1865 (load-library "haskell-menu"))