PageRenderTime 65ms CodeModel.GetById 13ms app.highlight 40ms RepoModel.GetById 2ms app.codeStats 0ms

/vendor/haskell-mode/haskell-indent.el

http://github.com/rejeep/emacs
Emacs Lisp | 1581 lines | 1196 code | 121 blank | 264 comment | 29 complexity | 6fdab41c0a16f04b469cfd5fb5ed123c MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1;;; haskell-indent.el --- "semi-intelligent" indentation module for Haskell Mode
   2
   3;; Copyright 2004, 2005, 2007, 2008, 2009  Free Software Foundation, Inc.
   4;; Copyright 1997-1998  Guy Lapalme
   5
   6;; Author: 1997-1998 Guy Lapalme <lapalme@iro.umontreal.ca>
   7
   8;; Keywords: indentation Haskell layout-rule
   9;; Version: 1.2
  10;; URL: http://www.iro.umontreal.ca/~lapalme/layout/index.html
  11
  12;;; This file is not part of GNU Emacs.
  13
  14;; This file is free software; you can redistribute it and/or modify
  15;; it under the terms of the GNU General Public License as published by
  16;; the Free Software Foundation; either version 3, or (at your option)
  17;; any later version.
  18
  19;; This file is distributed in the hope that it will be useful,
  20;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  21;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  22;; GNU General Public License for more details.
  23
  24;; You should have received a copy of the GNU General Public License
  25;; along with GNU Emacs; see the file COPYING.  If not, write to the
  26;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  27;; Boston, MA 02111-1307, USA.
  28
  29
  30;;; Commentary:
  31
  32;; Purpose:
  33;;
  34;; To support automatic indentation of Haskell programs using
  35;; the layout rule described in section 1.5 and appendix B.3 of the
  36;; the Haskell report.  The rationale and the implementation principles
  37;; are described in an article to appear in Journal of Functional Programming.
  38;;   "Dynamic tabbing for automatic indentation with the layout rule"
  39;;
  40;; It supports literate scripts.
  41;; Haskell indentation is performed
  42;;     within \begin{code}...\end{code} sections of a literate script
  43;;     and in lines beginning with > with Bird style literate script
  44;; TAB aligns to the left column outside of these sections.
  45;;
  46;; Installation:
  47;;
  48;; To turn indentation on for all Haskell buffers under the Haskell
  49;; mode of Moss&Thorn <http://www.haskell.org/haskell-mode/>
  50;; add this to .emacs:
  51;;
  52;;    (add-hook 'haskell-mode-hook 'turn-on-haskell-indent)
  53;;
  54;; Otherwise, call `turn-on-haskell-indent'.
  55;;
  56;;
  57;; Customisation:
  58;;       The "standard" offset for statements is 4 spaces.
  59;;       It can be changed by setting the variable "haskell-indent-offset" to
  60;;       another value
  61;;
  62;;       The default number of blanks after > in a Bird style literate script
  63;;       is 1; it can be changed by setting the variable
  64;;       "haskell-indent-literate-Bird-default-offset"
  65;;
  66;;       `haskell-indent-hook' is invoked if not nil.
  67;;
  68;; All functions/variables start with
  69;; `(turn-(on/off)-)haskell-indent' or `haskell-indent-'.
  70
  71;; This file can also be used as a hook for the Hugs Mode developed by
  72;;         Chris Van Humbeeck <chris.vanhumbeeck@cs.kuleuven.ac.be>
  73;; It can be obtained at:
  74;; http://www-i2.informatik.rwth-aachen.de/Forschung/FP/Haskell/hugs-mode.el
  75;;
  76;; For the Hugs mode put the following in your .emacs
  77;;
  78;;(setq auto-mode-alist (append auto-mode-alist '(("\\.hs\\'" . hugs-mode))))
  79;;(autoload 'hugs-mode "hugs-mode" "Go into hugs mode" t)
  80;;
  81;; If only the indentation mode is used then replace the two
  82;; preceding lines with
  83;;(setq auto-mode-alist (append auto-mode-alist
  84;;                              '(("\\.hs\\'" . turn-on-haskell-indent))))
  85;;(autoload 'turn-on-haskell-indent "hindent" "Indentation mode for Haskell" t)
  86;;
  87;; For indentation in both cases then add the following to your .emacs
  88;;(add-hook 'hugs-mode-hook 'turn-on-haskell-indent)
  89;;(autoload 'haskell-indent-cycle "hindent" "Indentation cycle for Haskell" t)
  90;;
  91
  92;;; Code:
  93
  94(eval-when-compile (require 'cl))	;need defs of push and pop
  95(defvar haskell-literate)
  96
  97(defgroup haskell-indent nil
  98  "Haskell indentation."
  99  :group 'haskell
 100  :prefix "haskell-indent-")
 101
 102(defcustom haskell-indent-offset 4
 103  "Indentation of Haskell statements with respect to containing block."
 104  :type 'integer
 105  :group 'haskell-indent)
 106
 107(defcustom haskell-indent-literate-Bird-default-offset 1
 108  "Default number of blanks after > in a Bird style literate script."
 109  :type 'integer
 110  :group 'haskell-indent)
 111
 112(defcustom haskell-indent-rhs-align-column 0
 113  "Column on which to align right-hand sides (use 0 for ad-hoc alignment)."
 114  :type 'integer
 115  :group 'haskell-indent)
 116
 117(defun haskell-indent-point-to-col (apoint)
 118  "Return the column number of APOINT."
 119  (save-excursion
 120    (goto-char apoint)
 121    (current-column)))
 122
 123(defconst haskell-indent-start-keywords-re
 124  (concat "\\<"
 125          (regexp-opt '("class" "data" "import" "infix" "infixl" "infixr"
 126                        "instance" "module" "newtype" "primitive" "type") t)
 127          "\\>")
 128  "Regexp for keywords to complete when standing at the first word of a line.")
 129
 130
 131;; Customizations for different kinds of environments
 132;; in which dealing with low-level events are different.
 133(defun haskell-indent-mark-active ()
 134  (if (featurep 'xemacs)
 135      (if zmacs-regions
 136          zmacs-region-active-p
 137        t)
 138    mark-active))
 139
 140;;  for pushing indentation information
 141
 142(defvar haskell-indent-info)            ;Used with dynamic scoping.
 143
 144(defun haskell-indent-push-col (col &optional name)
 145  "Push indentation information for the column COL.
 146The info is followed by NAME (if present).
 147Makes sure that the same indentation info is not pushed twice.
 148Uses free var `haskell-indent-info'."
 149  (let ((tmp (cons col name)))
 150    (if (member tmp haskell-indent-info)
 151	haskell-indent-info
 152      (push tmp haskell-indent-info))))
 153
 154(defun haskell-indent-push-pos (pos &optional name)
 155  "Push indentation information for POS followed by NAME (if present)."
 156  (haskell-indent-push-col (haskell-indent-point-to-col pos) name))
 157
 158;; (defvar haskell-indent-tab-align nil
 159;;   "Align all indentations on TAB stops.")
 160
 161(defun haskell-indent-column+offset (column offset)
 162  (unless offset (setq offset haskell-indent-offset))
 163  (setq column (+ column offset))
 164  ;; (if (and haskell-indent-tab-align (> offset 0))
 165  ;;     (* 8 (/ (+ column 7) 8))
 166    column) ;; )
 167
 168(defun haskell-indent-push-pos-offset (pos &optional offset)
 169  "Pushes indentation information for the column corresponding to POS
 170followed by an OFFSET (if present use its value otherwise use
 171`haskell-indent-offset')."
 172  (haskell-indent-push-col (haskell-indent-column+offset
 173                            (haskell-indent-point-to-col pos)
 174                            offset)))
 175
 176;; redefinition of some Emacs function for dealing with
 177;; Bird Style literate scripts
 178
 179(defun haskell-indent-bolp ()
 180  "`bolp' but dealing with Bird-style literate scripts."
 181  (or (bolp)
 182      (and (eq haskell-literate 'bird)
 183           (<= (current-column) (1+ haskell-indent-literate-Bird-default-offset))
 184           (eq (char-after (line-beginning-position)) ?\>))))
 185
 186(defun haskell-indent-empty-line-p ()
 187  "Checks if the current line is empty; deals with Bird style scripts."
 188  (save-excursion
 189    (beginning-of-line)
 190    (if (and (eq haskell-literate 'bird)
 191             (eq (following-char) ?\>))
 192        (forward-char 1))
 193    (looking-at "[ \t]*$")))
 194
 195(defun haskell-indent-back-to-indentation ()
 196  "`back-to-indentation' function but dealing with Bird-style literate scripts."
 197  (if (and (eq haskell-literate 'bird)
 198           (progn (beginning-of-line) (eq (following-char) ?\>)))
 199      (progn
 200        (forward-char 1)
 201        (skip-chars-forward " \t"))
 202    (back-to-indentation)))
 203
 204(defun haskell-indent-current-indentation ()
 205  "`current-indentation' function dealing with Bird-style literate scripts."
 206  (if (eq haskell-literate 'bird)
 207      (save-excursion
 208        (haskell-indent-back-to-indentation)
 209        (current-column))
 210    (current-indentation)))
 211
 212(defun haskell-indent-backward-to-indentation (n)
 213  "`backward-to-indentation' function dealing with Bird-style literate scripts."
 214  (if (eq haskell-literate 'bird)
 215      (progn
 216        (forward-line (- n))
 217        (haskell-indent-back-to-indentation))
 218    (backward-to-indentation n)))
 219
 220(defun haskell-indent-forward-line (&optional n)
 221  "`forward-line' function but dealing with Bird-style literate scripts."
 222  (prog1
 223      (forward-line n)
 224    (if (and (eq haskell-literate 'bird) (eq (following-char) ?\>))
 225        (progn (forward-char 1)                ; skip > and initial blanks...
 226               (skip-chars-forward " \t")))))
 227
 228(defun haskell-indent-line-to (n)
 229  "`indent-line-to' function but dealing with Bird-style literate scripts."
 230  (if (eq haskell-literate 'bird)
 231      (progn
 232        (beginning-of-line)
 233        (if (eq (following-char) ?\>)
 234            (delete-char 1))
 235        (delete-horizontal-space)       ; remove any starting TABs so
 236        (indent-line-to n)              ; that indent-line only adds spaces
 237        (save-excursion
 238          (beginning-of-line)
 239          (if (> n 0) (delete-char 1))  ; delete the first space before
 240          (insert ?\>)))                ; inserting a >
 241    (indent-line-to n)))
 242
 243(defun haskell-indent-skip-blanks-and-newlines-forward (end)
 244  "Skip forward blanks, tabs and newlines until END.
 245Take account of Bird-style literate scripts."
 246  (skip-chars-forward " \t\n" end)
 247  (if (eq haskell-literate 'bird)
 248      (while (and (bolp) (eq (following-char) ?\>))
 249        (forward-char 1)                ; skip >
 250        (skip-chars-forward " \t\n" end))))
 251
 252(defun haskell-indent-skip-blanks-and-newlines-backward (start)
 253  "Skip backward blanks, tabs and newlines up to START.
 254Take account of Bird-style literate scripts."
 255  (skip-chars-backward " \t\n" start)
 256  (if (eq haskell-literate 'bird)
 257      (while (and (eq (current-column) 1)
 258                  (eq (preceding-char) ?\>))
 259        (forward-char -1)               ; skip back >
 260        (skip-chars-backward " \t\n" start))))
 261
 262;; specific functions for literate code
 263
 264(defun haskell-indent-within-literate-code ()
 265  "Check if point is within a part of literate Haskell code.
 266If so, return its start; otherwise return nil:
 267If it is Bird-style, then return the position of the >;
 268otherwise return the ending position of \\begin{code}."
 269  (save-excursion
 270    (case haskell-literate
 271      (bird
 272       (beginning-of-line)
 273       (if (or (eq (following-char) ?\>)
 274               (and (bolp) (forward-line -1) (eq (following-char) ?\>)))
 275           (progn
 276             (while (and (zerop (forward-line -1))
 277                         (eq (following-char) ?\>)))
 278             (if (not (eq (following-char) ?\>))
 279                 (forward-line))
 280             (point))))
 281      ;;  Look for a \begin{code} or \end{code} line.
 282      ((latex tex)
 283       (if (re-search-backward
 284            "^\\(\\\\begin{code}$\\)\\|\\(\\\\end{code}$\\)" nil t)
 285           ;; within a literate code part if it was a \\begin{code}.
 286           (match-end 1)))
 287      (t (error "haskell-indent-within-literate-code: should not happen!")))))
 288
 289(defun haskell-indent-put-region-in-literate (beg end &optional arg)
 290  "Put lines of the region as a piece of literate code.
 291With prefix arg, remove indication that the region is literate code.
 292It deals with both Bird style and non Bird-style scripts."
 293  (interactive "r\nP")
 294  (unless haskell-literate
 295    (error "Cannot put a region in literate in a non literate script"))
 296  (if (eq haskell-literate 'bird)
 297      (let ((comment-start "> ")        ; Change dynamic bindings for
 298            (comment-start-skip "^> ?") ; comment-region.
 299            (comment-end "")
 300            (comment-end-skip "\n")
 301            (comment-style 'plain))
 302        (comment-region beg end arg))
 303    ;; Not Bird style.
 304    (if arg                             ; Remove the literate indication.
 305        (save-excursion
 306          (goto-char end)               ; Remove end.
 307          (if (re-search-backward "^\\\\end{code}[ \t\n]*\\="
 308                                  (line-beginning-position -2) t)
 309              (delete-region (point) (line-beginning-position 2)))
 310          (goto-char beg)               ; Remove end.
 311          (beginning-of-line)
 312          (if (looking-at "\\\\begin{code}")
 313              (kill-line 1)))
 314      (save-excursion                   ; Add the literate indication.
 315        (goto-char end)
 316        (unless (bolp) (newline))
 317        (insert "\\end{code}\n")
 318        (goto-char beg)
 319        (unless (bolp) (newline))
 320        (insert "\\begin{code}\n")))))
 321
 322;;; Start of indentation code
 323
 324(defcustom haskell-indent-look-past-empty-line t
 325  "If nil, indentation engine will not look past an empty line for layout points."
 326  :group 'haskell-indent
 327  :type 'boolean)
 328
 329(defun haskell-indent-start-of-def ()
 330  "Return the position of the start of a definition.
 331The start of a def is expected to be recognizable by starting in column 0,
 332unless `haskell-indent-look-past-empty-line' is nil, in which case we
 333take a coarser approximation and stop at the first empty line."
 334  (save-excursion
 335    (let ((start-code (and haskell-literate
 336                           (haskell-indent-within-literate-code)))
 337          (top-col (if (eq haskell-literate 'bird) 2 0))
 338          (save-point (point)))
 339      ;; determine the starting point of the current piece of code
 340      (setq start-code (if start-code (1+ start-code) (point-min)))
 341      ;; go backward until the first preceding empty line
 342      (haskell-indent-forward-line -1)
 343      (while (and (if haskell-indent-look-past-empty-line
 344                      (or (> (haskell-indent-current-indentation) top-col)
 345                          (haskell-indent-empty-line-p))
 346                    (and (> (haskell-indent-current-indentation) top-col)
 347                         (not (haskell-indent-empty-line-p))))
 348                  (> (point) start-code)
 349                  (= 0 (haskell-indent-forward-line -1))))
 350      ;; go forward after the empty line
 351      (if (haskell-indent-empty-line-p)
 352          (haskell-indent-forward-line 1))
 353      (setq start-code (point))
 354      ;; find the first line of code which is not a comment
 355      (forward-comment (point-max))
 356      (if (> (point) save-point)
 357	  start-code
 358	(point)))))
 359
 360(defun haskell-indent-open-structure (start end)
 361  "If any structure (list or tuple) is not closed, between START and END,
 362returns the location of the opening symbol, nil otherwise."
 363  (save-excursion
 364    (nth 1 (parse-partial-sexp start end))))
 365
 366(defun haskell-indent-in-string (start end)
 367  "If a string is not closed , between START and END, returns the
 368location of the opening symbol, nil otherwise."
 369  (save-excursion
 370    (let ((pps (parse-partial-sexp start end)))
 371      (if (nth 3 pps) (nth 8 pps)))))
 372
 373(defun haskell-indent-in-comment (start end)
 374  "Check, starting from START, if END is at or within a comment.
 375Returns the location of the start of the comment, nil otherwise."
 376  (let (pps)
 377    (assert (<= start end))
 378    (cond ((= start end) nil)
 379	  ((nth 4 (save-excursion (setq pps (parse-partial-sexp start end))))
 380	   (nth 8 pps))
 381	  ;; We also want to say that we are *at* the beginning of a comment.
 382	  ((and (not (nth 8 pps))
 383                (>= (point-max) (+ end 2))
 384		(nth 4 (save-excursion
 385			 (setq pps (parse-partial-sexp end (+ end 2))))))
 386	   (nth 8 pps)))))
 387
 388(defvar haskell-indent-off-side-keywords-re
 389      "\\<\\(do\\|let\\|of\\|where\\)\\>[ \t]*")
 390
 391(defun haskell-indent-type-at-point ()
 392  "Return the type of the line (also puts information in `match-data')."
 393  (cond
 394   ((haskell-indent-empty-line-p) 'empty)
 395   ((haskell-indent-in-comment (point-min) (point)) 'comment)
 396   ((looking-at "\\(\\([[:alpha:]]\\(\\sw\\|'\\)*\\)\\|_\\)[ \t\n]*")
 397    'ident)
 398   ((looking-at "\\(|[^|]\\)[ \t\n]*") 'guard)
 399   ((looking-at "\\(=[^>=]\\|::\\|->\\|<-\\)[ \t\n]*") 'rhs)
 400   (t 'other)))
 401
 402(defvar haskell-indent-current-line-first-ident ""
 403  "Global variable that keeps track of the first ident of the line to indent.")
 404
 405
 406(defun haskell-indent-contour-line (start end)
 407  "Generate contour information between START and END points."
 408  (if (< start end)
 409      (save-excursion
 410	(goto-char end)
 411	(haskell-indent-skip-blanks-and-newlines-backward start)
 412        (let ((cur-col (current-column))            ; maximum column number
 413              (fl 0)     ; number of lines that forward-line could not advance
 414              contour)
 415          (while (and (> cur-col 0) (= fl 0) (>= (point) start))
 416            (haskell-indent-back-to-indentation)
 417	    (if (< (point) start) (goto-char start))
 418            (and (not (member (haskell-indent-type-at-point)
 419                              '(empty comment))) ; skip empty and comment lines
 420                 (< (current-column) cur-col) ; less indented column found
 421                 (push (point) contour) ; new contour point found
 422                 (setq cur-col (current-column)))
 423            (setq fl (haskell-indent-forward-line -1)))
 424          contour))))
 425
 426(defun haskell-indent-next-symbol (end)
 427  "Move point to the next symbol."
 428  (skip-syntax-forward ")" end)
 429  (if (< (point) end)
 430     (progn
 431       (forward-sexp 1)
 432       (haskell-indent-skip-blanks-and-newlines-forward end))))
 433
 434(defun haskell-indent-next-symbol-safe (end)
 435  "Puts point to the next following symbol, or to end if there are no more symbols in the sexp."
 436  (condition-case errlist (haskell-indent-next-symbol end)
 437      (error (goto-char end))))
 438
 439(defun haskell-indent-separate-valdef (start end)
 440  "Return a list of positions for important parts of a valdef."
 441  (save-excursion
 442    (let (valname valname-string aft-valname
 443                  guard aft-guard
 444                  rhs-sign aft-rhs-sign
 445                  type)
 446      ;; "parse" a valdef separating important parts
 447      (goto-char start)
 448      (setq type (haskell-indent-type-at-point))
 449      (if (or (memq type '(ident other))) ; possible start of a value def
 450          (progn
 451            (if (eq type 'ident)
 452                (progn
 453                  (setq valname (match-beginning 0))
 454                  (setq valname-string (match-string 0))
 455                  (goto-char (match-end 0)))
 456              (skip-chars-forward " \t" end)
 457              (setq valname (point))    ; type = other
 458              (haskell-indent-next-symbol-safe end))
 459            (while (and (< (point) end)
 460                        (setq type (haskell-indent-type-at-point))
 461                        (or (memq type '(ident other))))
 462              (if (null aft-valname)
 463                  (setq aft-valname (point)))
 464              (haskell-indent-next-symbol-safe end))))
 465      (if (and (< (point) end) (eq type 'guard)) ; start of a guard
 466          (progn
 467            (setq guard (match-beginning 0))
 468            (goto-char (match-end 0))
 469            (while (and (< (point) end)
 470                        (setq type (haskell-indent-type-at-point))
 471                        (not (eq type 'rhs)))
 472              (if (null aft-guard)
 473                  (setq aft-guard (point)))
 474              (haskell-indent-next-symbol-safe end))))
 475      (if (and (< (point) end) (eq type 'rhs)) ; start of a rhs
 476          (progn
 477            (setq rhs-sign (match-beginning 0))
 478            (goto-char (match-end 0))
 479            (if (< (point) end)
 480                (setq aft-rhs-sign (point)))))
 481      (list valname valname-string aft-valname
 482            guard aft-guard rhs-sign aft-rhs-sign))))
 483
 484(defsubst haskell-indent-no-otherwise (guard)
 485  "Check if there is no otherwise at GUARD."
 486  (save-excursion
 487    (goto-char guard)
 488    (not (looking-at "|[ \t]*otherwise\\>"))))
 489
 490
 491(defun haskell-indent-guard (start end end-visible indent-info)
 492  "Find indentation information for a line starting with a guard."
 493  (save-excursion
 494    (let* ((haskell-indent-info indent-info)
 495           (sep (haskell-indent-separate-valdef start end))
 496           (valname (nth 0 sep))
 497           (guard (nth 3 sep))
 498           (rhs-sign (nth 5 sep)))
 499      ;; push information indentation for the visible part
 500      (if (and guard (< guard end-visible) (haskell-indent-no-otherwise guard))
 501          (haskell-indent-push-pos guard)
 502        (if rhs-sign
 503            (haskell-indent-push-pos rhs-sign) ; probably within a data definition...
 504          (if valname
 505              (haskell-indent-push-pos-offset valname))))
 506      haskell-indent-info)))
 507
 508(defun haskell-indent-rhs (start end end-visible indent-info)
 509  "Find indentation information for a line starting with a rhs."
 510  (save-excursion
 511    (let* ((haskell-indent-info indent-info)
 512           (sep (haskell-indent-separate-valdef start end))
 513           (valname (nth 0 sep))
 514           (guard (nth 3 sep))
 515           (rhs-sign (nth 5 sep)))
 516      ;; push information indentation for the visible part
 517      (if (and rhs-sign (< rhs-sign end-visible))
 518          (haskell-indent-push-pos rhs-sign)
 519        (if (and guard (< guard end-visible))
 520            (haskell-indent-push-pos-offset guard)
 521          (if valname                   ; always visible !!
 522              (haskell-indent-push-pos-offset valname))))
 523      haskell-indent-info)))
 524
 525(defconst haskell-indent-decision-table
 526  (let ((or "\\)\\|\\("))
 527    (concat "\\("
 528            "1.1.11" or                 ; 1= vn gd rh arh
 529            "1.1.10" or                 ; 2= vn gd rh
 530            "1.1100" or                 ; 3= vn gd agd
 531            "1.1000" or                 ; 4= vn gd
 532            "1.0011" or                 ; 5= vn rh arh
 533            "1.0010" or                 ; 6= vn rh
 534            "110000" or                 ; 7= vn avn
 535            "100000" or                 ; 8= vn
 536            "001.11" or                 ; 9= gd rh arh
 537            "001.10" or                 ;10= gd rh
 538            "001100" or                 ;11= gd agd
 539            "001000" or                 ;12= gd
 540            "000011" or                 ;13= rh arh
 541            "000010" or                 ;14= rh
 542            "000000"                    ;15=
 543            "\\)")))
 544
 545(defun haskell-indent-find-case (test)
 546  "Find the index that matches TEST in the decision table."
 547  (if (string-match haskell-indent-decision-table test)
 548      ;; use the fact that the resulting match-data is a list of the form
 549      ;; (0 6 [2*(n-1) nil] 0 6) where n is the number of the matching regexp
 550      ;; so n= ((length match-data)/2)-1
 551      (- (/ (length (match-data 'integers)) 2) 1)
 552    (error "haskell-indent-find-case: impossible case: %s" test)))
 553
 554(defun haskell-indent-empty (start end end-visible indent-info)
 555  "Find indentation points for an empty line."
 556  (save-excursion
 557    (let* ((haskell-indent-info indent-info)
 558           (sep (haskell-indent-separate-valdef start end))
 559           (valname (pop sep))
 560           (valname-string (pop sep))
 561           (aft-valname (pop sep))
 562           (guard (pop sep))
 563           (aft-guard (pop sep))
 564           (rhs-sign (pop sep))
 565           (aft-rhs-sign (pop sep))
 566           (last-line (= end end-visible))
 567           (test (string
 568                  (if valname ?1 ?0)
 569                  (if (and aft-valname (< aft-valname end-visible)) ?1 ?0)
 570                  (if (and guard (< guard end-visible)) ?1 ?0)
 571                  (if (and aft-guard (< aft-guard end-visible)) ?1 ?0)
 572                  (if (and rhs-sign (< rhs-sign end-visible)) ?1 ?0)
 573                  (if (and aft-rhs-sign (< aft-rhs-sign end-visible)) ?1 ?0))))
 574      (if (and valname-string           ; special case for start keywords
 575               (string-match haskell-indent-start-keywords-re valname-string))
 576          (progn
 577            (haskell-indent-push-pos valname)
 578            ;; very special for data keyword
 579            (if (string-match "\\<data\\>" valname-string)
 580                (if rhs-sign (haskell-indent-push-pos rhs-sign)
 581                  (haskell-indent-push-pos-offset valname))
 582              (haskell-indent-push-pos-offset valname)))
 583        (case                           ; general case
 584            (haskell-indent-find-case test)
 585          ;; "1.1.11"   1= vn gd rh arh
 586          (1 (haskell-indent-push-pos valname)
 587             (haskell-indent-push-pos valname valname-string)
 588             (if (haskell-indent-no-otherwise guard) (haskell-indent-push-pos guard "| "))
 589             (haskell-indent-push-pos aft-rhs-sign))
 590          ;; "1.1.10"   2= vn gd rh
 591          (2 (haskell-indent-push-pos valname)
 592             (haskell-indent-push-pos valname valname-string)
 593             (if last-line
 594                 (haskell-indent-push-pos-offset guard)
 595               (if (haskell-indent-no-otherwise guard) (haskell-indent-push-pos guard "| "))))
 596          ;; "1.1100"   3= vn gd agd
 597          (3 (haskell-indent-push-pos valname)
 598             (haskell-indent-push-pos aft-guard)
 599             (if last-line (haskell-indent-push-pos-offset valname)))
 600          ;; "1.1000"   4= vn gd
 601          (4 (haskell-indent-push-pos valname)
 602             (if last-line (haskell-indent-push-pos-offset guard 2)))
 603          ;; "1.0011"   5= vn rh arh
 604          (5 (haskell-indent-push-pos valname)
 605             (if (or (and aft-valname (= (char-after rhs-sign) ?\=))
 606                     (= (char-after rhs-sign) ?\:))
 607                 (haskell-indent-push-pos valname valname-string))
 608             (haskell-indent-push-pos aft-rhs-sign))
 609          ;; "1.0010"   6= vn rh
 610          (6 (haskell-indent-push-pos valname)
 611             (haskell-indent-push-pos valname valname-string)
 612             (if last-line (haskell-indent-push-pos-offset valname)))
 613          ;; "110000"   7= vn avn
 614          (7 (haskell-indent-push-pos valname)
 615             (if last-line
 616                 (haskell-indent-push-pos aft-valname)
 617               (haskell-indent-push-pos valname valname-string)))
 618          ;; "100000"   8= vn
 619          (8 (haskell-indent-push-pos valname))
 620          ;; "001.11"   9= gd rh arh
 621          (9 (if (haskell-indent-no-otherwise guard) (haskell-indent-push-pos guard "| "))
 622             (haskell-indent-push-pos aft-rhs-sign))
 623          ;; "001.10"  10= gd rh
 624          (10 (if (haskell-indent-no-otherwise guard) (haskell-indent-push-pos guard "| "))
 625	      (if last-line (haskell-indent-push-pos-offset guard)))
 626          ;; "001100"  11= gd agd
 627          (11 (if (haskell-indent-no-otherwise guard) (haskell-indent-push-pos guard "| "))
 628	      (haskell-indent-push-pos aft-guard))
 629          ;; "001000"  12= gd
 630          (12 (if (haskell-indent-no-otherwise guard) (haskell-indent-push-pos guard "| "))
 631	      (if last-line (haskell-indent-push-pos-offset guard 2)))
 632          ;; "000011"  13= rh arh
 633          (13 (haskell-indent-push-pos aft-rhs-sign))
 634          ;; "000010"  14= rh
 635          (14 (if last-line (haskell-indent-push-pos-offset rhs-sign 2 )))
 636          ;; "000000"  15=
 637          (t (error "haskell-indent-empty: %s impossible case" test ))))
 638      haskell-indent-info)))
 639
 640(defun haskell-indent-ident (start end end-visible indent-info)
 641  "Find indentation points for a line starting with an identifier."
 642  (save-excursion
 643    (let*
 644        ((haskell-indent-info indent-info)
 645         (sep (haskell-indent-separate-valdef start end))
 646         (valname (pop sep))
 647         (valname-string (pop sep))
 648         (aft-valname (pop sep))
 649         (guard (pop sep))
 650         (aft-guard (pop sep))
 651         (rhs-sign (pop sep))
 652         (aft-rhs-sign (pop sep))
 653         (last-line (= end end-visible))
 654         (is-where
 655          (string-match "where[ \t]*" haskell-indent-current-line-first-ident))
 656         (diff-first                 ; not a function def with the same name
 657          (not(string= valname-string haskell-indent-current-line-first-ident)))
 658         ;; (is-type-def
 659         ;;  (and rhs-sign (eq (char-after rhs-sign) ?\:)))
 660         (test (string
 661                (if valname ?1 ?0)
 662                (if (and aft-valname (< aft-valname end-visible)) ?1 ?0)
 663                (if (and guard (< guard end-visible)) ?1 ?0)
 664                (if (and aft-guard (< aft-guard end-visible)) ?1 ?0)
 665                (if (and rhs-sign (< rhs-sign end-visible)) ?1 ?0)
 666                (if (and aft-rhs-sign (< aft-rhs-sign end-visible)) ?1 ?0))))
 667      (if (and valname-string           ; special case for start keywords
 668               (string-match haskell-indent-start-keywords-re valname-string))
 669          (progn
 670            (haskell-indent-push-pos valname)
 671            (if (string-match "\\<data\\>" valname-string)
 672                ;; very special for data keyword
 673                (if aft-rhs-sign (haskell-indent-push-pos aft-rhs-sign)
 674                  (haskell-indent-push-pos-offset valname))
 675              (if (not (string-match
 676                        haskell-indent-start-keywords-re
 677                        haskell-indent-current-line-first-ident))
 678                  (haskell-indent-push-pos-offset valname))))
 679        (if (string= haskell-indent-current-line-first-ident "::")
 680            (if valname (haskell-indent-push-pos valname))
 681          (case                         ; general case
 682              (haskell-indent-find-case test)
 683            ;; "1.1.11"   1= vn gd rh arh
 684            (1 (if is-where
 685                   (haskell-indent-push-pos guard)
 686                 (haskell-indent-push-pos valname)
 687                 (if diff-first (haskell-indent-push-pos aft-rhs-sign))))
 688            ;; "1.1.10"   2= vn gd rh
 689            (2 (if is-where
 690                   (haskell-indent-push-pos guard)
 691                 (haskell-indent-push-pos valname)
 692                 (if last-line
 693                     (haskell-indent-push-pos-offset guard))))
 694            ;; "1.1100"   3= vn gd agd
 695            (3 (if is-where
 696                   (haskell-indent-push-pos-offset guard)
 697                 (haskell-indent-push-pos valname)
 698                 (if diff-first
 699                     (haskell-indent-push-pos aft-guard))))
 700            ;; "1.1000"   4= vn gd
 701            (4 (if is-where
 702                   (haskell-indent-push-pos guard)
 703                 (haskell-indent-push-pos valname)
 704                 (if last-line
 705                     (haskell-indent-push-pos-offset guard 2))))
 706            ;; "1.0011"   5= vn rh arh
 707            (5 (if is-where
 708                   (haskell-indent-push-pos-offset valname)
 709                 (haskell-indent-push-pos valname)
 710                 (if diff-first
 711                     (haskell-indent-push-pos aft-rhs-sign))))
 712            ;; "1.0010"   6= vn rh
 713            (6 (if is-where
 714                   (haskell-indent-push-pos-offset valname)
 715                 (haskell-indent-push-pos valname)
 716                 (if last-line
 717                     (haskell-indent-push-pos-offset valname))))
 718            ;; "110000"   7= vn avn
 719            (7 (if is-where
 720                   (haskell-indent-push-pos-offset valname)
 721                 (haskell-indent-push-pos valname)
 722                 (if last-line
 723                     (haskell-indent-push-pos aft-valname))))
 724            ;; "100000"   8= vn
 725            (8 (if is-where
 726                   (haskell-indent-push-pos-offset valname)
 727                 (haskell-indent-push-pos valname)))
 728            ;; "001.11"   9= gd rh arh
 729            (9 (if is-where
 730                   (haskell-indent-push-pos guard)
 731                 (haskell-indent-push-pos aft-rhs-sign)))
 732            ;; "001.10"  10= gd rh
 733            (10 (if is-where
 734                    (haskell-indent-push-pos guard)
 735                  (if last-line
 736                      (haskell-indent-push-pos-offset guard))))
 737            ;; "001100"  11= gd agd
 738            (11 (if is-where
 739                    (haskell-indent-push-pos guard)
 740                  (if (haskell-indent-no-otherwise guard)
 741                      (haskell-indent-push-pos aft-guard))))
 742            ;; "001000"  12= gd
 743            (12 (if last-line (haskell-indent-push-pos-offset guard 2)))
 744            ;; "000011"  13= rh arh
 745            (13 (haskell-indent-push-pos aft-rhs-sign))
 746            ;; "000010"  14= rh
 747            (14 (if last-line (haskell-indent-push-pos-offset rhs-sign 2)))
 748            ;; "000000"  15=
 749            (t (error "haskell-indent-ident: %s impossible case" test )))))
 750      haskell-indent-info)))
 751
 752(defun haskell-indent-other (start end end-visible indent-info)
 753  "Find indentation points for a non-empty line starting with something other
 754than an identifier, a guard or rhs."
 755  (save-excursion
 756    (let* ((haskell-indent-info indent-info)
 757           (sep (haskell-indent-separate-valdef start end))
 758           (valname (pop sep))
 759           (valname-string (pop sep))
 760           (aft-valname (pop sep))
 761           (guard (pop sep))
 762           (aft-guard (pop sep))
 763           (rhs-sign (pop sep))
 764           (aft-rhs-sign (pop sep))
 765           (last-line (= end end-visible))
 766           (test (string
 767                  (if valname ?1 ?0)
 768                  (if (and aft-valname (< aft-valname end-visible)) ?1 ?0)
 769                  (if (and guard (< guard end-visible)) ?1 ?0)
 770                  (if (and aft-guard (< aft-guard end-visible)) ?1 ?0)
 771                  (if (and rhs-sign (< rhs-sign end-visible)) ?1 ?0)
 772                  (if (and aft-rhs-sign (< aft-rhs-sign end-visible)) ?1 ?0))))
 773      (if (and valname-string           ; special case for start keywords
 774               (string-match haskell-indent-start-keywords-re valname-string))
 775          (haskell-indent-push-pos-offset valname)
 776        (case                           ; general case
 777         (haskell-indent-find-case test)
 778         ;; "1.1.11"   1= vn gd rh arh
 779         (1 (haskell-indent-push-pos aft-rhs-sign))
 780         ;; "1.1.10"   2= vn gd rh
 781         (2 (if last-line
 782                   (haskell-indent-push-pos-offset guard)
 783               (haskell-indent-push-pos-offset rhs-sign 2)))
 784         ;; "1.1100"   3= vn gd agd
 785         (3 (haskell-indent-push-pos aft-guard))
 786         ;; "1.1000"   4= vn gd
 787         (4 (haskell-indent-push-pos-offset guard 2))
 788         ;; "1.0011"   5= vn rh arh
 789         (5 (haskell-indent-push-pos valname)
 790            (haskell-indent-push-pos aft-rhs-sign))
 791         ;; "1.0010"   6= vn rh
 792         (6 (if last-line
 793                (haskell-indent-push-pos-offset valname)
 794              (haskell-indent-push-pos-offset rhs-sign 2)))
 795         ;; "110000"   7= vn avn
 796         (7 (haskell-indent-push-pos-offset aft-valname))
 797         ;; "100000"   8= vn
 798         (8 (haskell-indent-push-pos valname))
 799         ;; "001.11"   9= gd rh arh
 800         (9 (haskell-indent-push-pos aft-rhs-sign))
 801         ;; "001.10"  10= gd rh
 802         (10 (if last-line
 803                   (haskell-indent-push-pos-offset guard)
 804               (haskell-indent-push-pos-offset rhs-sign 2)))
 805         ;; "001100"  11= gd agd
 806         (11 (if (haskell-indent-no-otherwise guard)
 807                   (haskell-indent-push-pos aft-guard)))
 808         ;; "001000"  12= gd
 809         (12 (if last-line (haskell-indent-push-pos-offset guard 2)))
 810         ;; "000011"  13= rh arh
 811         (13 (haskell-indent-push-pos aft-rhs-sign))
 812         ;; "000010"  14= rh
 813         (14 (if last-line (haskell-indent-push-pos-offset rhs-sign 2)))
 814         ;; "000000"  15=
 815         (t (error "haskell-indent-other: %s impossible case" test ))))
 816      haskell-indent-info)))
 817
 818(defun haskell-indent-valdef-indentation (start end end-visible curr-line-type
 819                                          indent-info)
 820  "Find indentation information for a value definition."
 821  (let ((haskell-indent-info indent-info))
 822    (if (< start end-visible)
 823        (case curr-line-type
 824          (empty (haskell-indent-empty start end end-visible indent-info))
 825          (ident (haskell-indent-ident start end end-visible indent-info))
 826          (guard (haskell-indent-guard start end end-visible indent-info))
 827          (rhs   (haskell-indent-rhs start end end-visible indent-info))
 828          (comment (error "Comment indent should never happen"))
 829          (other (haskell-indent-other start end end-visible indent-info)))
 830      haskell-indent-info)))
 831
 832(defun haskell-indent-line-indentation (line-start line-end end-visible
 833                                         curr-line-type indent-info)
 834  "Compute indentation info between LINE-START and END-VISIBLE.
 835Separate a line of program into valdefs between offside keywords
 836and find indentation info for each part."
 837  (save-excursion
 838    ;; point is (already) at line-start
 839    (assert (eq (point) line-start))
 840    (let ((haskell-indent-info indent-info)
 841          (start (or (haskell-indent-in-comment line-start line-end)
 842                     (haskell-indent-in-string line-start line-end))))
 843      (if start                         ; if comment at the end
 844          (setq line-end start))  ; end line before it
 845      ;; loop on all parts separated by off-side-keywords
 846      (while (and (re-search-forward haskell-indent-off-side-keywords-re
 847                                     line-end t)
 848                  (not (or (haskell-indent-in-comment line-start (point))
 849                           (haskell-indent-in-string line-start (point)))))
 850	(let ((beg-match (match-beginning 0)) ; save beginning of match
 851	      (end-match (match-end 0)))      ; save end of match
 852          ;; Do not try to find indentation points if off-side-keyword at
 853          ;; the start...
 854          (if (or (< line-start beg-match)
 855                  ;; Actually, if we're looking at a "let" inside a "do", we
 856                  ;; should add the corresponding indentation point.
 857                  (eq (char-after beg-match) ?l))
 858              (setq haskell-indent-info
 859                    (haskell-indent-valdef-indentation line-start beg-match
 860                                                       end-visible
 861                                                       curr-line-type
 862                                                       haskell-indent-info)))
 863          ;; ...but keep the start of the line if keyword alone on the line
 864          (if (= line-end end-match)
 865              (haskell-indent-push-pos beg-match))
 866          (setq line-start end-match)
 867          (goto-char line-start)))
 868      (haskell-indent-valdef-indentation line-start line-end end-visible
 869                                         curr-line-type haskell-indent-info))))
 870
 871
 872(defun haskell-indent-layout-indent-info (start contour-line)
 873  (let ((haskell-indent-info nil)
 874        (curr-line-type (haskell-indent-type-at-point))
 875	line-start line-end end-visible)
 876    (save-excursion
 877      (if (eq curr-line-type 'ident)
 878	  (let				; guess the type of line
 879	      ((sep
 880		(haskell-indent-separate-valdef
 881		 (point) (line-end-position))))
 882	    ;; if the first ident is where or the start of a def
 883	    ;; keep it in a global variable
 884	    (setq haskell-indent-current-line-first-ident
 885		  (if (string-match "where[ \t]*" (nth 1 sep))
 886		      (nth 1 sep)
 887		    (if (nth 5 sep)		; is there a rhs-sign
 888			(if (= (char-after (nth 5 sep)) ?\:) ;is it a typdef
 889			    "::" (nth 1 sep))
 890		      "")))))
 891      (while contour-line		; explore the contour points
 892	(setq line-start (pop contour-line))
 893	(goto-char line-start)
 894	(setq line-end (line-end-position))
 895	(setq end-visible		; visible until the column of the
 896	      (if contour-line		; next contour point
 897		  (save-excursion
 898		    (move-to-column
 899		     (haskell-indent-point-to-col (car contour-line)))
 900		    (point))
 901		line-end))
 902	(unless (or (haskell-indent-open-structure start line-start)
 903		    (haskell-indent-in-comment start line-start))
 904	  (setq haskell-indent-info
 905		(haskell-indent-line-indentation line-start line-end
 906						 end-visible curr-line-type
 907						 haskell-indent-info)))))
 908    haskell-indent-info))
 909
 910(defun haskell-indent-find-matching-start (regexp limit &optional pred start)
 911  (let ((open (haskell-indent-open-structure limit (point))))
 912    (if open (setq limit (1+ open))))
 913  (unless start (setq start (point)))
 914  (when (re-search-backward regexp limit t)
 915    (let ((nestedcase (match-end 1))
 916          (outer (or (haskell-indent-in-string limit (point))
 917                     (haskell-indent-in-comment limit (point))
 918                     (haskell-indent-open-structure limit (point))
 919                     (if (and pred (funcall pred start)) (point)))))
 920      (cond
 921       (outer
 922        (goto-char outer)
 923        (haskell-indent-find-matching-start regexp limit pred start))
 924       (nestedcase
 925        ;; Nested case.
 926        (and (haskell-indent-find-matching-start regexp limit pred)
 927             (haskell-indent-find-matching-start regexp limit pred start)))
 928       (t (point))))))
 929
 930(defun haskell-indent-filter-let-no-in (start)
 931  "Return non-nil if point is in front of a `let' that has no `in'.
 932START is the position of the presumed `in'."
 933  ;; We're looking at either `in' or `let'.
 934  (when (looking-at "let")
 935    (ignore-errors
 936      (save-excursion
 937        (forward-word 1)
 938        (forward-comment (point-max))
 939        (if (looking-at "{")
 940            (progn
 941              (forward-sexp 1)
 942              (forward-comment (point-max))
 943              (< (point) start))
 944          ;; Use the layout rule to see whether this let is already closed
 945          ;; without an `in'.
 946          (let ((col (current-column)))
 947            (while (progn (forward-line 1) (haskell-indent-back-to-indentation)
 948                          (< (point) start))
 949              (when (< (current-column) col)
 950                (setq col nil)
 951                (goto-char start)))
 952            (null col)))))))
 953
 954(defun haskell-indent-comment (open start)
 955  "Compute indent info for comments and text inside comments.
 956OPEN is the start position of the comment in which point is."
 957  ;; Ideally we'd want to guess whether it's commented out code or
 958  ;; whether it's text.  Instead, we'll assume it's text.
 959  (save-excursion
 960    (if (= open (point))
 961	;; We're actually just in front of a comment: align with following
 962	;; code or with comment on previous line.
 963        (let ((prev-line-info
 964               (cond
 965                ((eq (char-after) ?\{) nil) ;Align as if it were code.
 966                ((and (forward-comment -1)
 967                      (> (line-beginning-position 3) open))
 968                 ;; We're after another comment and there's no empty line
 969                 ;; between us.
 970                 (list (list (haskell-indent-point-to-col (point)))))
 971                (t nil))))              ;Else align as if it were code
 972          ;; Align with following code.
 973          (forward-comment (point-max))
 974          ;; There are several possible indentation points for this code-line,
 975          ;; but the only valid indentation point for the comment is the one
 976          ;; that the user will select for the code-line.  Obviously we can't
 977          ;; know that, so we just assume that the code-line is already at its
 978          ;; proper place.
 979          ;; Strictly speaking "assume it's at its proper place" would mean
 980          ;; we'd just use (current-column), but since this is using info from
 981          ;; lines further down and it's common to reindent line-by-line,
 982          ;; we'll align not with the current indentation, but with the
 983          ;; one that auto-indentation "will" select.
 984          (append
 985           prev-line-info
 986           (let ((indent-info (save-excursion
 987                                (haskell-indent-indentation-info start)))
 988                 (col (current-column)))
 989             ;; Sort the indent-info so that the current indentation comes
 990             ;; out first.
 991             (setq indent-info
 992                   (sort indent-info
 993                         (lambda (x y)
 994                           (<= (abs (- col (car x))) (abs (- col (car y)))))))
 995             indent-info)))
 996
 997      ;; We really are inside a comment.
 998      (if (looking-at "-}")
 999	  (progn
1000	    (forward-char 2)
1001	    (forward-comment -1)
1002            (list (list (1+ (haskell-indent-point-to-col (point))))))
1003	(let ((offset (if (looking-at "--?")
1004			  (- (match-beginning 0) (match-end 0)))))
1005	  (forward-line -1)		;Go to previous line.
1006	  (haskell-indent-back-to-indentation)
1007	  (if (< (point) start) (goto-char start))
1008
1009          (list (list (if (looking-at comment-start-skip)
1010                          (if offset
1011                              (+ 2 offset (haskell-indent-point-to-col (point)))
1012                            (haskell-indent-point-to-col (match-end 0)))
1013                        (haskell-indent-point-to-col (point))))))))))
1014
1015(defcustom haskell-indent-thenelse 0
1016  "If non-nil, \"then\" and \"else\" are indented.
1017This is necessary in the \"do\" layout under Haskell-98.
1018See http://hackage.haskell.org/trac/haskell-prime/wiki/DoAndIfThenElse"
1019  :group 'haskell-indent
1020  :type 'integer)
1021
1022(defun haskell-indent-closing-keyword (start)
1023  (let ((open (save-excursion
1024                (haskell-indent-find-matching-start
1025                 (case (char-after)
1026                   (?i "\\<\\(?:\\(in\\)\\|let\\)\\>")
1027                   (?o "\\<\\(?:\\(of\\)\\|case\\)\\>")
1028                   (?t "\\<\\(?:\\(then\\)\\|if\\)\\>")
1029                   (?e "\\<\\(?:\\(else\\)\\|if\\)\\>"))
1030                 start
1031                 (if (eq (char-after) ?i)
1032                     ;; Filter out the `let's that have no `in'.
1033                     'haskell-indent-filter-let-no-in)))))
1034    ;; For a "hanging let/case/if at EOL" we should use a different
1035    ;; indentation scheme.
1036    (save-excursion
1037      (goto-char open)
1038      (if (haskell-indent-hanging-p)
1039          (setq open (haskell-indent-virtual-indentation start))))
1040    ;; FIXME: we should try and figure out if the `if' is in a `do' layout
1041    ;; before using haskell-indent-thenelse.
1042    (list (list (+ (if (memq (char-after) '(?t ?e)) haskell-indent-thenelse 0)
1043                   (haskell-indent-point-to-col open))))))
1044
1045(defcustom haskell-indent-after-keywords
1046  '(("where" 2 0)
1047    ("of" 2)
1048    ("do" 2)
1049    ("in" 2 0)
1050    ("{" 2)
1051    "if"
1052    "then"
1053    "else"
1054    "let")
1055  "Keywords after which indentation should be indented by some offset.
1056Each keyword info can have the following forms:
1057
1058   KEYWORD | (KEYWORD OFFSET [OFFSET-HANGING])
1059
1060If absent OFFSET-HANGING defaults to OFFSET.
1061If absent OFFSET defaults to `haskell-indent-offset'.
1062
1063OFFSET-HANGING is the offset to use in the case where the keyword
1064is at the end of an otherwise-non-empty line."
1065  :group 'haskell-indent
1066  :type '(repeat (choice string
1067                         (cons :tag "" (string :tag "keyword:")
1068                         (cons :tag "" (integer :tag "offset")
1069                         (choice (const nil)
1070                                 (list :tag ""
1071                                       (integer :tag "offset-pending"))))))))
1072
1073(defun haskell-indent-skip-lexeme-forward ()
1074  (and (zerop (skip-syntax-forward "w"))
1075       (skip-syntax-forward "_")
1076       (skip-syntax-forward "(")
1077       (skip-syntax-forward ")")))
1078
1079(defvar haskell-indent-inhibit-after-offset nil)
1080
1081(defun haskell-indent-offset-after-info ()
1082  "Return the info from `haskell-indent-after-keywords' for keyword at point."
1083  (let ((id (buffer-substring
1084             (point)
1085             (save-excursion
1086               (haskell-indent-skip-lexeme-forward)
1087               (point)))))
1088    (or (assoc id haskell-indent-after-keywords)
1089        (car (member id haskell-indent-after-keywords)))))
1090
1091(defcustom haskell-indent-dont-hang '("(")
1092  "Lexemes that should never be considered as hanging."
1093  :group 'haskell-indent
1094  :type '(repeat string))
1095
1096(defun haskell-indent-hanging-p ()
1097  ;; A Hanging keyword is one that's at the end of a line except it's not at
1098  ;; the beginning of a line.
1099  (not (or (= (current-column) (haskell-indent-current-indentation))
1100           (save-excursion
1101             (let ((lexeme
1102                    (buffer-substring
1103                     (point)
1104                     (progn (haskell-indent-skip-lexeme-forward) (point)))))
1105               (or (member lexeme haskell-indent-dont-hang)
1106                   (> (line-end-position)
1107                      (progn (forward-comment (point-max)) (point)))))))))
1108
1109(defun haskell-indent-after-keyword-column (offset-info start &optional default)
1110  (unless offset-info
1111    (setq offset-info (haskell-indent-offset-after-info)))
1112  (unless default (setq default haskell-indent-offset))
1113  (setq offset-info
1114        (if haskell-indent-inhibit-after-offset '(0) (cdr-safe offset-info)))
1115  (if (not (haskell-indent-hanging-p))
1116      (haskell-indent-column+offset (current-column)
1117                                    (or (car offset-info) default))
1118    ;; The keyword is hanging at the end of the line.
1119    (haskell-indent-column+offset
1120     (haskell-indent-virtual-indentation start)
1121     (or (cadr offset-info) (car offset-info) default))))
1122
1123(defun haskell-indent-inside-paren (open)
1124  ;; there is an open structure to complete
1125  (if (looking-at "\\s)\\|[;,]")
1126      ;; A close-paren or a , or ; can only correspond syntactically to
1127      ;; the open-paren at `open'.  So there is no ambiguity.
1128      (progn
1129        (if (or (and (eq (char-after) ?\;) (eq (char-after open) ?\())
1130                (and (eq (char-after) ?\,) (eq (char-after open) ?\{)))
1131            (message "Mismatched punctuation: `%c' in %c...%c"
1132                     (char-after) (char-after open)
1133                     (if (eq (char-after open) ?\() ?\) ?\})))
1134        (save-excursion
1135          (goto-char open)
1136          (list (list
1137                 (if (haskell-indent-hanging-p)
1138                     (haskell-indent-virtual-indentation nil)
1139                   (haskell-indent-point-to-col open))))))
1140    ;; There might still be layout within the open structure.
1141    (let* ((end (point))
1142           (basic-indent-info
1143             ;; Anything else than a ) is subject to layout.
1144             (if (looking-at "\\s.\\|\\$ ")
1145                 (haskell-indent-point-to-col open) ; align a punct with (
1146               (let ((follow (save-excursion
1147                               (goto-char (1+ open))
1148                               (haskell-indent-skip-blanks-and-newlines-forward end)
1149                               (point))))
1150                 (if (= follow end)
1151                     (save-excursion
1152                       (goto-char open)
1153                       (haskell-indent-after-keyword-column nil nil 1))
1154                   (haskell-indent-point-to-col follow)))))
1155           (open-column (haskell-indent-point-to-col open))
1156           (contour-line (haskell-indent-contour-line (1+ open) end)))
1157      (if (null contour-line)
1158          (list (list basic-indent-info))
1159        (let ((indent-info
1160               (hask

Large files files are truncated, but you can click here to view the full file