[project @ 1997-03-14 05:31:07 by sof]
[ghc-hetmet.git] / ghc / CONTRIB / haskell-modes / chalmers / thiemann / haskell-mode.el
1 ;; haskell-mode.el. Major mode for editing Haskell.
2 ;; Copyright (C) 1989, Free Software Foundation, Inc., Lars Bo Nielsen
3 ;; and Lennart Augustsson
4 ;; modified by Peter Thiemann, March 1994
5
6 ;; This file is not officially part of GNU Emacs.
7
8 ;; GNU Emacs is distributed in the hope that it will be useful,
9 ;; but WITHOUT ANY WARRANTY.  No author or distributor
10 ;; accepts responsibility to anyone for the consequences of using it
11 ;; or for whether it serves any particular purpose or works at all,
12 ;; unless he says so in writing.  Refer to the GNU Emacs General Public
13 ;; License for full details.
14
15 ;; Everyone is granted permission to copy, modify and redistribute
16 ;; GNU Emacs, but only under the conditions described in the
17 ;; GNU Emacs General Public License.   A copy of this license is
18 ;; supposed to have been given to you along with GNU Emacs so you
19 ;; can know your rights and responsibilities.  It should be in a
20 ;; file named COPYING.  Among other things, the copyright notice
21 ;; and this notice must be preserved on all copies.
22
23 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
24 ;;
25 ;; Haskell Mode. A major mode for editing and running Haskell. (Version 0.0)
26 ;; =================================================================
27 ;;
28 ;; This is a mode for editing and running Haskell.
29 ;; It is very much based on the sml mode for GNU Emacs. It
30 ;; features:
31 ;;
32 ;;      - Inferior shell running Haskell. No need to leave emacs, just
33 ;;        keep right on editing while Haskell runs in another window.
34 ;;
35 ;;      - Automatic "load file" in inferior shell. Send regions of code
36 ;;        to the Haskell program.
37 ;;
38 ;;
39 ;; 1. HOW TO USE THE Haskell-MODE
40 ;; ==========================
41 ;;
42 ;; Here is a short introduction to the mode.
43 ;;
44 ;; 1.1 GETTING STARTED
45 ;; -------------------
46 ;;
47 ;; If you are an experienced user of Emacs, just skip this section.
48 ;;
49 ;; To use the haskell-mode, insert this in your "~/.emacs" file (Or ask your
50 ;; emacs-administrator to help you.):
51 ;;
52 ;;    (setq auto-mode-alist (cons '("\\.hs$" . haskell-mode) (cons '("\\.lhs$" . haskell-mode)
53 ;;                           auto-mode-alist)))
54 ;;    (autoload 'haskell-mode "haskell-mode" "Major mode for editing Haskell." t)
55 ;;
56 ;; Now every time a file with the extension `.hs' or `.lhs' is found, it is
57 ;; automatically started up in haskell-mode.
58 ;;
59 ;; You will also have to specify the path to this file, so you will have
60 ;; to add this as well:
61 ;;
62 ;;    (setq load-path (cons "/usr/me/emacs" load-path))
63 ;;
64 ;; where "/usr/me/emacs" is the directory where this file is.
65 ;;
66 ;; You may also want to compile the this file (M-x byte-compile-file)
67 ;; for speed.
68 ;;
69 ;; You are now ready to start using haskell-mode. If you have tried other
70 ;; language modes (like lisp-mode or C-mode), you should have no
71 ;; problems. There are only a few extra functions in this mode.
72 ;;
73 ;; 1.2. EDITING COMMANDS.
74 ;; ----------------------
75 ;;
76 ;; The following editing and inferior-shell commands can ONLY be issued
77 ;; from within a buffer in haskell-mode.
78 ;;
79 ;; LFD (haskell-newline-and-indent).  
80 ;;     This is probably the function you will be using the most (press
81 ;;     CTRL while you press Return, press C-j or press Newline). It
82 ;;     makes a new line and performs indentation based on the last 
83 ;;     preceding non-comment line.
84 ;;
85 ;; M-; (indent-for-comment).
86 ;;     Like in other language modes, this command will give you a comment
87 ;;     at the of the current line. The column where the comment starts is
88 ;;     determined by the variable comment-column (default: 40).
89 ;;    
90 ;; C-c C-v (haskell-mode-version). 
91 ;;     Get the version of the haskell-mode.
92 ;;
93 ;;
94 ;; 1.3. COMMANDS RELATED TO THE INFERIOR SHELL
95 ;; -------------------------------------------
96 ;;
97 ;; C-c C-s (haskell-pop-to-shell).
98 ;;     This command starts up an inferior shell running haskell. If the shell
99 ;;     is running, it will just pop up the shell window.
100 ;;
101 ;; C-c C-u (haskell-save-buffer-use-file).
102 ;;     This command will save the current buffer and send a "load file",
103 ;;     where file is the file visited by the current buffer, to the
104 ;;     inferior shell running haskell.
105 ;;
106 ;; C-c C-f (haskell-run-on-file).
107 ;;     Will send a "load file" to the inferior shell running haskell,
108 ;;     prompting you for the file name.
109 ;;    
110 ;; C-c C-r (haskell-send-region). 
111 ;;     Will send region, from point to mark, to the inferior shell
112 ;;     running haskell.
113 ;;
114 ;; C-c C-b (haskell-send-buffer). 
115 ;;     Will send whole buffer to inferior shell running haskell.
116 ;;
117 ;; 2. INDENTATION
118 ;; ================
119 ;; 
120 ;; The first indentation command (using C-j or TAB) on a given line
121 ;; indents like the last preceding non-comment line. The next TAB
122 ;; indents to the indentation of the innermost enclosing scope. Further
123 ;; TABs get you to further enclosing scopes. After indentation has
124 ;; reached the first column, the process restarts using the indentation
125 ;; of the preceding non-comment line, again.
126 ;;
127 ;; 3. INFERIOR SHELL.
128 ;; ==================
129 ;;
130 ;; The mode for Standard ML also contains a mode for an inferior shell
131 ;; running haskell. The mode is the same as the shell-mode, with just one
132 ;; extra command.
133 ;;
134 ;; 3.1. INFERIOR SHELL COMMANDS
135 ;; ----------------------------
136 ;;
137 ;; C-c C-f (haskell-run-on-file).  Send a `load file' to the process running
138 ;; haskell.
139 ;;
140 ;; 3.2. CONSTANTS CONTROLLING THE INFERIOR SHELL MODE
141 ;; --------------------------------------------------
142 ;;
143 ;; Because haskell is called differently on various machines, and the
144 ;; haskell-systems have their own command for reading in a file, a set of
145 ;; constants controls the behavior of the inferior shell running haskell (to
146 ;; change these constants: See CUSTOMIZING YOUR Haskell-MODE below).
147 ;;
148 ;; haskell-prog-name (default "hbi").
149 ;;     This constant is a string, containing the command to invoke
150 ;;     Standard ML on your system. 
151 ;;
152 ;; haskell-use-right-delim (default "\"")
153 ;; haskell-use-left-delim  (default "\"")
154 ;;     The left and right delimiter used by your version of haskell, for
155 ;;     `use file-name'.
156 ;;
157 ;; haskell-process-name (default "Haskell"). 
158 ;;     The name of the process running haskell. (This will be the name
159 ;;     appearing on the mode line of the buffer)
160 ;;
161 ;; NOTE: The haskell-mode functions: haskell-send-buffer, haskell-send-function and
162 ;; haskell-send-region, creates temporary files (I could not figure out how
163 ;; to send large amounts of data to a process). These files will be
164 ;; removed when you leave emacs.
165 ;;
166 ;; 4. FONTIFICATION
167 ;;
168 ;; There is support for Jamie Zawinski's font-lock-mode through the
169 ;; variable "haskell-font-lock-keywords".
170 ;;
171 ;; 5. CUSTOMIZING YOUR Haskell-MODE
172 ;; ============================
173 ;;
174 ;; If you have to change some of the constants, you will have to add a
175 ;; `hook' to the haskell-mode. Insert this in your "~/.emacs" file.
176 ;;
177 ;;    (setq haskell-mode-hook 'my-haskell-constants)
178 ;;
179 ;; Your function "my-haskell-constants" will then be executed every time
180 ;; "haskell-mode" is invoked.  Now you only have to write the emacs-lisp
181 ;; function "my-haskell-constants", and put it in your "~/.emacs" file.
182 ;;
183 ;; Say you are running a version of haskell that uses the syntax `load
184 ;; ["file"]', is invoked by the command "OurHaskell" and you don't want the
185 ;; indentation algorithm to indent according to open parenthesis, your
186 ;; function should look like this:
187 ;;
188 ;;    (defun my-haskell-constants ()
189 ;;       (setq haskell-prog-name "OurHaskell")
190 ;;       (setq haskell-use-left-delim "[\"")
191 ;;       (setq haskell-use-right-delim "\"]")
192 ;;       (setq haskell-paren-lookback nil))
193 ;;
194 ;; The haskell-shell also runs a `hook' (haskell-shell-hook) when it is invoked.
195 ;;
196 ;;
197 ;;
198 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
199 ;;
200 ;;
201 ;; ORIGINAL AUTHOR
202 ;;         Lars Bo Nielsen
203 ;;         Aalborg University
204 ;;         Computer Science Dept.
205 ;;         9000 Aalborg
206 ;;         Denmark
207 ;;
208 ;;         lbn@iesd.dk
209 ;;         or: ...!mcvax!diku!iesd!lbn
210 ;;         or: mcvax!diku!iesd!lbn@uunet.uu.net
211 ;;
212 ;; MODIFIED FOR Haskell BY
213 ;;         Lennart Augustsson
214 ;;         indentation stuff by Peter Thiemann
215 ;;
216 ;;
217 ;; Please let me know if you come up with any ideas, bugs, or fixes.
218 ;;
219 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
220
221 (defconst haskell-mode-version-string
222   "HASKELL-MODE, Version 0.2, PJT indentation")
223
224 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
225 ;;;
226 ;;; CONSTANTS CONTROLLING THE MODE.
227 ;;;
228 ;;; These are the constants you might want to change
229 ;;; 
230
231 ;; The command used to start up the haskell-program.
232 (defconst haskell-prog-name "hbi" "*Name of program to run as haskell.")
233
234 ;; The left delimmitter for `load file'
235 (defconst haskell-use-left-delim "\""
236   "*The left delimiter for the filename when using \"load\".")
237
238 ;; The right delimmitter for `load file'
239 (defconst haskell-use-right-delim "\""
240   "*The right delimiter for the filename when using \"load\".")
241
242 ;; A regular expression matching the prompt pattern in the inferior
243 ;; shell
244 (defconst haskell-shell-prompt-pattern "^> *"
245   "*The prompt pattern for the inferion shell running haskell.")
246
247 ;; The template used for temporary files, created when a region is
248 ;; send to the inferior process running haskell.
249 (defconst haskell-tmp-template "/tmp/haskell.tmp."
250   "*Template for the temporary file, created by haskell-simulate-send-region.")
251
252 ;; The name of the process running haskell (This will also be the name of
253 ;; the buffer).
254 (defconst haskell-process-name "Haskell" "*The name of the Haskell-process")
255
256 ;;;
257 ;;; END OF CONSTANTS CONTROLLING THE MODE.
258 ;;;
259 ;;; If you change anything below, you are on your own.
260 ;;; 
261 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
262
263
264 (defvar haskell-mode-syntax-table nil "The syntax table used in haskell-mode.")
265
266 (defvar haskell-mode-map nil "The mode map used in haskell-mode.")
267
268 (defvar haskell-mode-abbrev-table nil "The abbrev-table used in haskell-mode.")
269
270 (defvar haskell-old-kill-emacs-hook nil "Old value of kill-emacs-hook")
271
272 (defun haskell-mode ()
273   "Major mode for editing Haskell code.
274 Tab indents for Haskell code.
275 Comments are delimited with --
276 Paragraphs are separated by blank lines only.
277 Delete converts tabs to spaces as it moves back.
278
279 Key bindings:
280 =============
281
282 \\[haskell-pop-to-shell]\t  Pop to the haskell window.
283 \\[haskell-save-buffer-use-file]\t  Save the buffer, and send a \"load file\".
284 \\[haskell-send-region]\t  Send region (point and mark) to haskell.
285 \\[haskell-run-on-file]\t  Send a \"load file\" to haskell.
286 \\[haskell-send-buffer]\t  Send whole buffer to haskell.
287 \\[haskell-mode-version]\t  Get the version of haskell-mode.
288 \\[haskell-evaluate-expression]\t  Prompt for an expression and evalute it.
289
290
291 Mode map
292 ========
293 \\{haskell-mode-map}
294 Runs haskell-mode-hook if non nil."
295   (interactive)
296   (kill-all-local-variables)
297   (if haskell-mode-map
298       ()
299     (setq haskell-mode-map (make-sparse-keymap))
300     (define-key haskell-mode-map "\C-c\C-v" 'haskell-mode-version)
301     (define-key haskell-mode-map "\C-c\C-u" 'haskell-save-buffer-use-file)
302     (define-key haskell-mode-map "\C-c\C-s" 'haskell-pop-to-shell)
303     (define-key haskell-mode-map "\C-c\C-r" 'haskell-send-region)
304     (define-key haskell-mode-map "\C-c\C-m" 'haskell-region)
305     (define-key haskell-mode-map "\C-c\C-f" 'haskell-run-on-file)
306     (define-key haskell-mode-map "\C-c\C-b" 'haskell-send-buffer)
307     (define-key haskell-mode-map "\C-ce"    'haskell-evaluate-expression)
308     (define-key haskell-mode-map "\C-j"     'haskell-newline-and-indent)
309     (define-key haskell-mode-map "\177"     'backward-delete-char-untabify))
310   (use-local-map haskell-mode-map)
311   (setq major-mode 'haskell-mode)
312   (setq mode-name "Haskell")
313   (define-abbrev-table 'haskell-mode-abbrev-table ())
314   (setq local-abbrev-table haskell-mode-abbrev-table)
315   (if haskell-mode-syntax-table
316       ()
317     (setq haskell-mode-syntax-table (make-syntax-table))
318     (modify-syntax-entry ?{  "(}1"    haskell-mode-syntax-table)
319     (modify-syntax-entry ?}  "){4"    haskell-mode-syntax-table)
320 ; partain: out
321 ;    (modify-syntax-entry ?-  "_ 2356" haskell-mode-syntax-table)
322 ;    (modify-syntax-entry ?\f "> b"    haskell-mode-syntax-table)
323 ;    (modify-syntax-entry ?\n "> b"    haskell-mode-syntax-table)
324 ; partain: end out
325 ; partain: in
326     (modify-syntax-entry ?-  "_ 23" haskell-mode-syntax-table)
327 ;    (modify-syntax-entry ?\f "> b"    haskell-mode-syntax-table)
328 ;    (modify-syntax-entry ?\n "> b"    haskell-mode-syntax-table)
329 ; partain: end in
330     (modify-syntax-entry ?\\ "\\"     haskell-mode-syntax-table)
331     (modify-syntax-entry ?*  "_"      haskell-mode-syntax-table)
332     (modify-syntax-entry ?_  "_"      haskell-mode-syntax-table)
333     (modify-syntax-entry ?'  "_"      haskell-mode-syntax-table)
334     (modify-syntax-entry ?:  "_"      haskell-mode-syntax-table)
335     (modify-syntax-entry ?|  "."      haskell-mode-syntax-table)
336     )
337   (set-syntax-table haskell-mode-syntax-table)
338   (make-local-variable 'require-final-newline) ; Always put a new-line
339   (setq require-final-newline t)        ; in the end of file
340   (make-local-variable 'indent-line-function)
341   (setq indent-line-function 'haskell-indent-line)
342   (make-local-variable 'comment-start)
343   (setq comment-start "-- ")
344   (make-local-variable 'comment-end)
345   (setq comment-end "")
346   (make-local-variable 'comment-column)
347   (setq comment-column 60)              ; Start of comment in this column
348   (make-local-variable 'comment-start-skip)
349   (setq comment-start-skip "--[^a-zA-Z0-9]*") ; This matches a start of comment
350   (make-local-variable 'comment-indent-function)
351   (setq comment-indent-function 'haskell-comment-indent)
352   ;;
353   ;; Adding these will fool the matching of parens. I really don't
354   ;; know why. It would be nice to have comments treated as
355   ;; white-space
356   ;; 
357   ;; (make-local-variable 'parse-sexp-ignore-comments)
358   ;; (setq parse-sexp-ignore-comments t)
359   ;; 
360   (run-hooks 'haskell-mode-hook))               ; Run the hook
361
362 (defun haskell-mode-version ()
363   (interactive)
364   (message haskell-mode-version-string))
365
366
367 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
368 ;;;
369 ;;; INDENTATION
370 ;;;
371 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
372
373 ;;; some variables for later use
374
375 (defvar haskell-open-comment "{-")
376 (defvar haskell-close-comment "-}")
377 (defvar haskell-indentation-counter 0
378   "count repeated invocations of indent-for-tab-command")
379 (defvar haskell-literate-flag nil
380   "used to guide literate/illiterate behavior, set automagically")
381
382 (defun haskell-newline-and-indent ()
383   (interactive)
384   (setq haskell-literate-flag
385         (save-excursion
386           (beginning-of-line)
387           (= (following-char) ?>)))
388   (newline)
389   (if haskell-literate-flag (insert ">"))
390   (haskell-indent-line))
391
392 (defun haskell-indent-line ()
393   "Indent current line of ordinary or literate Haskell code."
394   (interactive)
395   (let ((indent (haskell-calculate-indentation-pjt-2)))
396     (if (/= (current-indentation) indent)
397         (let ((beg (progn
398                      (beginning-of-line)
399                      (if (= (following-char) ?>) (forward-char 1)) ;LITERATE
400                      (point))))
401           (skip-chars-forward "\t ")
402           (delete-region beg (point))
403           (indent-to indent))
404       ;; If point is before indentation, move point to indentation
405       (if (< (current-column) (current-indentation))
406           (skip-chars-forward "\t ")))))
407
408 (defun haskell-calculate-indentation ()
409   (save-excursion
410     (let ((col (current-column)))
411       (while (and (not (bobp))          ;skip over empty and comment-only lines
412                   (= col (current-column)))
413         (previous-line 1)
414         (beginning-of-line)                     ; Go to first non whitespace
415         (if (= (following-char) ?>)     ;LITERATE
416             (forward-char 1)
417           (if haskell-literate-flag     ;ignore illiterate lines
418               (end-of-line)))
419         (skip-chars-forward "\t ")              ; on the line.
420         (setq col (current-column))
421         (search-forward-regexp (concat haskell-open-comment "\\|--\\|\n") nil 0)
422         (goto-char (match-beginning 0)))
423       (search-backward-regexp "\\b\\(where\\|let\\|of\\|in\\)\\b\\|\n" nil 0)
424       (if (looking-at "\n")
425           ()
426         (setq col (current-column))
427         (forward-word 1)
428         (skip-chars-forward "\t ")
429         (if (looking-at "\\w")
430             (setq col (current-column))
431           (setq col (+ 2 col))))
432       col)))
433
434 (defun haskell-calculate-indentation-pjt-2 ()
435   "Calculate indentation for Haskell program code, versatile version"
436   (save-excursion
437     (if (eq last-command 'haskell-indentation)
438         (setq haskell-indentation-counter (1+ haskell-indentation-counter))
439       (setq haskell-indentation-counter -1))
440     (setq this-command 'haskell-indentation)
441     (let* ((simple-indent (haskell-calculate-indentation))
442            (count haskell-indentation-counter)
443            (min-indent simple-indent)   ; minimum indentation found in a non-comment line
444            (last-indent simple-indent)  ; indentation of the following non-comment line
445            (return-indent nil)          ; computed indentation
446            (comment-depth 0))
447       (previous-line 1)
448       (if (< haskell-indentation-counter 0) ; 1st tab gives simple indentation
449           (setq return-indent simple-indent))
450       (while (not return-indent)
451         (if (search-backward-regexp "\\b\\(where\\|let\\|of\\)\\b\\|\n\\|{-\\|-}" nil t 1)
452             (cond
453              ((looking-at haskell-open-comment)
454               (setq comment-depth (1- comment-depth)))
455              ((looking-at haskell-close-comment)
456               (setq comment-depth (1+ comment-depth)))
457              ((= 0 comment-depth)
458               (cond
459                ((looking-at "\n")
460                 (save-excursion
461                   (forward-char 1)
462                   (if (= (following-char) ?>)
463                       (forward-char 1)
464                     (if haskell-literate-flag
465                         (end-of-line))) ;LITERATE: ignore lines w/o >
466                   (skip-chars-forward "\t ")
467                   (if (looking-at (concat haskell-open-comment "\\|--\\|\n"))
468                       ()
469                     (setq last-indent (current-column))
470                     (if (< last-indent min-indent)
471                         (setq min-indent last-indent)))))
472                (t                       ; looking at a keyword
473                 (save-excursion
474                   (forward-word 1)
475                   (skip-chars-forward " \t")
476                   (if (and haskell-literate-flag ;LITERATE: ignore lines w/o >
477                            (save-excursion
478                              (beginning-of-line)
479                              (/= (following-char) ?>)))
480                       (end-of-line))
481                   (if (looking-at (concat haskell-open-comment "\\|--\\|\n"))
482                       ()
483                     (setq last-indent (current-column)))
484                   (if (<= last-indent min-indent)
485                       (if (> count 0)
486                           (setq count (1- count))
487                         (setq return-indent last-indent)))
488                   (if (< last-indent min-indent)
489                       (setq min-indent last-indent)))))))
490           (setq return-indent simple-indent)
491           (setq haskell-indentation-counter -1)))
492       return-indent)))
493
494 (defun haskell-skip-nested-comment ()
495   ;; point looks at opening {-, move over closing -}
496   ;; todo: specify what happens on failure, bounds check ...
497   (forward-char 2)
498   (let ((comment-depth 1))
499     (while (> comment-depth 0)
500       (search-forward-regexp "{-\\|-}")
501       (goto-char (match-beginning 0))
502       (setq comment-depth
503             (if (= (following-char) 123) ; code for opening brace
504                 (1+ comment-depth)
505               (1- comment-depth)))
506       (goto-char (match-end 0)))))
507
508
509 ;;;seemingly obsolete functions
510 (defun haskell-inside-of-inline-comment ()
511   (let ((bolp (save-excursion
512                (beginning-of-line)
513                (point))))
514     (search-backward comment-start bolp t 1)))
515
516 (defun haskell-inside-of-nested-comment ()
517   (save-excursion
518     (let ((count 0))
519       (while
520           (search-backward-regexp "\\({-\\|-}\\)" 0 t 1)
521         (if (haskell-inside-of-inline-comment)
522             ()
523           (if (looking-at haskell-open-comment)
524               (setq count (1+ count))
525             (setq count (1- count)))))
526       (> count 0))))
527
528 (defun haskell-inside-of-comment ()
529   (or (haskell-inside-of-inline-comment)
530       (haskell-inside-of-nested-comment)))
531
532 ;;;stolen from sml-mode.el
533 (defun haskell-comment-indent ()
534   "Compute indentation for Haskell comments"
535   (if (looking-at "^--")
536       0
537     (save-excursion
538       (skip-chars-backward " \t")
539       (max (1+ (current-column))
540            comment-column))))
541
542 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
543 ;;;
544 ;;; INFERIOR SHELL
545 ;;;
546 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
547
548 (defvar haskell-shell-map nil "The mode map for haskell-shell.")
549
550 (defun haskell-shell ()
551   "Inferior shell invoking Haskell.
552 It is not possible to have more than one shell running Haskell.
553 Like the shell mode with the additional command:
554
555 \\[haskell-run-on-file]\t Runs haskell on the file.
556 \\{haskell-shell-map}
557 Variables controlling the mode:
558
559 haskell-prog-name (default \"hbi\")
560     The string used to invoke the haskell program.
561
562 haskell-use-right-delim (default \"\\\"\")
563 haskell-use-left-delim  (default \"\\\"\")
564     The left and right delimiter used by your version of haskell, for
565     \"load file-name\".
566
567 haskell-process-name (default \"Haskell\")
568     The name of the process running haskell.
569
570 haskell-shell-prompt-pattern (default \"^> *\")
571     The prompt pattern.
572
573 Runs haskell-shell-hook if not nil."
574   (interactive)
575   (if (not (process-status haskell-process-name))
576       (save-excursion                   ; Process is not running
577         (message "Starting Haskell...") ; start up a new process
578         (require 'shell)
579         (set-buffer (make-comint haskell-process-name haskell-prog-name))
580         (erase-buffer)                  ; Erase the buffer if a previous
581         (if haskell-shell-map           ; process died in there
582             ()
583           (setq haskell-shell-map (copy-keymap shell-mode-map))
584           (define-key haskell-shell-map "\C-c\C-f" 'haskell-run-on-file))
585         (use-local-map haskell-shell-map)
586         (make-local-variable 'shell-prompt-pattern)
587         (setq shell-prompt-pattern haskell-shell-prompt-pattern)
588         (setq major-mode 'haskell-shell)
589         (setq mode-name "Haskell Shell")
590         (setq mode-line-format 
591               "-----Emacs: %17b   %M   %[(%m: %s)%]----%3p--%-")
592         (set-process-filter (get-process haskell-process-name) 'haskell-process-filter)
593         (message "Starting Haskell...done.")
594         (run-hooks 'haskell-shell-hook))))
595
596 (defun haskell-process-filter (proc str)
597   (let ((cur (current-buffer))
598         (pop-up-windows t))
599     (pop-to-buffer (concat "*" haskell-process-name "*"))
600     (goto-char (point-max))
601     (if (string= str "\b\b\b  \b\b\b")
602         (backward-delete-char 4)
603       (insert str))
604     (set-marker (process-mark proc) (point-max))
605     (pop-to-buffer cur)))
606
607 (defun haskell-pop-to-shell ()
608   (interactive)
609   (haskell-shell)
610   (pop-to-buffer (concat "*" haskell-process-name "*")))
611
612 (defun haskell-run-on-file (fil)
613   (interactive "FRun Haskell on : ")
614   (haskell-shell)
615   (save-some-buffers)
616   (process-send-string haskell-process-name
617                (concat "load " haskell-use-left-delim (expand-file-name fil)
618                        haskell-use-right-delim ";\n")))
619
620 (defun haskell-save-buffer-use-file ()
621   "Save the buffer, and send a `use file' to the inferior shell
622 running Haskell."
623   (interactive)
624   (let (file)
625     (if (setq file (buffer-file-name))  ; Is the buffer associated
626         (progn                          ; with file ?
627           (save-buffer)
628           (haskell-shell)
629           (process-send-string haskell-process-name
630                        (concat "load " haskell-use-left-delim
631                                (expand-file-name file)
632                                haskell-use-right-delim ";\n")))
633       (error "Buffer not associated with file."))))
634
635 (defvar haskell-tmp-files-list nil
636   "List of all temporary files created by haskell-simulate-send-region.
637 Each element in the list is a list with the format:
638
639       (\"tmp-filename\"  buffer  start-line)")
640
641 (defvar haskell-simulate-send-region-called-p nil
642   "Has haskell-simulate-send-region been called previously.")
643
644 (defun haskell-make-temp-name (pre)
645   (concat (make-temp-name pre) ".m"))
646
647 (defun haskell-simulate-send-region (point1 point2)
648   "Simulate send region. As send-region only can handle what ever the
649 system sets as the default, we have to make a temporary file.
650 Updates the list of temporary files (haskell-tmp-files-list)."
651   (let ((file (expand-file-name (haskell-make-temp-name haskell-tmp-template))))
652     ;; Remove temporary files when we leave emacs
653     (if (not haskell-simulate-send-region-called-p)
654         (progn
655           (setq haskell-old-kill-emacs-hook kill-emacs-hook)
656           (setq kill-emacs-hook 'haskell-remove-tmp-files)
657           (setq haskell-simulate-send-region-called-p t)))
658     (save-excursion
659       (goto-char point1)
660       (setq haskell-tmp-files-list
661             (cons (list file
662                         (current-buffer)
663                         (save-excursion ; Calculate line no.
664                           (beginning-of-line)
665                           (1+ (count-lines 1 (point)))))
666                   haskell-tmp-files-list)))
667     (write-region point1 point2 file nil 'dummy)
668     (haskell-shell)
669     (message "Using temporary file: %s" file)
670     (process-send-string
671      haskell-process-name
672      ;; string to send: load file;
673      (concat "load " haskell-use-left-delim file haskell-use-right-delim ";\n"))))
674
675 (defun haskell-remove-tmp-files ()
676   "Remove the temporary files, created by haskell-simulate-send-region, if
677 they still exist. Only files recorded in haskell-tmp-files-list are removed."
678   (message "Removing temporary files created by haskell-mode...")
679   (while haskell-tmp-files-list
680     (condition-case ()
681         (delete-file (car (car haskell-tmp-files-list)))
682       (error ()))
683     (setq haskell-tmp-files-list (cdr haskell-tmp-files-list)))
684   (message "Removing temporary files created by haskell-mode...done.")
685   (run-hooks 'haskell-old-kill-emacs-hook))
686
687 (defun haskell-send-region ()
688   "Send region."
689   (interactive)
690   (let (start end)
691     (save-excursion
692       (setq end (point))
693       (exchange-point-and-mark)
694       (setq start (point)))
695     (haskell-simulate-send-region start end)))
696
697 (defun haskell-send-buffer ()
698   "Send the buffer."
699   (interactive)
700   (haskell-simulate-send-region (point-min) (point-max)))
701
702 (defun haskell-evaluate-expression (h-expr)
703   "Prompt for and evaluate an expression"
704   (interactive "sExpression: ")
705   (let ((str (concat h-expr ";\n"))
706         (buf (current-buffer)))
707     (haskell-pop-to-shell)
708     (insert str)
709     (process-send-string haskell-process-name str)
710     (pop-to-buffer buf)))
711
712 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
713 ;;;
714 ;;; keywords for jwz's font-look-mode (lemacs 19)
715 ;;;
716 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
717 (setq haskell-font-lock-keywords
718       (list (concat "\\b\\("
719                     (mapconcat 'identity 
720                                '("case" "class" "data" "default" "deriving" "else" "hiding"
721                                  "if" "import" "in" "infix" "infixl" "infixr" "instance"
722                                  "interface" "let" "module" "of" "renaming" "then" "to"
723                                  "type" "where")
724                                "\\|")
725                     "\\)\\b")
726             (list "^\\(#[ \t]*\\(if\\|ifdef\\|ifndef\\|else\\|endif\\|include\\)\\)")
727             (list "\\(^>?\\|\\bwhere\\b\\|\\blet\\b\\)[ \t]*\\(\\(\\w\\|\\s_\\)+\\)\\(\\([^=\n]*\\S.\\)?=\\(\\S.\\|$\\)\\|[ \t]*::\\S.\\).*$"
728                     2 'font-lock-function-name-face)
729             (list "\\b\\(data\\|type\\)\\b[ \t]+\\(\\(\\w\\|\\s_\\)+\\)"
730                      2 'font-lock-type-face)
731             (list (concat "'\\([^\\]\\|\\\\\\([0-9]+\\|"
732                           (mapconcat 'identity
733                                      '("a" "b" "f" "n" "r" "t" "v" "\\\\" "\"" "'" "&")
734                                      "\\|")
735                           "\\|\\^\\([][_^A-Z@\\\\]\\)"
736                           "\\)\\)'") 1 'font-lock-string-face)))
737
738 ;;; font-lock-keywords for literate style files
739
740 (setq haskell-font-lock-keywords-2
741       (list (concat "^>.*\\b\\("
742                     (mapconcat 'identity 
743                                '("case" "class" "data" "default" "deriving" "else" "hiding"
744                                  "if" "import" "in" "infix" "infixl" "infixr" "instance"
745                                  "interface" "let" "module" "of" "renaming" "then" "to"
746                                  "type" "where")
747                                "\\|")
748                     "\\)\\b")
749             (list "^>\\(.*\\(\\bwhere\\b\\|\\blet\\b\\)\\|\\)[ \t]*\\(\\(\\w\\|\\s_\\)+\\)\\(\\([^=\n]*\\S.\\)?=\\(\\S.\\|$\\)\\|[ \t]*::\\S.\\).*$"
750                     3 'font-lock-function-name-face)
751             (list "^>.*\\b\\(data\\|type\\)\\b[ \t]+\\(\\(\\w\\|\\s_\\)+\\)"
752                      2 'font-lock-type-face)
753             (list (concat "^>.*'\\([^\\]\\|\\\\\\([0-9]+\\|"
754                           (mapconcat 'identity
755                                      '("a" "b" "f" "n" "r" "t" "v" "\\\\" "\"" "'" "&")
756                                      "\\|")
757                           "\\|\\^\\([][_^A-Z@\\\\]\\)"
758                           "\\)\\)'") 1 'font-lock-string-face)))
759 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
760 ;;;
761 ;;; END OF Haskell-MODE
762 ;;;
763 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
764 (provide 'haskell-mode)