Skip to content

Allow more indentation positions in haskell-indentation #1290

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Apr 25, 2016
117 changes: 68 additions & 49 deletions haskell-indentation.el
Original file line number Diff line number Diff line change
Expand Up @@ -355,7 +355,6 @@ fixes up only indentation."
(defvar starter-indent) ;; column at a keyword
(defvar current-indent) ;; the most right indentation
(defvar layout-indent) ;; the column of the layout list
(defvar parse-line-number) ;; the number of lines parsed
(defvar possible-indentations) ;; the return value of the indentations
(defvar indentation-point) ;; where to stop parsing
(defvar implicit-layout-active) ;; is "off-side" rule active?
Expand Down Expand Up @@ -409,7 +408,6 @@ fixes up only indentation."
(skip-syntax-forward "-")
(let ((indentation-point (point))
(layout-indent 0)
(parse-line-number 0)
(current-indent haskell-indentation-layout-offset)
(starter-indent haskell-indentation-layout-offset)
(left-indent haskell-indentation-layout-offset)
Expand Down Expand Up @@ -616,8 +614,9 @@ After a lambda (backslash) there are two possible cases:
((eq current-token 'end-tokens)
(when (member following-token
'(value operator no-following-token
"->" "(" "[" "{" "::"))
(haskell-indentation-add-indentation current-indent))
"(" "[" "{" "::"))
(haskell-indentation-add-indentation current-indent)
(haskell-indentation-add-indentation left-indent))
(throw 'return nil))
(t (let ((parser (assoc current-token haskell-indentation-type-list)))
(if (not parser)
Expand Down Expand Up @@ -884,41 +883,46 @@ parser. If parsing ends here, set indentation to left-indent."
(defun haskell-indentation-expression ()
"Parse an expression until an unknown token is encountered."
(catch 'return
(while t
(cond
((memq current-token '(value operator))
(haskell-indentation-read-next-token))
((eq current-token 'end-tokens)
(cond ((string= following-token "where")
(haskell-indentation-add-where-pre-indent)) ; before a where
((haskell-indentation-expression-token-p following-token)
(haskell-indentation-add-indentation
current-indent))) ; a normal expression
(throw 'return nil))
(t (let ((parser (assoc current-token
haskell-indentation-expression-list)))
(when (null parser)
(throw 'return nil)) ; not expression token, so exit
(funcall (cdr parser)) ; run parser
(when (and (eq current-token 'end-tokens)
(string= (car parser) "let")
(= haskell-indentation-layout-offset current-indent)
(haskell-indentation-expression-token-p following-token))
;; inside a layout, after a let construct
;; for example: "do let a = 20"
(haskell-indentation-add-layout-indent)
(throw 'parse-end nil))
;; after an 'open' expression such as 'if', exit
(unless (member (car parser) '("(" "[" "{" "case"))
(throw 'return nil))))))))
(let ((current-indent (current-column)))
(while t
(cond
((memq current-token '(value operator))
(haskell-indentation-read-next-token))
((eq current-token 'end-tokens)
(cond ((string= following-token "where")
(haskell-indentation-add-where-pre-indent)) ; before a where
((haskell-indentation-expression-token-p following-token)
;; a normal expression can be either continued or have
;; left indent
(haskell-indentation-add-indentation
current-indent)
(haskell-indentation-add-indentation
left-indent)))
(throw 'return nil))
(t (let ((parser (assoc current-token
haskell-indentation-expression-list)))
(when (null parser)
(throw 'return nil)) ; not expression token, so exit
(funcall (cdr parser)) ; run parser
(when (and (eq current-token 'end-tokens)
(string= (car parser) "let")
(= haskell-indentation-layout-offset current-indent)
(haskell-indentation-expression-token-p following-token))
;; inside a layout, after a let construct
;; for example: "do let a = 20"
(haskell-indentation-add-layout-indent)
(throw 'parse-end nil))
;; after an 'open' expression such as 'if', exit
(unless (member (car parser) '("(" "[" "{" "case"))
(throw 'return nil)))))))))

(defun haskell-indentation-separated (parser separator &optional stmt-separator)
"Evaluate PARSER separated by SEPARATOR and STMT-SEPARATOR.
If STMT-SEPARATOR is not NIL, it will be used to set a new starter-indent.

For example:

[ i | i <- [1..10]
[ i | i <- [1..10]
,"
(catch 'return
(unless (listp separator)
Expand All @@ -935,13 +939,21 @@ For example:
(haskell-indentation-at-separator))

((eq current-token 'end-tokens)
(cond ((or (member following-token separator)
(member following-token stmt-separator))
;; Set an indentation before a separator, for example:
;; [ 1 or [ 1 | a
;; , 2 , 20
(haskell-indentation-add-indentation starter-indent)
(throw 'parse-end nil)))
(when (or (member following-token separator)
(member following-token stmt-separator))
;; Set an indentation before a separator, for example:
;; [ 1 or [ 1 | a
;; , 2 , 20
(haskell-indentation-add-indentation starter-indent)
(when (< left-indent starter-indent)
(haskell-indentation-add-indentation left-indent))
(throw 'parse-end nil))
(when (equal following-token 'no-following-token)
;; Set an indentation before a separator, for example:
;; [ 1 or [ 1 | a
;; , 2 , 20
(haskell-indentation-add-indentation starter-indent)
(haskell-indentation-add-indentation left-indent))
(throw 'return nil))
(t (throw 'return nil))))))

Expand All @@ -960,6 +972,7 @@ l = [ 1
(haskell-indentation-read-next-token)
(cond ((eq current-token 'end-tokens)
(haskell-indentation-add-indentation current-indent)
(haskell-indentation-add-indentation left-indent)
(throw 'return nil))
(separator-column ; on the beginning of the line
(setq current-indent (current-column))
Expand Down Expand Up @@ -1024,16 +1037,20 @@ layout starts."
(defun haskell-indentation-phrase-rest (phrase1)
"" ; FIXME
(while phrase1
(let ((starter-line parse-line-number)
(phrase phrase1))
(let ((phrase phrase1))
(setq phrase1 nil)
(let ((current-indent (current-column)))
(let ((current-indent (current-column))
(left-indent left-indent)
(layout-indent layout-indent))
(funcall (car phrase)))
(cond
((eq current-token 'end-tokens)
(cond ((null (cdr phrase))) ;; fallthrough
((equal following-token (cadr phrase))
(haskell-indentation-add-indentation starter-indent)
(unless (member following-token '("," ";"))
;; we want to keep comma and semicolon aligned always
(haskell-indentation-add-indentation left-indent))
(throw 'parse-end nil))
((string= (cadr phrase) "in")
(when (= left-indent layout-indent)
Expand Down Expand Up @@ -1082,11 +1099,13 @@ layout starts."
(+ left-indent haskell-indentation-left-offset)))

(defun haskell-indentation-push-indentation (indent)
"" ; FIXME
(when (or (null possible-indentations)
(< indent (car possible-indentations)))
"Add INDENT to list of possible indentations.

Add INDENT to `possible-indentations' if it is not there
yet. Keep the list in ascending order."
(unless (member indent possible-indentations)
(setq possible-indentations
(cons indent possible-indentations))))
(sort (cons indent possible-indentations) #'<))))

(defun haskell-indentation-read-next-token ()
"Go to the next token and set current-token to the next token.
Expand Down Expand Up @@ -1131,14 +1150,14 @@ line."
(if (>= (point) indentation-point)
(progn
(setq following-token
(if (= (point) indentation-point)
(if (and (not (eobp))
(= (point) indentation-point))
(haskell-indentation-peek-token)
'no-following-token))
(setq current-token 'end-tokens))
(when (= (current-column) (haskell-indentation-current-indentation))
;; on a new line
(setq current-indent (current-column))
(setq parse-line-number (+ parse-line-number 1)))
(setq current-indent (current-column)))
(cond ((and implicit-layout-active
(> layout-indent (current-column)))
(setq current-token 'layout-end))
Expand Down
Loading