summaryrefslogtreecommitdiffhomepage
path: root/lib
diff options
context:
space:
mode:
authorŁukasz Gołębiewski <lukasz.golebiewski@gmail.com>2020-01-23 17:43:04 +0100
committerGitHub <noreply@github.com>2020-01-23 17:43:04 +0100
commit8065c3c074719bd13db67b5ec74db560609a4e64 (patch)
treeb4cd6715cd196eecabe488caaab6b9a24ab637a1 /lib
parent1a869950eba47e30ebe84e118f404ef9a62e9cc6 (diff)
downloadstylish-haskell-8065c3c074719bd13db67b5ec74db560609a4e64.tar.gz
Support for records formatting (#256)
* Initial test describing simplest scenario for Data step Co-authored-by: Łukasz Gołębiewski <lukasz.golebiewski@gmail.com> * [sanity-check] Delete data defs * Extract changeDecl Co-authored-by: Łukasz Gołębiewski <lukasz.golebiewski@gmail.com> * First green test :-) * Cover case where there are more then one field in data type declaration Co-authored-by: Łukasz Gołębiewski <lukasz.golebiewski@gmail.com> * Add case03 where a type variable is present * Add case04 - multiple declarations * Make case04 pass * Extend tests with case05 Co-authored-by: Łukasz Gołębiewski <lukasz.golebiewski@gmail.com> * Add pending case06 Co-authored-by: Łukasz Gołębiewski <lukasz.golebiewski@gmail.com> * Fix case 06 Co-authored-by: Łukasz Gołębiewski <lukasz.golebiewski@gmail.com> * Add case07 Co-authored-by: Łukasz Gołębiewski <lukasz.golebiewski@gmail.com> * Add second phantom case * Add records to config * Make indent size configurable for records Co-authored-by: Paweł Szulc <paul.szulc@gmail.com> * Fix warnings in Data.hs * Process derivings during record formatting Co-authored-by: Paweł Szulc <paul.szulc@gmail.com> * Do not format when context is present Co-authored-by: Paweł Szulc <paul.szulc@gmail.com> * Add case 11 - deriving with DerivingStrategies * Bugfix: do not remove empty data declarations Co-authored-by: Paweł Szulc <paul.szulc@gmail.com> * Update README example with ability to format records * Add case12 (Point) * Fix case 12 * Factor out processName * Apply hlint suggestions * Extract constructors helper function * Make 'indent' global * Remove unused Stylish.records method * Fix Config formatting in Config.hs * Extract processConstructor function Co-authored-by: Łukasz Gołębiewski <lukasz.golebiewski@gmail.com> * Refactor datas function Co-authored-by: Łukasz Gołębiewski <lukasz.golebiewski@gmail.com> * Include comments with AST. Two tests are still failing... * Fix cases 15 and 16 * Do not format records when comments within Co-authored-by: Łukasz Gołębiewski <lukasz.golebiewski@gmail.com> * Clean-up Data.hs * Refactor Data.hs Co-authored-by: Pawel Szulc <paul.szulc@gmail.com>
Diffstat (limited to 'lib')
-rw-r--r--lib/Language/Haskell/Stylish/Config.hs9
-rw-r--r--lib/Language/Haskell/Stylish/Step/Data.hs66
2 files changed, 75 insertions, 0 deletions
diff --git a/lib/Language/Haskell/Stylish/Config.hs b/lib/Language/Haskell/Stylish/Config.hs
index 725a465..bd15867 100644
--- a/lib/Language/Haskell/Stylish/Config.hs
+++ b/lib/Language/Haskell/Stylish/Config.hs
@@ -35,6 +35,7 @@ import qualified System.IO as IO (Newline
import qualified Language.Haskell.Stylish.Config.Cabal as Cabal
import Language.Haskell.Stylish.Config.Internal
import Language.Haskell.Stylish.Step
+import qualified Language.Haskell.Stylish.Step.Data as Data
import qualified Language.Haskell.Stylish.Step.Imports as Imports
import qualified Language.Haskell.Stylish.Step.LanguagePragmas as LanguagePragmas
import qualified Language.Haskell.Stylish.Step.SimpleAlign as SimpleAlign
@@ -52,6 +53,7 @@ type Extensions = [String]
--------------------------------------------------------------------------------
data Config = Config
{ configSteps :: [Step]
+ , configIndent :: Int
, configColumns :: Maybe Int
, configLanguageExtensions :: [String]
, configNewline :: IO.Newline
@@ -119,6 +121,7 @@ parseConfig (A.Object o) = do
-- First load the config without the actual steps
config <- Config
<$> pure []
+ <*> (o A..:? "indent" A..!= 4)
<*> (o A..:! "columns" A..!= Just 80)
<*> (o A..:? "language_extensions" A..!= [])
<*> (o A..:? "newline" >>= parseEnum newlines IO.nativeNewline)
@@ -141,6 +144,7 @@ parseConfig _ = mzero
catalog :: Map String (Config -> A.Object -> A.Parser Step)
catalog = M.fromList
[ ("imports", parseImports)
+ , ("records", parseRecords)
, ("language_pragmas", parseLanguagePragmas)
, ("simple_align", parseSimpleAlign)
, ("squash", parseSquash)
@@ -180,6 +184,11 @@ parseSimpleAlign c o = SimpleAlign.step
where
withDef f k = fromMaybe (f SimpleAlign.defaultConfig) <$> (o A..:? k)
+--------------------------------------------------------------------------------
+parseRecords :: Config -> A.Object -> A.Parser Step
+parseRecords c _ = Data.step
+ <$> pure (configIndent c)
+
--------------------------------------------------------------------------------
parseSquash :: Config -> A.Object -> A.Parser Step
diff --git a/lib/Language/Haskell/Stylish/Step/Data.hs b/lib/Language/Haskell/Stylish/Step/Data.hs
new file mode 100644
index 0000000..9acd22b
--- /dev/null
+++ b/lib/Language/Haskell/Stylish/Step/Data.hs
@@ -0,0 +1,66 @@
+module Language.Haskell.Stylish.Step.Data where
+
+import Data.List (find, intercalate)
+import Data.Maybe (maybeToList)
+import qualified Language.Haskell.Exts as H
+import Language.Haskell.Exts.Comments
+import Language.Haskell.Stylish.Block
+import Language.Haskell.Stylish.Editor
+import Language.Haskell.Stylish.Step
+import Language.Haskell.Stylish.Util
+import Prelude hiding (init)
+
+datas :: H.Module l -> [H.Decl l]
+datas (H.Module _ _ _ _ decls) = decls
+datas _ = []
+
+type ChangeLine = Change String
+
+step :: Int -> Step
+step indentSize = makeStep "Data" (step' indentSize)
+
+step' :: Int -> Lines -> Module -> Lines
+step' indentSize ls (module', allComments) = applyChanges changes ls
+ where
+ datas' = datas $ fmap linesFromSrcSpan module'
+ changes = datas' >>= maybeToList . changeDecl allComments indentSize
+
+findComment :: LineBlock -> [Comment] -> Maybe Comment
+findComment lb = find commentOnLine
+ where
+ commentOnLine (Comment _ (H.SrcSpan _ start _ end _) _) =
+ blockStart lb == start && blockEnd lb == end
+
+commentsWithin :: LineBlock -> [Comment] -> [Comment]
+commentsWithin lb = filter within
+ where
+ within (Comment _ (H.SrcSpan _ start _ end _) _) =
+ start >= blockStart lb && end <= blockEnd lb
+
+changeDecl :: [Comment] -> Int -> H.Decl LineBlock -> Maybe ChangeLine
+changeDecl _ _ (H.DataDecl _ (H.DataType _) Nothing _ [] _) = Nothing
+changeDecl allComments indentSize (H.DataDecl block (H.DataType _) Nothing dhead decls derivings)
+ | null $ commentsWithin block allComments = Just $ change block (const $ concat newLines)
+ | otherwise = Nothing
+ where
+ newLines = fmap constructors zipped ++ [fmap (indented . H.prettyPrint) derivings]
+ zipped = zip decls ([1..] ::[Int])
+ constructors (decl, 1) = processConstructor allComments typeConstructor indentSize decl
+ constructors (decl, _) = processConstructor allComments (indented "| ") indentSize decl
+ typeConstructor = "data " <> H.prettyPrint dhead <> " = "
+ indented = indent indentSize
+changeDecl _ _ _ = Nothing
+
+processConstructor :: [Comment] -> String -> Int -> H.QualConDecl LineBlock -> [String]
+processConstructor allComments init indentSize (H.QualConDecl _ _ _ (H.RecDecl _ dname fields)) = do
+ init <> H.prettyPrint dname : n1 : ns ++ [indented "}"]
+ where
+ n1 = processName "{ " ( extractField $ head fields)
+ ns = fmap (processName ", " . extractField) (tail fields)
+ processName prefix (fnames, _type, Nothing) =
+ indented prefix <> intercalate ", " (fmap H.prettyPrint fnames) <> " :: " <> H.prettyPrint _type
+ processName prefix (fnames, _type, (Just (Comment _ _ c))) =
+ indented prefix <> intercalate ", " (fmap H.prettyPrint fnames) <> " :: " <> H.prettyPrint _type <> " --" <> c
+ extractField (H.FieldDecl lb names _type) = (names, _type, findComment lb allComments)
+ indented = indent indentSize
+processConstructor _ init _ decl = [init <> trimLeft (H.prettyPrint decl)]