[project @ 1997-03-14 05:31:07 by sof]
[ghc-hetmet.git] / ghc / CONTRIB / haskell-modes / simonm / ghc / haskell.el
1 ;;; Haskell mode for emacs (c) Simon Marlow 11/1/92
2
3 ;;; To: partain@dcs.gla.ac.uk
4 ;;; Subject: Haskell mode for emacs
5 ;;; Date: Mon, 14 Dec 92 17:41:56 +0000
6 ;;; From: Simon Marlow <simonm@dcs.gla.ac.uk>
7 ;;; 
8 ;;; ...  What it buys you: very little actually, but the nice things are
9 ;;; 
10 ;;; (i)    Pressing line feed indents the next line according to the
11 ;;;        previous one,
12 ;;; (ii)   Pressing Meta-; gives you a comment on the current line,
13 ;;; (iii)  For literate scripts, pressing line feed gives you a bird
14 ;;;        track on the next line if there was one on the previous
15 ;;;        line, and does the indentation
16 ;;; (iv)   For literate scripts, pressing Meta-Tab toggles a bird track
17 ;;;        on or off at the beginning of the current line,
18 ;;; (v)    There's a function for toggling bird tracks on all lines in a
19 ;;;        region.
20 ;;;  (vi)  Emacs says "Haskell" or "Literate Haskell" in the mode line :-)
21 ;;; 
22 ;;; You'll have to make the necessary changes in .emacs to load in the
23 ;;; library automatically (you probably know what to do). ...
24
25 (defvar haskell-mode-map ()
26   "Keymap used in Haskell mode.")
27
28 (defvar haskell-literate-mode-map ()
29   "Keymap used in Haskell literate script mode.")
30
31 (defvar haskell-mode-syntax-table ()
32   "Syntax table for haskell mode.")
33
34 (if haskell-mode-map
35     ()
36   (setq haskell-mode-map (make-sparse-keymap))
37   (define-key haskell-mode-map "\C-j" 'haskell-newline-and-indent))
38
39 (if haskell-literate-mode-map
40     ()
41   (setq haskell-literate-mode-map (make-sparse-keymap))
42   (define-key haskell-literate-mode-map "\C-j" 'haskell-literate-newline-and-indent)
43   (define-key haskell-literate-mode-map "\M-\C-i" 'haskell-literate-toggle-bird-track-line))
44
45 (if haskell-mode-syntax-table
46     ()
47   (let ((i 0))
48     (setq haskell-mode-syntax-table (make-syntax-table))
49     (while (< i ?0)
50       (modify-syntax-entry i "." haskell-mode-syntax-table)
51       (setq i (1+ i)))
52     (while (< i (1+ ?9))
53       (modify-syntax-entry i "_" haskell-mode-syntax-table)
54       (setq i (1+ i)))
55     (while (< i ?A)
56       (modify-syntax-entry i "." haskell-mode-syntax-table)
57       (setq i (1+ i)))
58     (while (< i (1+ ?Z))
59       (modify-syntax-entry i "w" haskell-mode-syntax-table)
60       (setq i (1+ i)))
61     (while (< i ?a)
62       (modify-syntax-entry i "." haskell-mode-syntax-table)
63       (setq i (1+ i)))
64     (while (< i (1+ ?z))
65       (modify-syntax-entry i "w" haskell-mode-syntax-table)
66       (setq i (1+ i)))
67     (while (< i 128)
68       (modify-syntax-entry i "." haskell-mode-syntax-table)
69       (setq i (1+ i)))
70     (modify-syntax-entry ?   " " haskell-mode-syntax-table)
71     (modify-syntax-entry ?\t " " haskell-mode-syntax-table)
72     (modify-syntax-entry ?\n ">" haskell-mode-syntax-table)
73     (modify-syntax-entry ?\f ">" haskell-mode-syntax-table)
74     (modify-syntax-entry ?\" "\"" haskell-mode-syntax-table)
75     (modify-syntax-entry ?\' "w" haskell-mode-syntax-table)
76     (modify-syntax-entry ?_  "w" haskell-mode-syntax-table)
77     (modify-syntax-entry ?\\ "." haskell-mode-syntax-table)
78     (modify-syntax-entry ?\( "()" haskell-mode-syntax-table)
79     (modify-syntax-entry ?\) ")(" haskell-mode-syntax-table)
80     (modify-syntax-entry ?\[ "(]" haskell-mode-syntax-table)
81     (modify-syntax-entry ?\] ")[" haskell-mode-syntax-table)
82     (modify-syntax-entry ?{  "(}1" haskell-mode-syntax-table)
83     (modify-syntax-entry ?}  "){4" haskell-mode-syntax-table)
84     (modify-syntax-entry ?-  "_ 123" haskell-mode-syntax-table)
85     ))
86
87 (defun haskell-vars ()
88   (kill-all-local-variables)
89   (make-local-variable 'paragraph-start)
90   (setq paragraph-start (concat "^$\\|" page-delimiter))
91   (make-local-variable 'paragraph-separate)
92   (setq paragraph-separate paragraph-start)
93   (make-local-variable 'comment-start)
94   (setq comment-start "--")
95   (make-local-variable 'comment-start-skip)
96   (setq comment-start-skip "--[^a-zA-Z0-9]*")
97   (make-local-variable 'comment-column)
98   (setq comment-column 40)
99   (make-local-variable 'comment-indent-hook)
100   (setq comment-indent-hook 'haskell-comment-indent))
101
102 (defun haskell-mode ()
103   "Major mode for editing Haskell programs.
104 Blank lines separate paragraphs, Comments start with '--'. 
105 Use Linefeed to do a newline and indent to the level of the previous line.
106 Tab simply inserts a TAB character.
107 Entry to this mode calls the value of haskell-mode-hook if non-nil."
108   (interactive)
109   (haskell-vars)
110   (setq major-mode 'haskell-mode)
111   (setq mode-name "Haskell")
112   (use-local-map haskell-mode-map)
113   (set-syntax-table haskell-mode-syntax-table)
114   (run-hooks 'haskell-mode-hook))
115
116 (defun haskell-literate-mode ()
117   "Major mode for editing haskell programs in literate script form.
118 Linefeed produces a newline, indented maybe with a bird track on it.
119 M-TAB toggles the state of the bird track on the current-line.
120 Entry to this mode calls haskell-mode-hook and haskell-literate-mode-hook."
121   (interactive)
122   (haskell-vars)
123   (setq major-mode 'haskell-literate-mode)
124   (setq mode-name "Literate Haskell")
125   (use-local-map haskell-literate-mode-map)
126   (set-syntax-table haskell-mode-syntax-table)
127   (run-hooks 'haskell-mode-hook)
128   (run-hooks 'haskell-literate-mode-hook))
129
130 ;; Find the indentation level for a comment..
131 (defun haskell-comment-indent ()
132   (skip-chars-backward " \t")
133   ;; if the line is blank, put the comment at the beginning,
134   ;; else at comment-column
135   (if (bolp) 0 (max (1+ (current-column)) comment-column)))
136
137 ;; Newline, and indent according to the previous line's indentation.
138 ;; Don't forget to use 'indent-tabs-mode' if you require tabs to be used
139 ;; for indentation.
140 (defun haskell-newline-and-indent ()
141   (interactive)
142   (newline)
143   (let ((c 0))
144     (save-excursion
145       (forward-line -1)
146       (back-to-indentation)
147       (setq c (if (eolp) 0 (current-column))))
148     (indent-to c)))                     ;ident new line to this level
149
150 ;;; Functions for literate scripts
151
152 ;; Newline and maybe add a bird track, indent
153 (defun haskell-literate-newline-and-indent ()
154   (interactive)
155   (newline)
156   (let ((bird-track nil) (indent-column 0))
157     (save-excursion
158       (forward-line -1)
159       (if (= (following-char) ?>) (setq bird-track t))
160       (skip-chars-forward "^ \t")
161       (skip-chars-forward " \t")
162       (setq indent-column (if (eolp) 0 (current-column))))
163     (if bird-track (insert-char ?> 1))
164     (indent-to indent-column)))
165
166 ;; Toggle bird-track ][ 
167 (defun haskell-literate-toggle-bird-track-line ()
168   (interactive)
169   (save-excursion
170     (beginning-of-line)
171     (if (= (following-char) ? )
172         (progn (delete-char 1) (insert-char ?> 1))
173       (if (= (following-char) ?>)
174           (progn (delete-char 1) (insert-char ?  1))
175         (progn (insert-char ?> 1) (insert-char ?  1))))))
176
177 (defun haskell-literate-toggle-bird-track-region (start end)
178   (interactive "r") 
179   (save-excursion 
180     (goto-char start) 
181     (while (<= (point) end) 
182       (beginning-of-line)
183       (haskell-literate-toggle-bird-track-line)
184       (forward-line 1))))
185