diff --git a/haskell-indentation.el b/haskell-indentation.el index 296178ee7..6a70d6c84 100644 --- a/haskell-indentation.el +++ b/haskell-indentation.el @@ -496,7 +496,8 @@ fixes up only indentation." ("newtype" . haskell-indentation-data) ("import" . haskell-indentation-import) ("class" . haskell-indentation-class-declaration) - ("instance" . haskell-indentation-class-declaration)) + ("instance" . haskell-indentation-class-declaration) + ("deriving" . haskell-indentation-deriving)) "Alist of toplevel keywords with associated parsers.") (defconst haskell-indentation-type-list @@ -635,6 +636,25 @@ After a lambda (backslash) there are two possible cases: (throw 'return nil) (funcall (cdr parser)))))))))) +(defun haskell-indentation-type-1 () + "Parse a single type declaration." + (let ((current-indent (current-column))) + (catch 'return + (cond + ((member current-token '(value operator "->")) + (haskell-indentation-read-next-token)) + + ((eq current-token 'end-tokens) + (when (member following-token + '(value operator no-following-token + "->" "(" "[" "{" "::")) + (haskell-indentation-add-indentation current-indent)) + (throw 'return nil)) + (t (let ((parser (assoc current-token haskell-indentation-type-list))) + (if (not parser) + (throw 'return nil) + (funcall (cdr parser))))))))) + (defun haskell-indentation-scoped-type () "Parse scoped type declaration. @@ -657,13 +677,30 @@ For example (haskell-indentation-add-indentation current-indent) (throw 'parse-end nil))) ((string= current-token "=") - (haskell-indentation-with-starter - (lambda () - (haskell-indentation-separated - #'haskell-indentation-expression "|" "deriving")))) + (let ((starter-indent-inside (current-column))) + (haskell-indentation-with-starter + (lambda () + (haskell-indentation-separated + #'haskell-indentation-expression "|"))) + (cond + ((equal current-token 'end-tokens) + (when (string= following-token "deriving") + (haskell-indentation-push-indentation starter-indent-inside) + (haskell-indentation-add-left-indent))) + ((equal current-token "deriving") + (haskell-indentation-with-starter + #'haskell-indentation-type-1))))) ((string= current-token "where") - (haskell-indentation-with-starter - #'haskell-indentation-expression-layout nil)))) + (let ((starter-indent-inside (current-column))) + (haskell-indentation-with-starter + #'haskell-indentation-expression-layout nil) + (cond + ((equal current-token 'end-tokens) + (when (string= following-token "deriving") + (haskell-indentation-add-left-indent))) + ((equal current-token "deriving") + (haskell-indentation-with-starter + #'haskell-indentation-type-1))))))) (defun haskell-indentation-import () "Parse import declaration." @@ -680,6 +717,19 @@ For example (haskell-indentation-with-starter #'haskell-indentation-declaration-layout nil))))) +(defun haskell-indentation-deriving () + "Parse standalone declaration." + (haskell-indentation-with-starter + (lambda () + (when (string= "instance" current-token) + (haskell-indentation-read-next-token)) + (when (equal current-token 'end-tokens) + (haskell-indentation-add-left-indent) + (throw 'parse-end nil)) + (haskell-indentation-type) + (when (string= current-token "|") + (haskell-indentation-fundep))))) + (defun haskell-indentation-module () "Parse module declaration." (haskell-indentation-with-starter diff --git a/tests/haskell-indentation-tests.el b/tests/haskell-indentation-tests.el index 176a9fd47..bb1069414 100644 --- a/tests/haskell-indentation-tests.el +++ b/tests/haskell-indentation-tests.el @@ -320,19 +320,26 @@ fun = do { putStrLn \"X\"; (2 9 11) (3 0)) -(hindent-test "13a* Deriving on new line"" +(hindent-test "13a Deriving on new line"" data X = X | Y deriving (Eq, Ord, Show)" (1 0) - (2 2)) + (2 0 2 7)) -(hindent-test "13b* Don't indent after deriving"" +(hindent-test "13b Don't indent after deriving"" data X = X deriving (Eq, Ord, Show)" (1 0) - (2 2) + (2 0 2 7) (3 0)) +(hindent-test "13bb Don't indent after deriving"" +data X = X + deriving" + (1 0) + (2 0 2 7) + (3 4)) + (hindent-test "13c honour = on a separate line in data declaration" " data X a b = X" @@ -869,7 +876,7 @@ data Term a where (3 0 2 9) (4 0 2 10)) -(hindent-test "49b* data with GADT syntax and a deriving clause" " +(hindent-test "49b data with GADT syntax and a deriving clause" " data G [a] b where G1 :: c -> G [Int] b deriving (Eq)" @@ -877,14 +884,14 @@ data G [a] b where (2 2) (3 0 2)) -(hindent-test "50* standalone deriving" " +(hindent-test "50 standalone deriving" " data Name = Name String deriving instance Eq Name" (1 0) ;; We accept position 2 here because we have just one ;; look-ahead token so we do not see 'instance' ;; following 'deriving'. - (2 0 2)) + (2 0 2 10)) (hindent-test "51 standalone deriving" " data family T a @@ -950,7 +957,7 @@ data Foo = Bar deriving (Show)" (1 0) (2 9) - (3 9)) + (3 0 2 9)) (ert-deftest haskell-indentation-ret-indents () (with-temp-switch-to-buffer