2 ;; (c) Copyright, Richard McPhee et al.
3 ;; University of Glasgow, February 1993
7 ;; if .hs is not recognised then put the extension in auto-mode-list
9 (if (assoc "\\.hs" auto-mode-alist)
11 (nconc auto-mode-alist '(("\\.hs". haskell-mode))))
13 (if (assoc "\\.hi" auto-mode-alist)
15 (nconc auto-mode-alist '(("\\.hi". haskell-mode))))
17 (if (assoc "\\.gs" auto-mode-alist)
19 (nconc auto-mode-alist '(("\\.gs". haskell-mode))))
21 (defvar haskell-mode-syntax-table nil
22 "Syntax table for haskell-mode buffers.")
24 (defvar haskell-mode-abbrev-table nil
25 "Abbrev table for haskell-mode buffers.")
27 (defvar haskell-mode-map (make-sparse-keymap)
28 "Keymap for haskell-mode-buffers.")
32 ;;; Here are the keymaps used in haskell-mode
34 (define-key haskell-mode-map "\M-;" 'haskell-insert-comment)
35 (define-key haskell-mode-map "\C-c=" 'haskell-insert-concat)
36 (define-key haskell-mode-map "\C-c;" 'set-haskell-comment-column)
37 (define-key haskell-mode-map "\C-c+" 'set-haskell-concat-column)
38 (define-key haskell-mode-map "\C-cn" 'set-haskell-indent-offset)
39 (define-key haskell-mode-map "\C-cl" 'set-haskell-list-offset)
40 (define-key haskell-mode-map "\C-ci" 'set-haskell-if-offset)
41 (define-key haskell-mode-map "\C-ce" 'set-haskell-let-offset)
42 (define-key haskell-mode-map "\C-cc" 'set-haskell-case-offset)
43 (define-key haskell-mode-map "\C-ct" 'set-haskell-then-offset)
44 (define-key haskell-mode-map "\C-co" 'set-haskell-comp-offset)
45 (define-key haskell-mode-map "\C-cw" 'set-haskell-where-offset)
46 (define-key haskell-mode-map "\C-cg" 'goto-line)
47 (define-key haskell-mode-map "\C-j" 'haskell-reindent-then-newline-and-indent)
48 (define-key haskell-mode-map "\t" 'haskell-indent-line)
49 (define-key haskell-mode-map "}" 'electric-haskell-brace)
50 (define-key haskell-mode-map "]" 'electric-haskell-brace)
51 (define-key haskell-mode-map ")" 'haskell-insert-round-paren)
52 (define-key haskell-mode-map "\C-cr" 'haskell-indent-region)
53 (define-key haskell-mode-map "\C-cf" 'haskell-further-indent)
54 (define-key haskell-mode-map "\C-cb" 'haskell-lesser-indent)
55 (define-key haskell-mode-map "\177" 'backward-delete-char-untabify)
56 (define-key haskell-mode-map "\M-\C-\177" 'delete-horizontal-space)
58 (defun haskell-set-local-vars ()
59 "Set the local variables for haskell-mode."
60 (kill-all-local-variables)
62 (setq indent-line-function 'haskell-indent-line)
64 (make-local-variable 'haskell-std-list-indent)
65 ;;Non-nil means indent to the offset, 'haskell-list-offset' in a bracket rather than
66 ;; moving to the next word afer a function name
67 (setq haskell-std-list-indent t)
69 (make-local-variable 'haskell-nest-ifs)
70 ;;Non-nil means that 'if' statements are nested ie. lined up with `if' not `else'.
71 (setq haskell-nest-ifs nil)
73 (make-local-variable 'haskell-align-else-with-then)
74 ;;Non-nil means align an `else' under it's corresponding `then'
75 (setq haskell-align-else-with-then nil)
78 ;;The local vars for 'where' indentation
80 (make-local-variable 'haskell-align-where-with-eq)
81 ;;Non-nil means align a 'where' under it's corresponding equals sign
82 (setq haskell-align-where-with-eq t)
84 (make-local-variable 'haskell-align-where-after-eq)
85 ;;Non-nil means align a 'where' after it's corresponding equals sign
86 (setq haskell-align-where-after-eq nil)
88 (make-local-variable 'haskell-std-indent-where)
89 ;;put the 'where' the standard offset ie. 'haskell-indent-offset'
90 (setq haskell-std-indent-where nil)
93 (make-local-variable 'haskell-always-fixup-comment-space)
94 ;;Non-nil means always insert a (single) space after a comment, even
95 ;; if there is more or less than one.
96 (setq haskell-always-fixup-comment-space t)
99 (make-local-variable 'haskell-indent-offset)
100 ;;Extra indentation for a line continued after a keyword.
101 (setq haskell-indent-offset 4)
103 (make-local-variable 'haskell-list-offset)
104 ;;Extra indentation for continuing a list.
105 (setq haskell-list-offset 4)
107 (make-local-variable 'haskell-comp-offset)
108 ;;Extra indentation for a list comprehension.
109 (setq haskell-comp-offset 4)
111 (make-local-variable 'haskell-case-offset)
112 (setq haskell-case-offset 4)
114 (make-local-variable 'haskell-where-offset)
115 (setq haskell-where-offset 4)
117 (make-local-variable 'haskell-let-offset)
118 (setq haskell-let-offset 4)
120 (make-local-variable 'haskell-then-offset)
121 (setq haskell-then-offset 0)
123 (make-local-variable 'haskell-if-offset)
124 (setq haskell-if-offset 4)
126 (make-local-variable 'haskell-comment-column)
127 (setq haskell-comment-column 35)
129 (make-local-variable 'haskell-concat-column)
130 (setq haskell-concat-column 69)
132 (make-local-variable 'haskell-where-threshold)
133 (setq haskell-where-threshold 35)
135 (make-local-variable 'line-comment)
136 (setq line-comment "-- ")
138 (make-local-variable 'haskell-indent-style)
139 (setq haskell-indent-style "none"))
142 (defun haskell-set-syntax-table ()
143 "Set the syntax table for Haskell-mode."
144 (setq haskell-mode-syntax-table (make-syntax-table))
145 (set-syntax-table haskell-mode-syntax-table)
146 (modify-syntax-entry ?\" "\"")
147 (modify-syntax-entry ?\\ "\\")
148 (modify-syntax-entry ?\' "w")
149 (modify-syntax-entry ?_ "w")
150 (modify-syntax-entry ?# "_")
151 (modify-syntax-entry ?$ "_")
152 (modify-syntax-entry ?% "_")
153 (modify-syntax-entry ?: "_")
154 (modify-syntax-entry ?? "_")
155 (modify-syntax-entry ?@ "_")
156 (modify-syntax-entry ?! "_")
157 (modify-syntax-entry ?^ "_")
158 (modify-syntax-entry ?~ "_")
159 (modify-syntax-entry ?- "_ 12")
160 (modify-syntax-entry ?\n ">")
161 (modify-syntax-entry ?{ "(}")
162 (modify-syntax-entry ?} "){")
163 (set-syntax-table haskell-mode-syntax-table))
167 (defun haskell-mode ()
168 "Major mode for editing Haskell code.
169 Linefeed reindents current line, takes newline and indents.
170 Tab indents current line for Haskell code.
171 Functions are seperated by blank lines.
172 Delete converts tabs to spaces as it moves back.
174 Variables controlling indentation style:
175 haskell-indent-offset
176 Standard extra indentation for continuing Haskell
177 code under the scope of an expression. The default is 4.
180 Extra indentation for indenting in a list. Used if variable
181 haskell-std-list-indent is non-nil. The default is 4.
184 Extra indentation for continuing a list comprehension.
188 Standard extra indentation for continuing Haskell
189 code under the scope of an expression. The default is 4.
192 Standard extra indentation for continuing Haskell
193 code under the scope of a `where'. The default is 4.
196 Standard extra indentation for continuing Haskell
197 code under the scope of a `let'. The default is 4.
200 Standard extra indentation for a `then' beyond
201 its corresponding `if'. The default is 0.
204 Standard extra indentation for continuing Haskell
205 code under the scope of an `if'. The default is 4.
207 haskell-comment-column
208 Column to which line comments `--' will be inserted.
211 haskell-concat-column
212 Column to which concatenation operator `++' will be inserted.
215 haskell-where-threshold
216 Column beyond which a `where' will be indented to the
217 start of a line (to avoid spilling over lines).
220 set-haskell-indent-offset (C-c i)
221 Changes the default value of the local variable,
222 haskell-indent-offset. May be a number from 0-10.
224 set-haskell-list-indent (C-c l)
225 Change the value of the local variable,
226 haskell-list-offset. May be a number from 0-100.
228 set-haskell-comment-column (C-x ;)
229 Changes the value of the local variable,
230 haskell-comment-column. May be any number from 0-100."
233 (haskell-set-local-vars)
234 (haskell-set-syntax-table)
235 (use-local-map haskell-mode-map)
236 (setq major-mode 'haskell-mode)
237 (setq mode-name "Haskell")
238 (define-abbrev-table 'haskell-mode-abbrev-table ()))
243 ;;; Returns the indentation column for a comment on this line.
244 ;;; The point is positioned at the last char of any code on the line.
246 (defun haskell-comment-indent ()
247 "Returns the indentation for a comment on the given line.
248 If the line has code on it or the point is not at the beginning of the line,
249 then indent to indent-column.
250 Otherwise, don't indent."
251 (cond ((or (haskell-code-on-linep)
253 ;;There is code before the haskell-comment-column
254 ;; or not at the beginning of the line
255 ;;Return the largest of
256 ;; the current column +1 and the haskell-comment-column
257 (max (1+ (current-column))
258 haskell-comment-column))
260 ;;Otherwise, return 0
265 ;;; Returns whether a comment is on the current line
266 ;;; Search from bol, and beware of "--", {-- etc!
267 ;;; DOES NOT RECOGNISE {- COMMENTS YET or -- within a string
269 (defun haskell-comment-on-linep ()
270 "Returns the truth value of whether there is a '--' comment on the current line."
273 (looking-at ".*--")))
276 ;;; This doesn't account for comments '{-'. Test explicitly if you use this function!
278 (defun haskell-code-on-linep ()
279 "Returns a truth value as to whether there is code on the current line."
283 ;; Code on line if not looking at a comment directly
284 ;; and the line is not blank
286 (looking-at "^[ \t]*--")
287 (looking-at "^[ \t]*$")))))
290 ;;; Insert a Haskell "--" comment on the current line.
291 ;;; Move to the comment position if there's already a comment here.
292 ;;; Otherwise, the comment is inserted either at the comment column
293 ;;; or one column after the last non-space character, whichever is further
295 ;;; This function is executed by M-;
297 (defun haskell-insert-comment ()
298 "Inserts a '--' comment on the given line."
300 (cond ((haskell-comment-on-linep)
301 ;;There is a comment on the line
302 ;;Just reindent existing comment
303 (haskell-reindent-comment))
305 (if (haskell-code-on-linep)
306 ;;There is code on the line
307 ;; and guarenteed that a comment
308 ;; does not already exist.
309 ;;Move to the last nonspace char
310 ;; (there may be spaces after the last char)
313 (skip-chars-backward " \t")))
314 ;;Indent to required level
315 ;; and insert the line comment '--'
316 (indent-to (haskell-comment-indent))
317 (insert line-comment))))
320 ;;; Reindents a comment.
321 ;;; The comment is indented according to the normal rules.
322 ;;; Skips over ---- and following spaces or tabs
324 (defun haskell-reindent-comment ()
325 "Indents a comment on a line to keep it at haskell-comment-column,
327 It is guaranteed that a comment exists on the current line."
329 ;;Go back to beginning of comment
330 (re-search-forward "--")
332 ;;Delete all spaces and reindent to
333 ;; the correct location.
334 (delete-horizontal-space)
335 (indent-to (haskell-comment-indent))
336 ;;Move past the comment and insert
337 ;; only one space between it and the text.
338 ;;Leave point just after comment.
339 (skip-chars-forward "- \t")
340 (if haskell-always-fixup-comment-space
347 ;;; Inserts a haskell concatenation operator, `++', at the
348 ;;; column dictated by haskell-concat-column
350 (defun haskell-insert-concat()
351 "Inserts a `++' operator on the given line."
354 (skip-chars-backward " \t")
355 ;;Indent to required level
356 ;; and insert the concat operator `++'
357 (indent-to (haskell-concat-indent))
362 ;;; Returns the indentation column for a concatenation operator on this line.
363 ;;; The point is positioned at the last char of any code on the line.
365 (defun haskell-concat-indent ()
366 "Returns the indentation for a concat operator on the given line."
367 (max (1+ (current-column))
368 haskell-concat-column))
372 ;;; Returns the indentation of the current line of haskell code.
373 ;;; A blank line has ZERO indentation
375 (defun haskell-current-indentation ()
376 "Returns the indentation for the current haskell line. A blank line has
380 (if (looking-at "^[ \t]*$")
382 ;; so the indentation is zero
384 ;;Otherwise find the normal value of indentation
385 (current-indentation))))
389 ;;; Returns the indentation of the previous line of haskell code.
390 ;;; A blank line has ZERO indentation
392 (defun haskell-previous-indentation ()
393 "Returns the previous line's indentation as Haskell indentation."
396 ;;Not at the start of the buffer
397 ;; so get the previous lines indentation
400 (haskell-current-indentation))
401 ;;We are at the start of buffer
402 ;;There is no previous line; Indent is zero
407 ;;; Move back to the last line which is aligned in the left column.
408 ;;; Ignores comments and blank lines.
409 ;;; The point is left at the beginning of the line.
411 (defun haskell-back-to-zero-indent ()
412 "Moves point to last line which has zero as indentation."
413 ;;Not at the beginning of buffer.
414 ;;Continue to go to the previous line until
415 ;; we find a line whose indentation is non-zero.
416 ;;Blank lines and lines containing only comments
420 (or (not (zerop (haskell-current-indentation)))
421 (looking-at "^[ \t]*\\($\\|--\\)"))
423 (haskell-backward-to-noncomment)
424 (beginning-of-line)))
428 ;;; Find the last symbol, usually an equality.
430 ;;; Note: we check for "=" as a complete WORD (and ignore
431 ;;; comments) when searching for this. Ie. an `=' may be
432 ;;; surrounded only by a letter, digit, or whitespace .
433 ;;; Strings are not considered.
434 ;;; Don't go beyond the first character in the (possibly narrowed) buffer.
435 ;;; From the beginning of the line,
436 ;;; find the comment position (or end-of-line)
437 ;;; search forward to this position, looking for a "where"
438 ;;; If one's found, then search forward for "\b=\b"
439 ;;; If there's no equality sign then
440 ;;; search forward from the start of the line for an equals
441 ;;; Otherwise we found it.
442 ;;; If there's no where then search forward for an equals, as above.
444 (defun haskell-back-to-symbol (exp)
445 "Goes backward from point until a symbol, EXP, is found.
446 The point is left at the first symbol matching the context
447 of the haskell code."
449 (symbol (concat "[ \ta-z0-9A-Z]" exp "[ \t\na-z0-9A-Z]"))
452 (zero-indent (save-excursion
453 (haskell-back-to-zero-indent)
455 (initial-depth (car (parse-partial-sexp
459 (while (and (not found)
460 (> (point) zero-indent))
461 ;;Not found and point > point min
462 ;;Record the limit of search for the beginning and
464 (setq eol-limit (point))
466 (setq bol-limit (point))
467 (goto-char eol-limit)
468 (re-search-backward "\\bwhere\\b" bol-limit 't)
469 ;;Search back from the end of the line
470 ;; to find the most recent 'where'.
472 (cond ((and (re-search-backward symbol bol-limit 't)
474 (car (parse-partial-sexp
477 ;;Found a symbol sign surrounded by
478 ;; a letter, digit or space only, or at the
479 ;; beginning of the buffer and they are at
480 ;; the same depth level
482 ((and (re-search-backward symbol bol-limit 't)
484 (car (parse-partial-sexp
487 ;; Found a symbol and it is not in any parens
489 ;;Otherwise, go back a line.
490 (t (haskell-backward-to-noncomment))))
495 ;;; Goes back to the last keyword. The point is left at the
496 ;;; beginning of the keyword.
497 ;;; The words recognised are:
498 ;;; `case',`of',`where',`let',`in',`if',`then',`else'
500 (defun haskell-back-to-keyword ()
501 "Goes backward from point until a keyword is found.
502 The point is left after the first keyword."
506 (zero-indent (save-excursion
507 (haskell-back-to-zero-indent)
509 (initial-depth (car (parse-partial-sexp
513 (while (and (not found)
514 (>= (point) zero-indent))
515 ;;Not found and point > point min
516 ;;Go back past any comment.
517 ;;Record the limit of search for the beginning and
519 (setq eol-limit (point))
521 (setq bol-limit (point))
522 (goto-char eol-limit)
523 (if (and (re-search-backward
524 "\\b\\(case\\|of\\|where\\|let\\|in\\|if\\|then\\|else\\)\\b"
527 (car (parse-partial-sexp
530 ;;Found a keyword and it is at the same level as the initial position
534 ;;Otherwise, go back a line.
535 (haskell-backward-to-noncomment)))))
539 ;;; Returns the end of line (point) of the current line, excluding any
540 ;;; line comments on it.
542 (defun haskell-eol ()
543 "Returns the end (point) of the current line, excluding any line comments."
546 (let ((eol-limit (point)))
548 (if (search-forward "--" eol-limit 'move-to-eol)
550 ;;So move to the beginning of the comment
551 ;;If fail then move to end of line
557 ;;; Returns whether or not the current line contains an equality outwith a
558 ;;; comment. The equality may only be surrounded by a letter, digit or
561 (defun haskell-looking-at-eqp ()
562 "Returns whether or not the current line contains an equality outwith a
566 (re-search-forward "[ \ta-z0-9A-Z]=[ \t\na-z0-9A-Z]" (1+ (haskell-eol)) 't)))
569 ;;; This function does not require all keywords, just those which
570 ;;; may have a bracket before them.
571 (defun haskell-looking-at-keywordp ()
572 "Returns whether or not there is a keyword after the point outwith a
576 "\\(\\(=>\\|=\\|++\\|->\\|<-\\|::\\)\\|\\b\\(case\\|of\\|if\\|then\\|else\\|let\\|in\\)\\b\\)"
580 ;;; This function returns whether or not there is a keyword contained in
581 ;;; the region START END. START < END.
583 (defun haskell-keyword-in-regionp (start end)
584 "Returns whether or not there is a keyword between START and END."
588 (eol-limit (haskell-eol)))
589 (while (and (not found) (< (point) end))
590 (if (> eol-limit end)
591 (setq eol-limit end))
592 (if (re-search-forward
593 "\\b\\(case\\|of\\|if\\|then\\|else\\|let\\|in\\)\\b"
596 ;;Otherwise, have not found a keyword. Now at haskell-eol.
598 ;;We still have an area to search
599 ;; so go forward one line
603 (setq eol-limit (haskell-eol))))))
604 ;;found is `t' or point >= end
608 ;;; Goes back to the last line which is not entirely commented out.
609 ;;; The point is left just before the comment.
611 (defun haskell-backward-to-noncomment ()
612 "Sets the point to the last char on the line of Haskell code before a comment."
615 (while (and comment (> (point) limit))
616 ;; comment is true and point > limit
618 (if (< (forward-line -1) 0)
619 ;;This was the first line in the buffer
621 ;;Otherwise, this was not the first line
622 (if (not (looking-at "^[ \t]*\\($\\|--\\)"))
623 ;;There is not a comment at the beginning of the line
624 ;; and the line is not blank
626 ;;The line is either blank or has code on it.
628 (goto-char (haskell-eol))))))
635 ;;; Indents a region (by applying "tab" to each line).
636 ;;; The marker upper-marker is set to the end of the region.
637 ;;; We indent from the beginning of the region to this marker.
638 ;;; Implements C-c r.
640 (defun haskell-indent-region ()
641 "Indents the region between the point and mark."
643 (let ((lower-limit (min (point) (mark)))
644 (upper-limit (max (point) (mark))))
645 (indent-region lower-limit upper-limit 'nil)))
650 ;;; This actually indents a line.
651 ;;; Eventually it will handle a line split at any point,
653 (defun haskell-indent-line ()
654 "Indent current line as Haskell code.
655 Keeps the point at the same position on the line unless the
656 point is less then the current indentation, in which case the
657 point is moved to the first char."
660 (let ((indent (haskell-calculate-indentation)))
662 (delete-horizontal-space)
663 ;;Kill any spaces that may preceed the code
664 ;; and reindent to the correct level.
666 (if (< (current-column) (current-indentation))
667 ;;The point is in the indentation
668 ;; so move to the first char on the line
669 (move-to-column (current-indentation))))
673 ;;; This is the haskell version of the Emacs function
674 ;;; reindent-then-newline-and-indent. It was necessary
675 ;;; to write this because the Emacs version has the
676 ;;; terrible property of deleting whitespace BEFORE
677 ;;; reindenting the original line.
679 (defun haskell-reindent-then-newline-and-indent ()
680 "Reidents the current line of Haskell code then takes a
681 newline and indents this new line."
683 (skip-chars-backward " \t")
684 (haskell-indent-line)
686 (delete-horizontal-space)
687 (haskell-indent-line))
691 ;;; Returns whether the first word of the last line with zero indentation
692 ;;; is the same as the first word of the current line.
693 ;;; This function is based on the (reasonable?) assumption that
694 ;;; a function definition occurs on the left hand margin.
695 ;;; This is not quit reasonable since recusive functions are not
698 (defun haskell-continued-fn-defp ()
699 "Returns whether the first word on the last line with zero indentation
700 matches the first word on the current line."
703 (skip-chars-forward " \t")
704 ;;Goto the first non space char
705 (haskell-word-eq (point)
708 (haskell-back-to-zero-indent)
712 ;;; Returns whether two words are the same.
713 ;;; The beginning of both words are given as their
714 ;;; respective points in the buffer.
716 (defun haskell-word-eq (current-pos previous-pos)
718 (goto-char previous-pos)
719 ;;We shall compare the two words starting
720 ;; at previous-pos and current-pos.
721 (while (and OK (looking-at "\\S-"))
722 ;;OK and looking at a word constituent
723 (if (eq (char-after current-pos)
724 (char-after previous-pos))
725 ;;The two chars are the same
727 ;;Increment the two postions
728 ;; and update location of point
729 (setq current-pos (1+ current-pos))
730 (setq previous-pos (1+ previous-pos))
731 (goto-char previous-pos))
732 ;;The two chars are different
733 ;; so set OK to be false
736 ;;Return the value of OK
742 ;;; This function returns the column of the last unbalanced
744 ;;; It is called when an keyword is found. The point is
745 ;;; initially placed before the corresponding keyword.
746 ;;; The function looks at every word to see if it is a
747 ;;; `let' or `in'. Each word must be outwith a comment.
749 (defun haskell-last-unbalanced-key-column (open close)
750 "Returns the column of the last unbalanced keyword, open."
752 (let ((original-pos (point))
753 (bol-limit (save-excursion
755 (setq bol-limit (point))))
757 (setq open (concat "\\b" open "\\b"))
758 (setq close (concat "\\b" close "\\b"))
761 (> (point) (point-min)))
763 (if (< (point) bol-limit)
764 ;;Moved past the beginning of line limit
765 ;; so go back to the previous line past
768 (goto-char original-pos)
769 (haskell-backward-to-noncomment)
770 (setq original-pos (point))
771 (setq bol-limit (save-excursion
774 ;;Otherwise, still on the same line
775 (if (looking-at open)
776 ;;This word is an open keyword
777 (setq depth (1- depth))
779 (if (looking-at close)
780 ;;This word is a close keyword
781 (setq depth (1+ depth))))))
783 (if (string= open "\\bif\\b")
784 ;;The argument is `if'
785 (if (not (save-excursion (skip-chars-backward " \t") (bolp)))
786 ;;There is something before the `if'
787 (if (and (save-excursion
789 (looking-at "\\belse\\b"))
790 (not haskell-nest-ifs))
791 ;;There is an `else' before the 'if'
799 ;;; Return the indentation for a line given that we expect a `where'.
800 ;;; The point lies on the corresponding symbol
801 ;;; that the `where' scopes over.
803 (defun haskell-indent-where ()
804 "Return the indentation for a line, given that we expect a `where'
806 (let ((symbol (if (looking-at "=")
810 (cond ((or haskell-std-indent-where
811 (> (current-column) haskell-where-threshold))
812 ;;Set indentation as the sum of the previous
813 ;; line's layout column and the standard offset
814 ;; (ie. 'haskell-where-offset)
817 (cond ((looking-at (concat "^[ \t]*" symbol))
818 ;;The line starts with the symbol
819 (setq indent (current-indentation)))
820 ((looking-at "^[ \t]*where\\b")
821 ;;The line starts with a 'where'
823 (skip-chars-forward " \t")
824 (setq indent (+ (current-column) haskell-where-offset)))
826 ;;The line begins on the layout column
827 (setq indent (+ (current-indentation)
828 haskell-indent-offset))))))
829 ((or haskell-align-where-with-eq
830 haskell-align-where-after-eq)
831 (if (looking-at (concat symbol "[ \t]*$"))
832 ;;The symbol is at the end of the line
833 (setq indent (+ (current-indentation)
834 haskell-where-offset))
836 ;;Set the indentation as required
837 (if haskell-align-where-after-eq
838 (skip-chars-forward (concat symbol " \t")))
839 (setq indent (current-column))))))))
843 ;;; Calculates the indentation for the current line.
844 ;;; When we come here, we are in a line which we want to indent.
845 ;;; We should leave the point at the same relative position it
846 ;;; was in before we called the function, that is, if a line
847 ;;; is already correctly indented, nothing happens!
849 ;;; The main problems are handling "where" definitions
850 ;;; and the syntax of expressions when these are continued
851 ;;; over multiple lines (e.g. tuples, lists, or just plain
852 ;;; bracketed expressions). Watch out for let ... in, too!
854 ;;; For example, think about the following tricky cases:
858 ;;; f x = [ x + y, <NL>
862 ;;; f x = [ -- start of a large list
863 ;;; -- which I'm commenting in as I go
866 (defun haskell-calculate-indentation ()
867 "Returns the indentation level for the current line of haskell code."
870 (eol-position (point)))
873 ;;We are at the beginning of the buffer so do nothing at all
876 ((looking-at "^[ \t]*--")
877 ;;There is a comment on the line by itself
878 ;;Leave it the way it is
879 (setq indent (current-indentation)))
881 ((looking-at "^[ \t]*\\(data\\|type\\|module\\|import\\|instance\\)\\b")
882 ;;There is a 'data', 'type', 'module' or 'import' at start of line
885 ((haskell-continued-fn-defp)
886 ;;This is clearly same function
887 ;; so set indent to be 0
890 ((looking-at "^[ \t]*[]}]")
891 ;;There is a "]" or "}" at the start of the line
892 (let ((state (parse-partial-sexp (match-end 0)
894 (haskell-back-to-zero-indent)
896 (if (>= (car state) 0)
897 ;;Since the point is just after a parenthesis
898 ;; it has a match if the depth is >= 0
900 (goto-char (nth 2 state))
904 (skip-chars-backward " \t")
906 ;;There is something before the brace.
908 (let ((initial-pos (point)))
911 "\\(let\\|where\\)"))
912 ;;The word is not `where' or `let'
915 (goto-char initial-pos)
916 (skip-chars-forward " \t"))))))
917 (setq indent (current-column)))
920 ((looking-at "^[ \t]*\\(->\\|=>\\)")
921 ;; '->' or '=>' at start of line
923 (haskell-backward-to-noncomment)
924 ;;Go back to previous line
925 (let ((eol-limit (point)))
927 (if (re-search-forward "::" eol-limit 't)
928 ;;There is a '::' on this (previous) line
929 ;; set indent to be at the start of it
930 (setq indent (- (current-column) 2))
931 ;;Otherwise copy this (previous) line's indentation
932 (setq indent (current-indentation))))))
934 ((looking-at "^[ \t]*where\\b")
935 ;;There is a 'where' at the start of the line
936 ;;Look for the equality (which will not
938 (haskell-backward-to-noncomment)
939 (goto-char (max (save-excursion
940 (haskell-back-to-symbol "=")
943 (haskell-back-to-symbol "->")
945 (setq indent (haskell-indent-where)))
947 ((looking-at "^[ \t]*then\\b")
948 ;;The first thing on the line is a `then'
949 (setq indent (+ (haskell-last-unbalanced-key-column "if" "then")
950 haskell-then-offset)))
952 ((looking-at "^[ \t]*else\\b")
953 ;;The first thing on the line is a `else'
954 (if haskell-align-else-with-then
955 (setq indent (haskell-last-unbalanced-key-column "then" "else"))
956 (setq indent (haskell-last-unbalanced-key-column "if" "else"))))
958 ((looking-at "^[ \t]*|")
959 ;;There is a `|' at beginning of line
962 (parse-partial-sexp (save-excursion
963 (haskell-back-to-zero-indent)
966 (if (not (or (nth 3 state) (nth 4 state)))
967 ;;Not in a comment or string
968 (if (> (car state) 0)
969 ;;In an unbalanced parenthesis.
971 (goto-char (nth 1 state))
972 ;;Move to the beginning of the unbalanced parentheses
973 (if (and (looking-at "\\[")
974 (search-forward "|" (haskell-eol) 't))
975 ;;It is a list comprehension
976 (setq indent (1- (current-column)))
977 (setq indent (+ (current-column)
978 haskell-comp-offset))))
979 ;;Otherwise, not in an unbalanced parenthesis
980 (setq indent (save-excursion
981 (haskell-back-to-symbol "=")
982 (cond ((not (looking-at "="))
983 ;;Did not find an equals
984 (+ (haskell-previous-indentation)
985 haskell-indent-offset))
988 (looking-at "^[ \t]*data\\b"))
989 ;;There is a `data' at beginning
990 (setq indent (current-column)))
994 "|" (haskell-eol) 't))
995 ;;There is a `|' on this line
996 ;; so set this to be the indent
998 (goto-char (match-beginning 0))
1001 ;;Otherwise, set `=' as indent
1002 (current-column))))))))))
1004 ((looking-at "^[ \t]*=")
1005 ;;There is an equals at the start of the line
1006 ;;Set the indentation to be the previous line's
1007 ;; indentation plus the standard offset
1008 (setq indent (+ haskell-indent-offset
1009 (haskell-previous-indentation))))
1011 ((looking-at "^[ \t]*in\\b")
1012 ;;The line starts with 'in'
1014 (setq indent (haskell-last-unbalanced-key-column "let" "in")))
1016 ((looking-at "^[ \t]*of\\b")
1017 ;;The line starts with `of'
1019 (setq indent (haskell-last-unbalanced-key-column "case" "of")))
1021 ((looking-at "^.*::")
1022 ;;There is a '::' in the line
1023 ;;There are several possibilities for indentation
1024 (if (looking-at "[ \t]*::")
1025 ;;The '::' is the first thing on the line
1026 ;; so set indent to be the previous line's
1027 ;; indentation plus the standard offset
1028 (setq indent (+ (haskell-previous-indentation)
1029 haskell-indent-offset))
1031 ;;Otherwise, the '::' is contained in the line somewhere
1032 ;; so use contextual indentation
1033 (setq indent (haskell-context-indent)))))
1036 ;;Do not recognise the first word on the line.
1037 (setq indent (haskell-context-indent))))
1039 indent))) ;return indent as indentation value
1043 ;;; Returns the indentation for the current line by looking at the
1044 ;;; previous line to give clues to the indentation.
1046 (defun haskell-context-indent ()
1047 "Returns the indentation for the current line by looking at
1048 the previous line to dictate the indentation."
1050 (let ((original-position (point))
1054 ;;At the beginning of the buffer
1056 ;;Otherwise, we are not at the beginning of the buffer
1057 (haskell-backward-to-noncomment)
1058 (let ((eol-limit (point))
1059 ;;Record the (upper) limit for any search on this line
1061 (paren-indent 'nil))
1062 ;;`paren-indent' flags whether we are indenting a list or not
1064 (setq bol-limit (point))
1065 ;;Record the (lower) limit for any search on this line
1066 (goto-char eol-limit) ;goto the end of the line
1069 (goto-char eol-limit)
1070 (and (re-search-backward
1071 "[])][^][()]*" bol-limit 't)
1073 (goto-char (match-beginning 0))
1074 (not (haskell-looking-at-keywordp)))))
1076 ;;There is a close parenthesis at the end of the line
1077 ;; followed by anything except "(", ")", "[", "]"
1080 ;;Search back for the close parenthesis
1081 ;; and move to just after it.
1082 (re-search-backward "[])]" bol-limit 't)
1085 (parse-partial-sexp (save-excursion
1086 (haskell-back-to-zero-indent)
1089 (if (not (or (nth 3 state) (nth 4 state)))
1090 ;;Not in a comment or string
1091 (if (>= (car state) 0)
1092 ;;The parenthesis has a match
1094 (goto-char (nth 2 state))
1095 ;;Move to the beginning of the parentheses
1096 ;; as this new line will determine
1097 ;; further indentation
1098 (if (zerop (car state))
1099 ;;This paren closes all unbalanced parens
1101 ;; the eol of last line with an equality.
1103 (setq eol-limit (point))
1105 (max (save-excursion
1106 (haskell-back-to-symbol "=")
1109 (haskell-back-to-keyword)
1111 (goto-char eol-limit))
1112 ;;esle just go to the end of the line
1113 (goto-char (haskell-eol)))
1114 (setq paren-indent 't)
1115 ;;Set 'paren-indent' to true to indicate we
1116 ;; are indenting a list.
1117 (setq eol-limit (point))
1119 (setq bol-limit (point))
1120 ;;Reduce the scope of any later
1122 ;; exclude the balanced parentheses
1123 ;; by making this point
1124 ;; be the eol-limit.
1125 (goto-char eol-limit)))))))
1127 ;;This cond expression is structured, to an
1128 ;; extent, such that the keywords with highest
1129 ;; indentation precedence come first. Order is important.
1130 ;;In each condition, the point of match is noted so
1131 ;; that we can see if this point is in a string.
1132 (let ((indent-point (point)))
1133 (cond ((re-search-backward "\\bof\\b" bol-limit 't)
1134 ;; `of' is contained in previous line
1135 (setq indent-point (point))
1136 (if (looking-at "of[ \t]*$")
1137 ;;`of' at end of line
1138 (setq indent (+ (haskell-last-unbalanced-key-column
1140 haskell-case-offset))
1141 ;;Otherwise, `of' is in line
1143 (skip-chars-forward " \t")
1144 (setq indent (current-column))
1145 (setq indent (list indent))))
1147 ((re-search-backward
1148 "\\bthen[ \t]*$" bol-limit 't)
1149 ;;There is a `then' at the end of the line.
1150 (setq indent-point (point))
1151 (if haskell-align-else-with-then
1152 ;;We want to align the `else' (to follow) with the `then'
1153 (setq indent (+ (current-column)
1155 (setq indent (+ (haskell-last-unbalanced-key-column
1157 haskell-if-offset))))
1158 ;; This was here but don't know why (setq indent (list indent))))
1161 (and (re-search-backward "\\bif\\b" bol-limit 't)
1162 (setq indent-point (point))
1163 (not (re-search-forward "\\bthen\\b" eol-limit 't))))
1164 ;;There is an `if' on the (previous) line and the line does
1165 ;; not have a `then' on it.
1166 (setq indent (+ (haskell-last-unbalanced-key-column
1168 haskell-then-offset)))
1171 (and (re-search-backward "\\bif\\b" bol-limit 't)
1172 (setq indent-point (point))
1173 (not (re-search-forward "\\belse\\b" eol-limit 't))))
1174 ;;There is an `if' on the (previous) line (the line may
1175 ;; have a `then' on it) and does not have an else on it.
1176 (if (re-search-backward "\\bthen\\b" bol-limit 't)
1177 ;;There is a then on the line and it is followed by
1181 (skip-chars-forward " \t")
1182 (setq indent (current-column)))
1183 (if haskell-align-else-with-then
1184 ;;We want to align the `else' with the `then'
1185 (setq indent (haskell-last-unbalanced-key-column
1187 (setq indent (haskell-last-unbalanced-key-column
1190 ((re-search-backward "\\b\\(let\\|in\\)\\b" bol-limit 't)
1191 ;; 'let' or 'in' is contained in the (previous) line
1192 (setq indent-point (point))
1193 (forward-word 1) ;skip past the word
1194 (skip-chars-forward " \t{")
1195 (if (looking-at "\\($\\|--\\)")
1196 ;;looking-at eol or comment
1199 (setq indent (+ (current-column)
1200 haskell-let-offset)))
1201 (setq indent (current-column))))
1203 ((re-search-backward
1204 "\\belse[ \t]*$" bol-limit 't)
1205 ;;There is a `else' at end of line
1206 (setq indent-point (point))
1208 (goto-char eol-limit)
1210 (setq indent (+ (current-column)
1211 haskell-if-offset))))
1213 ((re-search-backward
1214 "\\belse\\b" bol-limit 't)
1215 ;;There is a `else' on the line with no if or then
1216 (setq indent-point (point))
1219 (skip-chars-forward " \t")
1220 (setq indent (current-column))))
1226 ;;There is a 'then' at beginning of line
1227 (setq indent-point (point))
1228 (setq indent (current-indentation)))
1232 (looking-at "^[ \t]*else[ \t]*if\\b"))
1233 (setq indent-point (point))
1234 ;;There is an 'else if' at start of (previous) line
1237 (if haskell-nest-ifs
1240 (skip-chars-forward " \t")
1241 (setq indent (current-column)))
1242 (skip-chars-forward " \t")
1243 (setq indent (current-column)))))
1245 ((re-search-backward "\\bcase\\b" bol-limit 't)
1246 ;;There is a 'case' on the previous line
1247 ;; so copy this line's indentation and add on
1248 ;; the offset unless there is not an of.
1249 (setq indent-point (point))
1250 (setq indent (+ (current-column)
1251 haskell-case-offset)))
1255 (looking-at "^\\(instance\\|class\\)\\b"))
1256 ;;This (previous) line has an 'instance' or 'class' at start
1257 ;; so just set indentation to be this line indentation
1258 ;; plus the standard offset
1259 (setq indent-point (point))
1260 (setq indent (+ (current-indentation)
1261 haskell-indent-offset)))
1263 ((re-search-backward "where\\b" bol-limit 't)
1264 ;;There is a 'where' on the (previous) line
1265 (setq indent-point (point))
1266 (if (looking-at "where[ \t]*$")
1267 ;;There is nothing after the 'where'
1268 ;; so set indent to be this column
1269 ;; (ie. the column of the 'w')
1270 ;; plus the standard offset
1272 (skip-chars-backward " \t")
1274 ;;The 'where' is the only thing on the line.
1275 (setq indent (+ (current-column)
1276 haskell-where-offset))
1277 ;;Otherwise, the 'where' is at the end
1278 ;; of the line and there is code before it.
1279 ;;Look before the 'where' for the symbol
1282 (goto-char (max (save-excursion
1283 (haskell-back-to-symbol "=")
1286 (haskell-back-to-symbol "->")
1288 (setq indent (haskell-indent-where)))
1290 ;;Otherwise, go past the 'where'
1291 ;; and goto the last non space character.
1292 ;;Set this column to be the indentation.
1294 (skip-chars-forward " \t")
1295 (setq indent (current-column))))
1297 ((re-search-backward
1298 "[ \ta-z0-9A-Z]=[ \t]*$" bol-limit 't)
1299 ;;There is an equals is at the end of line
1300 ;; so make the indentation be this line's indentation
1301 ;; plus the standard offset
1302 (setq indent-point (point))
1303 (setq indent (+ (current-indentation)
1304 haskell-indent-offset)))
1306 ((re-search-backward
1307 "[ \ta-z0-9A-Z]\\+\\+[ \t]*$" bol-limit 't)
1308 ;;There is a concat operator at the end of line
1309 ;; so make the indentation be this line's indentation
1310 (setq indent-point (point))
1311 (setq indent (current-indentation)))
1316 "^[ \t]*=[ \ta-z0-9A-Z]"))
1317 ;;There is an equals is at the beginning of line
1318 ;; so make the indentation be the previous line's
1319 ;; indentation unless the previous line's
1320 ;; indentation is zero.
1321 (setq indent-point (point))
1323 (haskell-backward-to-noncomment)
1324 (if (zerop (current-indentation))
1325 (setq indent (+ (current-indentation)
1326 haskell-indent-offset))
1327 (setq indent (haskell-current-indentation)))))
1329 ((re-search-backward "|" bol-limit 't)
1330 ;;There is an `|' on this line.
1331 (setq indent-point (point))
1333 (goto-char original-position)
1334 (looking-at "^[ \t]*\\($\\|--\\||\\)"))
1335 ;;The original line is empty or has a `|' at the
1336 ;; start. So set indent to be first `|' on this line
1338 (goto-char bol-limit)
1339 (re-search-forward "|" eol-limit 't)
1340 (setq indent (1- (current-column))))
1341 ;;Otherwise set indent to be this (previous) line's
1344 ((re-search-backward "->" bol-limit 't)
1345 ;;There is a `->' in the line.
1346 ;;This may be from a `case' or a
1347 ;; type declaration.
1348 (setq indent-point (point))
1350 (if (re-search-backward "::" bol-limit 't)
1351 ;;There is a '::' on this line
1352 (if (looking-at ".*->[ \t]*$")
1353 ;;The '->' is at the end of line.
1354 ;;Move past the '::' and any spaces
1355 ;; and set indent to be this column.
1357 (skip-chars-forward ": \t")
1358 (setq indent (current-column)))
1359 ;;Otherwise, the '->' is not at end of line
1360 ;; so copy the indentation
1361 (setq indent (haskell-context-indent)))
1363 ;;Otherwise, there is not a
1364 ;; `::' on this line so copy this
1365 ;; (previous) indentation.
1366 (setq indent (haskell-context-indent)))))
1368 ((re-search-backward "::" bol-limit 't)
1369 ;;There is an '::' on this line.
1370 ;;We know that the line does not end with '->'.
1371 (setq indent-point (point))
1372 (if (looking-at "::[ \t]*$")
1373 ;;The '::' is at the end of the line
1374 ;; so set indent to be this line's
1375 ;; indentation plus the offset.
1376 (setq indent (+ (current-indentation)
1377 haskell-indent-offset))
1378 ;;Otherwise the `::' is in the line
1379 (setq indent (current-indentation))))
1381 ((re-search-backward
1382 "\\b\\(import\\|class\\)\\b"
1384 ;;There is an `import' or `class' on the line.
1385 ;;Copy this indentation.
1386 (setq indent-point (point))
1387 (setq indent (current-indentation)))
1390 (haskell-looking-at-eqp)
1393 (looking-at "^[ \t]*$")))
1394 ;;There is an '=' on the line
1396 (setq indent-point (point))
1397 (cond ((save-excursion
1399 (looking-at "^[ \t]*data\\b"))
1400 ;;`data' at start of line
1402 (haskell-back-to-symbol "=")
1403 (setq indent (current-column)))
1404 ((zerop (current-indentation))
1405 ;;If the indentation is zero, we expect a `where'
1406 (goto-char eol-limit)
1407 (haskell-back-to-symbol "=")
1408 (setq indent (haskell-indent-where)))
1409 ((looking-at "^[ \t]*=[ \t\na-z0-9A-Z]")
1410 ;;The equality is the first thing on the line
1411 ;; so copy the last lines indentation
1413 (haskell-backward-to-noncomment)
1414 (setq indent (current-indentation))))
1416 ;;Otherwise, copy the indentation
1417 (setq indent (current-indentation)))))
1421 (and (zerop (current-indentation))
1422 (not (looking-at "^[ \t]*$"))))
1423 ;;The line is not blank and its indentation is zero
1424 ;;It is a function definition. We know that
1425 ;; there is not an equals on the line
1426 (goto-char eol-limit)
1427 ;;We expect a keyword
1428 ;; so set indent to be this line's indentation
1430 (setq indent-point (point))
1431 (setq indent (+ (current-indentation)
1432 haskell-indent-offset)))
1435 ;;At the beginning of buffer
1439 ;;We are indenting a list and none
1440 ;; of the above indentations are applicable
1441 ;; so copy the indentation of this line
1442 (setq indent (current-indentation)))
1446 (setq indent (haskell-context-indent)))))
1448 (if (nth 3 (parse-partial-sexp
1450 (goto-char indent-point)
1451 (haskell-back-to-zero-indent)
1454 (goto-char indent-point))))
1455 ;;The point we determined indentation at is in a
1456 ;; string so go to this point and go back one line to
1457 ;; find indentation.
1458 (setq indent (haskell-context-indent))))
1461 ;;HOWEVER, we may have to override any indentation if we are in
1462 ;; an unbalanced parenthesis (on the original line).
1465 (goto-char original-position)
1466 (let* ((eq-point (save-excursion
1467 (haskell-back-to-symbol "=")
1469 (state (parse-partial-sexp
1472 (if (> (car state) 0)
1473 ;;There is an unbalanced parenthesis between
1474 ;; the function and here.
1475 (if (not (or (nth 3 state) (nth 4 state)))
1476 ;;We are not in a string or comment
1477 ;; so goto the parenthesis
1479 (goto-char (nth 1 state))
1480 (if (not (haskell-keyword-in-regionp
1483 ;;There is not a keyword after the open
1484 ;; bracket so we override the indentation
1486 (if (not (looking-at "{"))
1487 ;;The parenthesis is not a `{'
1488 (if (or (looking-at "\\[")
1490 (goto-char (haskell-eol))
1491 (skip-chars-backward " \t")
1493 (char-equal (preceding-char) ?,)
1495 (car (parse-partial-sexp
1498 ;;The paren is a square one
1499 ;; or it is a tuple.
1500 ;;Don't ignore what is after it.
1501 (setq indent (haskell-list-align (haskell-eol)))
1502 ;;Otherwise, ignore what comes after it.
1503 (setq indent (haskell-list-align (point))))))))))))
1509 ;;; Inserts the close parenthesis and reindents the line.
1510 ;;; We want to reindent the line if the parenthesis is
1511 ;;; the first character on the line. The parenthesis
1512 ;;; recognised by this function are `]', `}'.
1514 (defun electric-haskell-brace ()
1515 "Inserts the character `]' or `}' and reindents the current line."
1516 "Insert character and correct line's indentation."
1519 (skip-chars-backward " \t")
1521 ;;The parenthesis is at the beginning of the line.
1523 (insert last-command-char)
1524 (haskell-indent-line))
1525 ;;Otherwise it is not at the beginning of line.
1526 (insert last-command-char))
1527 ;; Match its beginning.
1528 (haskell-blink-open))
1533 ;;; This function returns the indentation for the next line given
1534 ;;; that it is contained in a bracket or we are extending a functions
1535 ;;; parameters over a line. For the case of being in an unbalanced
1536 ;;; parenthesis list, the point lies on the unbalanced parenthesis.
1537 ;;; The parameter eol-limit is used to delimit the end of the line.
1539 (defun haskell-list-align (eol-limit)
1540 "Returns the indentation for the next line given that
1541 the point lies on an unbalanced open parenthesis."
1543 (let ((indent (1+ (current-column))))
1544 ;;Set indent to be the next char (at least).
1547 (looking-at ".[ \t]*\\($\\|--\\)"))
1548 ;;There is something after the parenthesis
1549 ;;ie. the line is not empty and ignore comments
1550 (cond ((save-excursion
1551 (goto-char eol-limit)
1552 (skip-chars-backward " \t")
1553 (and (char-equal (preceding-char) ?,)
1556 (not (search-forward "|" eol-limit 't)))))
1557 ;;This is a normal list since a `,' at end
1558 ;; and there is no a `|' on the line.
1560 (skip-chars-forward " \t")
1561 (setq indent (current-column)))
1564 ;;It is a list comp we are looking at
1567 (search-forward "|" eol-limit 't)
1568 (skip-chars-forward " \t")
1569 (setq indent (current-column)))
1571 ((looking-at ".[ \t]*(")
1572 ;;We are looking at an open parenthesis
1573 ;; after this character.
1574 ;;It must be balanced so
1575 ;; move to the start of this paren
1576 ;; and set indent to be here
1578 (skip-chars-forward " \t")
1579 (setq indent (current-column)))
1583 ;;We are not looking at another open
1584 ;; parenthesis, so move forward past the
1585 ;; (assumed) function name.
1587 haskell-std-list-indent
1588 (looking-at"[ \t]*\\($\\|--\\)"))
1589 ;;There is nothing after the name
1590 ;; or haskell-std-list-offset is set
1591 ;; so set indent to be its original
1592 ;; value plus the offset minus 1
1593 ;; since we added one on earlier.
1596 (1- haskell-list-offset)))
1598 ;;Otherwise there is something after the
1599 ;; name, so skip to the first non space
1601 (skip-chars-forward " \t")
1602 (setq indent (current-column)))))))
1609 (defun haskell-insert-round-paren ()
1610 "Inserts a `(' and blinks to its matching parenthesis."
1612 (insert last-command-char)
1613 (haskell-blink-open))
1617 ;;; This function is called when a close parenthesis
1618 ;;; `)', `]', or `}' is typed.
1619 ;;; Blinks the cursor on the corresponding open parnethesis.
1620 ;;; The point lies just after the close parenthesis.
1622 (defun haskell-blink-open ()
1623 "Blinks the cursor to the matching open parenthesis.
1624 The point lies just after a parenthesis."
1625 (let ((state (parse-partial-sexp (point)
1627 (haskell-back-to-zero-indent)
1631 (not (or (nth 3 state) (nth 4 state))))
1632 ;;The parenthesis just inserted has a match
1633 ;; and is not in a string or a comment
1634 ;; so blink on its match
1636 (goto-char (nth 2 state))
1641 ;;; This function indents the line expecting the line to be a
1642 ;;; continued function application.
1645 ;;; b {haskell-further-indent applied to this line
1646 ;;; indents the line as shown}
1648 ;;; The line would look like this if only tab had been applied:
1652 (defun haskell-further-indent ()
1653 "Indents the line more than the ordinary indentation in order to
1654 extend function arguments over multiple lines."
1657 (new-point (max (save-excursion
1658 (haskell-back-to-symbol "=")
1661 (haskell-back-to-keyword)
1664 ;;This may be a continuation of a function
1665 ;; application so go back to the last '='
1666 ;; and set indent as designated by the style chosen
1667 (goto-char new-point)
1668 (skip-chars-forward "= \t")
1669 (setq indent (haskell-list-align (haskell-eol))))
1670 ;;The argument to haskell-list-align is not important here.
1673 (delete-horizontal-space)
1675 (if (< (current-column) indent)
1676 (move-to-column indent))))
1679 ;;; This function indents the current line to the first previous
1680 ;;; indentation value which is less than the current indentation.
1682 (defun haskell-lesser-indent ()
1683 "Indents the current line to the first previous indentation
1684 value which is less than the current indentation."
1686 (let ((original-indent
1687 (current-indentation))
1688 (indent (haskell-context-indent))
1692 (while (and (not (bobp))
1693 (not (zerop (current-indentation)))
1694 (>= indent original-indent))
1695 (haskell-backward-to-noncomment)
1696 (setq indent (current-indentation)))
1697 ;;bobp or indent < original-indent
1698 (if (>= indent original-indent)
1699 ;;indent is still greater than or equal to original indent
1703 ;;Otherwise, indent is less than orignal indent.
1705 (setq indent (haskell-context-indent))
1706 (if (< indent original-indent)
1707 ;;The new indent is an improvement
1709 ;;Otherwise, indent is still >= original
1710 ;; so go back to the line and keep typing.
1711 (forward-line -1)))))
1714 (delete-horizontal-space)
1716 (if (< (current-column) indent)
1717 (move-to-column indent))))
1721 ;;; Here are the functions which change the local variables
1722 ;;; to facilitate tailorability.
1724 (defun default-mode ()
1725 "Calls the function haskell-mode."
1728 (message haskell-indent-style))
1730 (defun wadler-mode ()
1731 "Sets defaults according to Dr. Philip L. Wadler's preferences.
1732 - Aligns `where' clauses with the corresponding equality.
1733 - Aligns `else' keyword with the corresponding `then'
1734 - haskell-list-offset 2
1735 - haskell-indent-offset 8
1736 - haskell-if-indent 2
1737 - haskell-comment-column 0
1738 - haskell-case-offset 2
1739 - haskell-let-offset 5."
1741 ;;'haskell-align-where-with-eq non-nil
1742 ;;'haskell-list-offset 2
1745 (or haskell-align-where-with-eq
1747 (setq haskell-align-where-with-eq t)
1748 (setq haskell-std-indent-where nil)))
1749 (setq haskell-align-else-with-then t)
1750 (setq haskell-list-offset 2)
1751 (setq haskell-indent-offset 8)
1752 (setq haskell-if-offset 2)
1753 (setq haskell-case-offset 2)
1754 (setq haskell-let-offset 5)
1755 (setq haskell-comment-column 0)
1756 (setq haskell-indent-style "Wadler")
1757 (message haskell-indent-style))
1760 (defun report-mode ()
1761 "Sets defaults according to the style of the Haskell Report.
1762 - Aligns `where' clauses after the corresponding equality.
1763 - Aligns `else' with `then'.
1764 - haskell-then-offset = 3
1765 - haskell-where-offset = 0.
1766 - haskell-case-offset = 5."
1768 ;; haskell-align-where-after-eq non-nil
1769 ;; haskell-then-offset 3
1770 ;; haskell-where-offset 0
1771 ;; haskell-case-offset 5
1774 (haskell-align-where-after-eq)
1775 (or haskell-align-else-with-then
1776 (haskell-align-else-with-then))
1777 (setq haskell-then-offset 3)
1778 (setq haskell-where-offset 0)
1779 (setq haskell-case-offset 5)
1780 (setq haskell-indent-style "Report")
1781 (message haskell-indent-style))
1784 (defun haskell-align-where-with-eq ()
1785 "Sets indentation so that a 'where' clause lines up underneath
1786 its corresponding equals sign."
1788 (or haskell-align-where-with-eq
1790 (setq haskell-align-where-after-eq nil)
1791 (setq haskell-std-indent-where nil)
1792 (setq haskell-align-where-with-eq t)
1793 haskell-align-where-with-eq)))
1797 (defun haskell-align-where-after-eq ()
1798 "Sets indentation so that a 'where' clause lines up underneath
1799 the first nonspace character after its corresponding equals sign."
1801 (or haskell-align-where-after-eq
1803 (setq haskell-align-where-with-eq nil)
1804 (setq haskell-std-indent-where nil)
1805 (setq haskell-align-where-after-eq t)
1806 haskell-align-where-after-eq)))
1809 (defun haskell-std-indent-where ()
1810 "Sets indentation so that a `where' clause lines up underneath
1811 its corresponding equals sign."
1813 (or haskell-std-indent-where
1815 (setq haskell-align-where-after-eq nil)
1816 (setq haskell-align-where-with-eq nil)
1817 (setq haskell-std-indent-where t)
1818 haskell-std-indent-where)))
1821 (defun haskell-align-else-with-then ()
1822 "Sets indentation so that an `else' lines up underneath
1823 it's corresponding `then'."
1825 (setq haskell-align-else-with-then
1826 (not haskell-align-else-with-then))
1827 (setq haskell-nest-ifs nil))
1829 (defun haskell-nest-ifs ()
1830 "Sets indentation so that an `if' is lined up
1831 under an `if' in an `else ."
1833 (setq haskell-nest-ifs
1834 (not haskell-nest-ifs))
1835 (setq haskell-align-else-with-then nil))
1838 (defun haskell-always-fixup-comment-space ()
1839 "Non-nil means always position one space after a line comment `--',
1840 when reindenting or inserting a comment,
1841 whether or not one space exists."
1842 (setq haskell-always-fixup-comment-space
1843 (not haskell-always-fixup-comment-space))
1844 haskell-always-fixup-comment-space)
1846 (defun haskell-indent-style ()
1847 "Echos the chosen indentation style in the mini-buffer."
1849 (message haskell-indent-style))
1851 (defun set-haskell-let-offset (offset)
1852 "Changes the value of haskell-let-offset, the variable which
1853 determines extra indentation after a `let' and `in'."
1854 (interactive "nSet haskell-let-offset to: ")
1855 (if (and (>= offset 0) (<= offset 10))
1856 (setq haskell-let-offset offset)))
1858 (defun set-haskell-if-offset (offset)
1859 "Changes the value of haskell-let-offset, the variable which
1860 determines extra indentation after an `if', `then' and `else'."
1861 (interactive "nSet haskell-if-offset to: ")
1862 (if (and (>= offset 0) (<= offset 10))
1863 (setq haskell-if-offset offset)))
1865 (defun set-haskell-case-offset (offset)
1866 "Changes the value of haskell-case-offset, the variable which
1867 determines extra indentation after a `case' and `of'."
1868 (interactive "nSet haskell-case-offset to: ")
1869 (if (and (>= offset 0) (<= offset 10))
1870 (setq haskell-case-offset offset)))
1873 (defun set-haskell-where-offset (offset)
1874 "Changes the value of haskell-where-offset, the variable which
1875 determines extra indentation after a line of haskell code."
1876 (interactive "nSet haskell-where-offset to: ")
1877 (if (and (>= offset 0) (<= offset 10))
1878 (setq haskell-where-offset offset)))
1881 (defun set-haskell-indent-offset (offset)
1882 "Changes the value of haskell-indent-offset, the variable which
1883 determines extra indentation after a line of haskell code."
1884 (interactive "nSet haskell-indent-offset to: ")
1885 (if (and (>= offset 1) (<= offset 10))
1886 (setq haskell-indent-offset offset)))
1889 (defun set-haskell-list-offset (offset)
1890 "Changes the value of haskell-list-offset, the variable which
1891 determines extra indentation after a line of haskell code for a list."
1892 (interactive "nSet haskell-list-offset to: ")
1893 (if (and (>= offset 0) (<= offset 10))
1894 (setq haskell-list-offset offset)))
1897 (defun set-haskell-comp-offset (offset)
1898 "Changes the value of haskell-comp-offset, the variable which
1899 determines extra indentation after a list comprehension."
1900 (interactive "nSet haskell-comp-offset to: ")
1901 (if (and (>= offset 0) (<= offset 10))
1902 (setq haskell-comp-offset offset)))
1905 (defun set-haskell-then-offset (offset)
1906 "Changes the value of haskell-then-offset, the variable which
1907 determines extra indentation for a `then' keyword after an `if'."
1908 (interactive "nSet haskell-then-offset to: ")
1909 (if (and (>= offset 0) (<= offset 10))
1910 (setq haskell-then-offset offset)))
1913 (defun set-haskell-comment-column (column)
1914 "Changes the value of haskell-comment-column, the variable which
1915 determines where to postition a line comment `--'."
1916 (interactive "nSet haskell-comment-column to: ")
1917 (if (and (>= column 0) (<= column 100))
1918 (setq haskell-comment-column column)))
1920 (defun set-haskell-concat-column (column)
1921 "Changes the value of haskell-concat-column, the variable which
1922 determines where to postition a concatenation operator `++'."
1923 (interactive "nSet haskell-concat-column to: ")
1924 (if (and (>= column 0) (<= column 100))
1925 (setq haskell-concat-column column)))
1927 (defun set-haskell-where-threshold (column)
1928 "Changes the value of haskell-where-threshold, the variable which
1929 determines when to override positioning a `where' under or after
1930 its corresponding equality."
1931 (interactive "nSet haskell-where-threshold to: ")
1932 (if (and (>= column 0) (<= column 100))
1933 (setq haskell-where-threshold column)))