packages feed

hindent 4.1.0 → 4.1.1

raw patch · 6 files changed

+366/−28 lines, 6 filesdep ~basePVP ok

version bump matches the API change (PVP)

Dependency ranges changed: base

API changes (from Hackage documentation)

+ HIndent.Styles.Gibiansky: lambdaCaseExpr :: Exp NodeInfo -> Printer ()
+ HIndent.Styles.Gibiansky: writeCaseAlts :: [Alt NodeInfo] -> Printer ()
+ HIndent.Styles.JohanTibell: recUpdateExpr :: Printer () -> [FieldUpdate NodeInfo] -> Printer ()
+ HIndent.Styles.JohanTibell: stmt :: s -> Stmt NodeInfo -> Printer ()
+ HIndent.Styles.JohanTibell: unguardedalt :: t -> Rhs NodeInfo -> Printer ()
+ HIndent.Styles.JohanTibell: unguardedrhs :: s -> Rhs NodeInfo -> Printer ()

Files

+ README.md view
@@ -0,0 +1,199 @@+# hindent [![Hackage](https://img.shields.io/hackage/v/hindent.svg?style=flat)](https://hackage.haskell.org/package/hindent)++Extensible Haskell pretty printer. Both a library and an+executable. Currently a work in progress (see+[FIXME items](https://github.com/chrisdone/hindent/blob/master/src/HIndent/Pretty.hs)).++[Haddock API documentation](http://chrisdone.github.io/hindent/).++## Install++    $ cabal install hindent++## Usage++    $ hindent+    hindent: arguments: --style [fundamental|chris-done|johan-tibell|gibiansky]++## Emacs++In+[elisp/hindent.el](https://github.com/chrisdone/hindent/blob/master/elisp/hindent.el),+there is the function `hindent/reformat-decl` which you can run with+`M-x hindent/reformat-decl`. Or alternatively define a keybinding,+e.g.:++``` lisp+(define-key haskell-mode-map (kbd "C-c i") 'hindent/reformat-decl)+```++By default it uses the style called `fundamental`, if you want to use+another, `johan-tibell`, run `M-x customize-variable+hindent-style`. If you want to configure per-project, make a file+called `.dir-locals.el` in the project root directory like this:++``` lisp+((nil . ((hindent-style . "johan-tibell"))))+```++## Vim++Basic support is provided through [vim/hindent.vim](https://github.com/chrisdone/hindent/blob/master/vim/hindent.vim),+which sets hindent as the formatter used by `gq` for haskell files. The formatting style+defaults to `fundamental` but can be configured by setting `g:hindent_style` to the desired style.++Note that unlike in emacs you have to take care of selecting a sensible buffer region as input to+hindent yourself. If that is too much trouble you can try [vim-textobj-haskell](https://github.com/gilligan/vim-textobj-haskell) which provides a text object for top level bindings.++## Contributing your own printer style++This package comes with a basic fundamental pretty printer, which is+probably not desirable to use.++It comes with other styles implemented on top of this fundamental+printer, in the modules in `HIndent.Styles.*`.++Make a module `HIndent.Styles.YourName` in which to place the printer.++To define your own, see+[HIndent.Styles.Fundamental](https://github.com/chrisdone/hindent/blob/master/src/HIndent/Styles/Fundamental.hs)+for a starting point. This module defines a blank style, adds no+additional extensions. Customizations are specified via the+`styleExtenders` property. See+[HIndent.Styles.ChrisDone](https://github.com/chrisdone/hindent/blob/master/src/HIndent/Styles/ChrisDone.hs)+for an example of a non-trivial style.++Useful combinators can be found in+[HIndent.Pretty](https://github.com/chrisdone/hindent/blob/master/src/HIndent/Pretty.hs)+for defining printers. When you want to use a fundamental printer, use+`prettyNoExt` instead of `pretty`. Comments will still be inserted by+`prettyNoExt`.++If you want to contribute it to the package, add it to the list of+styles in+[HIndent](https://github.com/chrisdone/hindent/blob/master/src/HIndent.hs)+and export it, and open a pull request. Use+[the Erlang git commit guide](https://github.com/erlang/otp/wiki/Writing-good-commit-messages)+for your commits.++## Remaining issues++* Add test suite.+* Flesh out more obscure parts of the AST.+* Improve comment re-insertion.+* Possibly: Support formatting whole modules.+* Implement some operator-specific layouts: e.g.++        Foo <$> foo+            <*> bar+            <*> mu++## Example++Input code:++``` haskell+foo = do print "OK, go"; foo (foo bar) -- Yep.+          (if bar then bob else pif) (case mu {- cool -} zot of+            Just x -> return (); Nothing -> do putStrLn "yay"; return 1) bill -- Etc+  where potato Cakes {} = 2 * x foo * bar / 5+```++### Fundamental++This is an intentionally very dumb style that demands extension.++``` haskell+foo =+  do print+       "OK, go"+     foo+       (foo+          bar)+       (if bar+           then bob+           else pif)+       (case mu {- cool -}+               zot of+          Just x ->+            return+              ()+          Nothing ->+            do putStrLn+                 "yay"+               return+                 1)+       bill -- Etc+  where potato Cakes{} =+          2 * x+                foo * bar / 5+```++### Johan Tibell++Documented in+[the style guide](https://github.com/tibbe/haskell-style-guide).+This printer style uses some simple heuristics in deciding when to go+to a new line or not, and custom handling of do, if, case alts, rhs,+etc.++``` haskell+foo = do+    print "OK, go"+    foo+        (foo bar)+        (if bar+             then bob+             else pif)+        (case mu {- cool -} zot of+             Just x ->+                 return ()+             Nothing -> do+                 putStrLn "yay"+                 return 1)+        bill -- Etc+  where+    potato Cakes{} =+        2 * x foo * bar / 5+```++### Chris Done++My style is documented in+[the style guide](https://github.com/chrisdone/haskell-style-guide).+This printer style uses some simple heuristics in deciding when to go+to a new line or not.++``` haskell+foo =+  do print "OK, go"+     foo (foo bar)+         (if bar+             then bob+             else pif)+         (case mu {- cool -} zot of+            Just x -> return ()+            Nothing ->+              do putStrLn "yay"+                 return 1)+         bill -- Etc+  where potato Cakes{} = 2 * x foo * bar / 5+```++### Andrew Gibiansky++``` haskell+foo = do+  print "OK, go"+  foo (foo bar) -- Yep.+   (if bar+       then bob+       else pif) (case mu {- cool -} zot of+                    Just x -> return ()+                    Nothing -> do+                      putStrLn "yay"+                      return 1) bill -- Etc++  where+    potato Cakes{} = 2 * x foo * bar / 5+```
elisp/hindent.el view
@@ -1,4 +1,4 @@-;;; hindent.el --- Haskell indenter.+;;; hindent.el --- Indent haskell code using the "hindent" program  ;; Copyright (c) 2014 Chris Done. All rights reserved. @@ -53,11 +53,15 @@                                               hindent-style)))                 (cond                  ((= ret 1)-                  (error (with-current-buffer temp+                  (let ((error-string+			 (with-current-buffer temp                            (let ((string (progn (goto-char (point-min))                                                 (buffer-substring (line-beginning-position)                                                                   (line-end-position)))))                              string))))+		    (if (string= error-string "hindent: Parse error: EOF")+			(message "language pragma")+		      (error error-string))))                  ((= ret 0)                   (let ((new-str (with-current-buffer temp                                    (buffer-string))))@@ -150,6 +154,30 @@          ;; comments, even though they are highlighted as such          (not (save-excursion (goto-char (line-beginning-position))                               (looking-at "{-# "))))))++(defun hindent-reformat-region ()+  (interactive)+  (save-excursion+    (save-restriction+      (if (> (point) (mark))+	  (exchange-point-and-mark))+      (while (< (point) (mark))+	(hindent/reformat-decl)+	(let ((dpoints (hindent-decl-points)))+	  (if dpoints ;; if we're in a comment hindent-decl-points returns nil+	      (goto-char (min (mark) (+ 1 (cdr dpoints))))+	    (forward-line 1)))+	;; might be on a blank line (which associates with the previous decl+	(if (search-forward-regexp "^[\\s-]*[^\\]" (mark) t)+	    nil+	  (goto-char (mark)))))))++(defun hindent-reformat-buffer ()+  (interactive)+  (save-excursion+    (save-restriction+      (mark-whole-buffer)+      (hindent-reformat-region))))  (provide 'hindent) 
hindent.cabal view
@@ -1,5 +1,5 @@ name:                hindent-version:             4.1.0+version:             4.1.1 synopsis:            Extensible Haskell pretty printer description:         Extensible Haskell pretty printer. Both a library and an executable.                      .@@ -14,6 +14,7 @@ build-type:          Simple cabal-version:       >=1.8 data-files:          elisp/hindent.el vim/hindent.vim+extra-source-files:  README.md  library   hs-source-dirs:    src/
src/HIndent/Pretty.hs view
@@ -62,7 +62,7 @@ import           Data.Int import           Data.List import           Data.Maybe-import           Data.Monoid+import           Data.Monoid hiding (Alt) import           Data.Text (Text) import qualified Data.Text as T import qualified Data.Text.Lazy as LT@@ -690,7 +690,7 @@   do write "\\case"      indentSpaces <- getIndentSpaces      newline-     indented indentSpaces (lined (map pretty alts))+     indented indentSpaces (lined (map (withCaseContext True . pretty) alts)) exp (MultiIf _ alts) =   depend (write "if ")          (lined (map (\p ->
src/HIndent/Styles/Gibiansky.hs view
@@ -184,6 +184,7 @@ exprs _ exp@(InfixApp _ _ (QVarOp _ (UnQual _ (Symbol _ "<*>"))) _) = applicativeExpr exp exprs _ exp@Lambda{} = lambdaExpr exp exprs _ exp@Case{} = caseExpr exp+exprs _ exp@LCase{} = lambdaCaseExpr exp exprs _ (RecUpdate _ exp updates) = recUpdateExpr (pretty exp) updates exprs _ (RecConstr _ qname updates) = recUpdateExpr (pretty qname) updates exprs _ (Tuple _ _ exps) = parens $ inter (write ", ") $ map pretty exps@@ -373,13 +374,26 @@  caseExpr :: Exp NodeInfo -> Printer () caseExpr (Case _ exp alts) = do-  allSingle <- and <$> mapM isSingle alts    depend (write "case ") $ do     pretty exp     write " of"   newline +  writeCaseAlts alts+caseExpr _ = error "Not a case"++lambdaCaseExpr :: Exp NodeInfo -> Printer ()+lambdaCaseExpr (LCase _ alts) = do+  write "\\case"+  newline+  writeCaseAlts alts+lambdaCaseExpr _ = error "Not a lambda case"+++writeCaseAlts :: [Alt NodeInfo] -> Printer ()+writeCaseAlts alts = do+  allSingle <- and <$> mapM isSingle alts   withCaseContext True $ indented indentSpaces $     if allSingle     then do@@ -425,13 +439,14 @@         indented indentSpaces $ depend (write "where ") (pretty binds)  -caseExpr _ = error "Not a case"  recUpdateExpr :: Printer () -> [FieldUpdate NodeInfo] -> Printer () recUpdateExpr expWriter updates = do   expWriter   write " "-  attemptSingleLine single mult+  if null updates+    then write "{}"+    else attemptSingleLine single mult    where     single = do@@ -442,7 +457,11 @@       col <- getColumn       column col $ do         write "{ "-        inter (newline >> write ", ") $ map pretty updates+        pretty (head updates)+        forM_ (tail updates) $ \update -> do+          newline+          write ", "+          pretty update         newline         write "}" 
src/HIndent/Styles/JohanTibell.hs view
@@ -47,6 +47,7 @@            ,Extender exp            ,Extender guardedRhs            ,Extender rhs+           ,Extender stmt            ,Extender fieldupdate            ]         ,styleDefConfig =@@ -56,9 +57,20 @@ -------------------------------------------------------------------------------- -- Extenders +-- Do statements need to handle infix expression indentation specially because+-- do x *+--    y+-- is two invalid statements, not one valid infix op.+stmt :: s -> Stmt NodeInfo -> Printer ()+stmt _ (Qualifier _ e@(InfixApp _ a op b)) =+  do col <- fmap (psColumn . snd)+                 (sandbox (write ""))+     infixApp e a op b (Just col)+stmt _ e = prettyNoExt e+ -- | Handle do specially and also space out guards more. rhs :: t -> Rhs NodeInfo -> Printer ()-rhs _ x =+rhs s x =   case x of     UnGuardedRhs _ (Do _ dos) ->       swing (write " = do")@@ -71,7 +83,10 @@                                  do write "|"                                     pretty p)                               gas))-    _ -> prettyNoExt x+    _ -> do inCase <- gets psInsideCase+            if inCase+               then unguardedalt s x+               else unguardedrhs s x  -- | Implement dangling right-hand-sides. guardedRhs :: t -> GuardedRhs NodeInfo -> Printer ()@@ -88,6 +103,21 @@            (lined (map pretty dos)) guardedRhs _ e = prettyNoExt e +-- | Unguarded case alts.+unguardedalt :: t -> Rhs NodeInfo -> Printer ()+unguardedalt _ (UnGuardedRhs _ e) =+  do indentSpaces <- getIndentSpaces+     write " -> "+     indented indentSpaces (pretty e)+unguardedalt _ e = prettyNoExt e++unguardedrhs :: s -> Rhs NodeInfo -> Printer ()+unguardedrhs _ (UnGuardedRhs _ e) =+  do indentSpaces <- getIndentSpaces+     write " = "+     indented indentSpaces (pretty e)+unguardedrhs _ e = prettyNoExt e+ -- | Expression customizations. exp :: t -> Exp NodeInfo -> Printer () -- | Space out tuples.@@ -178,10 +208,59 @@   where p =           brackets (inter (write ", ")                           (map pretty es))+exp _ (RecUpdate _ exp updates) = recUpdateExpr (pretty exp) updates+exp _ (RecConstr _ qname updates) = recUpdateExpr (pretty qname) updates exp _ e = prettyNoExt e  -- | Specially format records. Indent where clauses only 2 spaces. decl :: t -> Decl NodeInfo -> Printer ()+-- | Pretty print type signatures like+--+-- foo :: (Show x,Read x)+--     => (Foo -> Bar)+--     -> Maybe Int+--     -> (Char -> X -> Y)+--     -> IO ()+--+decl _ (TypeSig _ names ty') =+  depend (do inter (write ", ")+                   (map pretty names)+             write " :: ")+         (declTy ty')+  where declTy dty =+          case dty of+            TyForall _ mbinds mctx ty ->+              do case mbinds of+                   Nothing -> return ()+                   Just ts ->+                     do write "forall "+                        spaced (map pretty ts)+                        write ". "+                        newline+                 case mctx of+                   Nothing -> prettyTy ty+                   Just ctx ->+                     do pretty ctx+                        newline+                        indented (-3)+                                 (depend (write "=> ")+                                         (prettyTy ty))+            _ -> prettyTy dty+        collapseFaps (TyFun _ arg result) = arg : collapseFaps result+        collapseFaps e = [e]+        prettyTy ty =+          do small <- isSmall' ty+             if small+                then pretty ty+                else case collapseFaps ty of+                       [] -> pretty ty+                       tys ->+                         prefixedLined "-> "+                                       (map pretty tys)+        isSmall' p =+          do overflows <- isOverflow (pretty p)+             oneLine <- isSingleLiner (pretty p)+             return (not overflows && oneLine) decl _ (PatBind _ pat rhs' mbinds) =       do pretty pat          pretty rhs'@@ -190,7 +269,7 @@            Just binds ->              do newline                 indented 2-                         (do write "where "+                         (do write "where"                              newline                              indented 2 (pretty binds)) -- | Handle records specially for a prettier display (see guide).@@ -236,6 +315,34 @@              write "}") conDecl _ e = prettyNoExt e +-- | Record decls are formatted like: Foo+-- { bar :: X+-- }+recDecl :: ConDecl NodeInfo -> Printer ()+recDecl (RecDecl _ name fields) =+  do pretty name+     indentSpaces <- getIndentSpaces+     newline+     column indentSpaces+            (do depend (write "{")+                       (prefixedLined ","+                                      (map (depend space . pretty) fields))+                newline+                write "} ")+recDecl r = prettyNoExt r++recUpdateExpr :: Printer () -> [FieldUpdate NodeInfo] -> Printer ()+recUpdateExpr expWriter updates = do+  expWriter+  newline+  indentSpaces <- getIndentSpaces+  write "{ "+  -- -2 because the "{ " moved us 2 chars to the right.+  indented (indentSpaces -2) $ do+    prefixedLined ", " $ map pretty updates+    newline+  write "}"+ -------------------------------------------------------------------------------- -- Predicates @@ -334,19 +441,3 @@                     do indentSpaces <- getIndentSpaces                        column (col + indentSpaces)                               (pretty b)---- | Record decls are formatted like: Foo--- { bar :: X--- }-recDecl :: ConDecl NodeInfo -> Printer ()-recDecl (RecDecl _ name fields) =-  do pretty name-     indentSpaces <- getIndentSpaces-     newline-     column indentSpaces-            (do depend (write "{")-                       (prefixedLined ","-                                      (map (depend space . pretty) fields))-                newline-                write "} ")-recDecl r = prettyNoExt r