packages feed

haskell-tools-prettyprint 0.6.0.0 → 0.7.0.0

raw patch · 7 files changed

+79/−55 lines, 7 filesdep ~haskell-tools-astPVP ok

version bump matches the API change (PVP)

Dependency ranges changed: haskell-tools-ast

API changes (from Hackage documentation)

- Language.Haskell.Tools.Transform: fixCPPSpans :: Ann UModule dom SrcTemplateStage -> Ann UModule dom SrcTemplateStage
+ Language.Haskell.Tools.PrettyPrint: toRoseTree :: (SourceInfoTraversal n) => n dom st -> RoseTree st
+ Language.Haskell.Tools.Transform: ChildElem :: SourceTemplateElem
+ Language.Haskell.Tools.Transform: NormalText :: String -> SourceTemplateTextElem
+ Language.Haskell.Tools.Transform: StayingText :: String -> String -> SourceTemplateTextElem
+ Language.Haskell.Tools.Transform: TextElem :: [SourceTemplateTextElem] -> SrcSpan -> SourceTemplateElem
+ Language.Haskell.Tools.Transform: [_lineEndings] :: SourceTemplateTextElem -> String
+ Language.Haskell.Tools.Transform: [_sourceTemplateTextElem] :: SourceTemplateElem -> [SourceTemplateTextElem]
+ Language.Haskell.Tools.Transform: [_sourceTemplateTextRange] :: SourceTemplateElem -> SrcSpan
+ Language.Haskell.Tools.Transform: [_sourceTemplateText] :: SourceTemplateTextElem -> String
+ Language.Haskell.Tools.Transform: data SourceTemplateElem
+ Language.Haskell.Tools.Transform: data SourceTemplateTextElem
+ Language.Haskell.Tools.Transform: extractStayingElems :: SourceInfoTraversal node => Ann node dom SrcTemplateStage -> Ann node dom SrcTemplateStage
+ Language.Haskell.Tools.Transform: isStayingText :: SourceTemplateTextElem -> Bool
+ Language.Haskell.Tools.Transform: sourceTemplateText :: Lens SourceTemplateTextElem SourceTemplateTextElem String String
+ Language.Haskell.Tools.Transform: sourceTemplateTextElem :: Partial SourceTemplateElem SourceTemplateElem [SourceTemplateTextElem] [SourceTemplateTextElem]
+ Language.Haskell.Tools.Transform: sourceTemplateTextRange :: Partial SourceTemplateElem SourceTemplateElem SrcSpan SrcSpan
- Language.Haskell.Tools.Transform: srcTmpSeparators :: Simple Lens (ListInfo SrcTemplateStage) [String]
+ Language.Haskell.Tools.Transform: srcTmpSeparators :: Simple Lens (ListInfo SrcTemplateStage) [([SourceTemplateTextElem], SrcSpan)]

Files

Language/Haskell/Tools/PrettyPrint.hs view
@@ -5,7 +5,7 @@            #-}
 
 -- | Pretty printing the AST
-module Language.Haskell.Tools.PrettyPrint (prettyPrint) where
+module Language.Haskell.Tools.PrettyPrint (prettyPrint, toRoseTree) where
 
 import FastString (fsLit)
 import SrcLoc
@@ -15,10 +15,12 @@ import Language.Haskell.Tools.Transform.SourceTemplate
 
 import Control.Monad.State
+import Control.Reference
 import Data.Foldable (Foldable(..), concat)
 import Data.List as List
 import Data.List.Split (splitOn)
 import Data.Sequence hiding (null, replicate)
+import Debug.Trace
 
 -- | Pretty prints an AST by using source templates stored as node info
 prettyPrint :: (SourceInfoTraversal node) => node dom SrcTemplateStage -> String
@@ -37,7 +39,8 @@ printRose' parent (RoseTree (RoseSpan (SourceTemplateNode rng elems minInd relInd)) children)
   = do slide <- calculateSlide rng
        let printTemplateElems :: [SourceTemplateElem] -> [RoseTree SrcTemplateStage] -> PPState (Seq Char)
-           printTemplateElems (TextElem txt : rest) children = putString slide min txt >+< printTemplateElems rest children
+           printTemplateElems (TextElem txtElems _ : rest) children = putString slide min txt >+< printTemplateElems rest children
+             where txt = concatMap (^. sourceTemplateText) txtElems
            printTemplateElems (ChildElem : rest) (child : children) = printRose' parent child >+< printTemplateElems rest children
            printTemplateElems [] [] = return empty
            printTemplateElems _ [] = error $ "More child elem in template than actual children (elems: " ++ show elems ++ ", children: " ++ show children ++ ")"
@@ -55,8 +58,10 @@          putString slide min bef
            >+< (maybe printListWithSeps printListWithSepsIndented indented) actRng slide min actualSeps children
            >+< putString slide min aft
-  where actualSeps = case seps of [] -> repeat defSep
-                                  _  -> seps ++ repeat (last seps)
+  where stringSeps :: [String]
+        stringSeps = map (concatMap (^. sourceTemplateText)) (map fst seps)
+        actualSeps = case stringSeps of [] -> repeat defSep
+                                        _  -> stringSeps ++ repeat (last stringSeps)
 
 printRose' _ (RoseTree (RoseOptional (SourceTemplateOpt {})) []) = return empty
 printRose' parent (RoseTree (RoseOptional (SourceTemplateOpt rng bef aft minInd relInd)) [child])
Language/Haskell/Tools/Transform.hs view
@@ -9,14 +9,14 @@   , sourceTemplateNodeRange, sourceTemplateNodeElems
   , sourceTemplateListRange, srcTmpListBefore, srcTmpListAfter, srcTmpDefaultSeparator, srcTmpIndented, srcTmpSeparators
   , sourceTemplateOptRange, srcTmpOptBefore, srcTmpOptAfter
+  , SourceTemplateElem(..), sourceTemplateTextElem, sourceTemplateTextRange, SourceTemplateTextElem(..), sourceTemplateText, isStayingText
   -- parts of the transformation, used for debugging purposes
-  , rangeToSource, fixRanges, cutUpRanges, getLocIndices, mapLocIndices, fixMainRange, fixCPPSpans
+  , rangeToSource, fixRanges, cutUpRanges, getLocIndices, mapLocIndices, fixMainRange, extractStayingElems
   ) where
 
-import Language.Haskell.Tools.Transform.FixCPPSpans (fixCPPSpans)
 import Language.Haskell.Tools.Transform.PlaceComments (getNormalComments, getPragmaComments, placeComments)
 import Language.Haskell.Tools.Transform.RangeTemplate ()
-import Language.Haskell.Tools.Transform.RangeTemplateToSourceTemplate (rangeToSource, getLocIndices, mapLocIndices)
+import Language.Haskell.Tools.Transform.RangeTemplateToSourceTemplate (rangeToSource, getLocIndices, mapLocIndices, extractStayingElems)
 import Language.Haskell.Tools.Transform.RangeToRangeTemplate (cutUpRanges, fixRanges)
 import Language.Haskell.Tools.Transform.SourceTemplate
 import Language.Haskell.Tools.Transform.SourceTemplateHelpers
@@ -31,7 +31,7 @@ prepareAST srcBuffer = rangeToSource srcBuffer . cutUpRanges . fixRanges
 
 prepareASTCpp :: StringBuffer -> Ann UModule dom RangeStage -> Ann UModule dom SrcTemplateStage
-prepareASTCpp srcBuffer = fixCPPSpans . rangeToSource srcBuffer . cutUpRanges . fixRanges . fixMainRange srcBuffer
+prepareASTCpp srcBuffer = extractStayingElems . rangeToSource srcBuffer . cutUpRanges . fixRanges . fixMainRange srcBuffer
 
 fixMainRange :: StringBuffer -> Ann UModule dom RangeStage -> Ann UModule dom RangeStage
 fixMainRange buffer mod = setRange (mkSrcSpan (srcSpanStart $ getRange mod) (RealSrcLoc (endPos startPos buffer))) mod
− Language/Haskell/Tools/Transform/FixCPPSpans.hs
@@ -1,31 +0,0 @@-{-# LANGUAGE OverloadedStrings, FlexibleContexts #-}
-module Language.Haskell.Tools.Transform.FixCPPSpans where
-
-import Control.Monad.State
-import Control.Reference
-import qualified Data.Text as Txt
-
-import Language.Haskell.Tools.AST
-import Language.Haskell.Tools.Transform.SourceTemplate (SourceTemplateElem(..), sourceTemplateNodeElems, srcTmpSeparators)
-
-fixCPPSpans :: Ann UModule dom SrcTemplateStage -> Ann UModule dom SrcTemplateStage
--- the state will be used to pass the removed separators to the correct child
-fixCPPSpans = flip evalState [] . (sourceInfoTraverseDown (SourceInfoTrf trfElem trfList pure) (modify ([]:)) (modify tail))
-  where trfList ls = do ret <- srcTmpSeparators&traversal !~ removeClosing $ ls
-                        modify $ (\(act:rest) -> ("" : act ++ [""]):rest)
-                        return ret
-        trfElem elem = do st <- get
-                          case st of
-                            -- add the moved element to the end
-                            []:(bef:aft:rest):stack -> do
-                              put $ []:rest:stack
-                              return $ sourceTemplateNodeElems .- ((TextElem bef :) . (++ [TextElem aft])) $ elem
-                            _ -> return elem
-
-        removeClosing :: String -> State [[String]] String
-        removeClosing sep = let (aftPrev,rest) = Txt.breakOnEnd "#endif" (Txt.pack sep)
-                                (remaining,befNext) = Txt.breakOn "#if" (rest)
-                             in if Txt.null aftPrev || Txt.null befNext
-                                  then do modify (\(act:rest) -> (act ++ [Txt.unpack aftPrev, Txt.unpack befNext]) : rest)
-                                          return $ Txt.unpack remaining
-                                  else return sep
Language/Haskell/Tools/Transform/RangeTemplateToSourceTemplate.hs view
@@ -5,17 +5,21 @@ -- Basically it reads the source file and attaches parts of the source file to the AST elements that have the range of the given source code fragment.
 module Language.Haskell.Tools.Transform.RangeTemplateToSourceTemplate where
 
+import Control.Monad.Identity
 import Control.Monad.State
-import Control.Reference ((^.), _1)
+import Control.Reference
 import Data.Map as Map
 import Data.Ord (Ord(..), Ordering(..))
 import Data.Set as Set
+import Data.List
+import Data.List.Split
 import FastString (mkFastString)
 import Language.Haskell.Tools.AST
 import Language.Haskell.Tools.Transform.RangeTemplate
 import Language.Haskell.Tools.Transform.SourceTemplate
 import SrcLoc
 import StringBuffer (StringBuffer, nextChar, atEnd)
+import Debug.Trace
 
 rangeToSource :: SourceInfoTraversal node => StringBuffer -> Ann node dom RngTemplateStage
                                                           -> Ann node dom SrcTemplateStage
@@ -57,14 +61,45 @@ applyFragments srcs = flip evalState srcs
   . sourceInfoTraverseDown (SourceInfoTrf
      (\ni -> do template <- mapM getTextFor (ni ^. rngTemplateNodeElems)
-                return $ SourceTemplateNode (RealSrcSpan $ ni ^. rngTemplateNodeRange) template 0 Nothing)
+                return $ SourceTemplateNode (RealSrcSpan $ ni ^. rngTemplateNodeRange) (concat template) 0 Nothing)
      (\(RangeTemplateList rng bef aft sep indented seps)
          -> do (own, rest) <- splitAt (length seps) <$> get
                put rest
-               return (SourceTemplateList (RealSrcSpan rng) bef aft sep indented own 0 Nothing))
+               return (SourceTemplateList (RealSrcSpan rng) bef aft sep indented (Prelude.zip (Prelude.map ((:[]) . NormalText) own) (Prelude.map RealSrcSpan seps)) 0 Nothing))
      (\(RangeTemplateOpt rng bef aft) -> return (SourceTemplateOpt (RealSrcSpan rng) bef aft 0 Nothing)))
      (return ()) (return ())
-  where getTextFor RangeChildElem = return ChildElem
-        getTextFor (RangeElem _) = do (src:rest) <- get
-                                      put rest
-                                      return (TextElem src)
+  where getTextFor RangeChildElem = return [ChildElem]
+        getTextFor (RangeElem rng) = do (src:rest) <- get
+                                        put rest
+                                        return [TextElem [NormalText src] (RealSrcSpan rng)]
+
+-- | Marks template elements in the AST that should always be present in the source code, regardless of their
+-- containing elements being deleted.
+-- Currently it recognizes CPP pragmas (lines starting with #)
+-- This function should only be applied to an AST if CPP is enabled.
+extractStayingElems :: SourceInfoTraversal node => Ann node dom SrcTemplateStage -> Ann node dom SrcTemplateStage
+extractStayingElems = runIdentity . sourceInfoTraverse (SourceInfoTrf
+    (sourceTemplateNodeElems & traversal & sourceTemplateTextElem !- breakStaying)
+    (srcTmpSeparators & traversal & _1 !- breakStaying)
+    pure)
+
+    where -- splits the elements into separate lines and then recombines them
+          breakStaying :: [SourceTemplateTextElem] -> [SourceTemplateTextElem]
+          breakStaying = concat . Prelude.map (\(NormalText s) -> toTxtElems s)
+
+          toTxtElems :: String -> [SourceTemplateTextElem]
+          toTxtElems = extractStaying . splitOn "\n"
+          extractStaying lines = Prelude.foldr appendTxt []
+                                   $ Prelude.map (\ln -> if "#" `isPrefixOf` ln then StayingText ln "\n" else NormalText ln) lines
+          -- recombines the lines if they are both normal text
+          -- otherwise it moves the windows '\r' characters to the correct position
+          appendTxt (NormalText n1) (NormalText n2 : rest) = NormalText (n1 ++ '\n':n2) : rest
+          appendTxt e (next@NormalText{} : ls) = case reverse (e ^. sourceTemplateText) of
+                                              -- fix '\r' characters that are separated from '\n'
+                                    '\r':_ -> ((sourceTemplateText .- init) . (lineEndings .= "\r\n") $ e) : (sourceTemplateText .- ("\r\n" ++) $ next) : ls
+                                    _      -> e : (sourceTemplateText .- ('\n':) $ next) : ls
+          appendTxt e (next : ls) = case reverse (e ^. sourceTemplateText) of
+                                              -- fix '\r' characters that are separated from '\n'
+                                    '\r':_ -> ((sourceTemplateText .- init) . (lineEndings .= "\r\n") $ e) : NormalText "\r\n" : next : ls
+                                    _      -> e : NormalText "\n" : next : ls
+          appendTxt e [] = [e]
Language/Haskell/Tools/Transform/SourceTemplate.hs view
@@ -28,7 +28,7 @@                               , _srcTmpListAfter :: String -- ^ Text that should be put after the last element if the list becomes populated
                               , _srcTmpDefaultSeparator :: String -- ^ The default separator if the list were empty
                               , _srcTmpIndented :: Maybe [Bool] -- ^ False for elements that should be not aligned
-                              , _srcTmpSeparators :: [String] -- ^ The actual separators that were found in the source code
+                              , _srcTmpSeparators :: [([SourceTemplateTextElem], SrcSpan)] -- ^ The actual separators that were found in the source code
                               , _srcTmpListMinInd :: Int -- ^ Minimum indentation for the element
                               , _srcTmpListRelPos :: Maybe Int -- ^ Relative indentation for newly created elements
                               }
@@ -73,7 +73,7 @@ srcTmpIndented :: Simple Lens (ListInfo SrcTemplateStage) (Maybe [Bool])
 srcTmpIndented = lens _srcTmpIndented (\v s -> s { _srcTmpIndented = v })
 
-srcTmpSeparators :: Simple Lens (ListInfo SrcTemplateStage) [String]
+srcTmpSeparators :: Simple Lens (ListInfo SrcTemplateStage) [([SourceTemplateTextElem], SrcSpan)]
 srcTmpSeparators = lens _srcTmpSeparators (\v s -> s { _srcTmpSeparators = v })
 
 srcTmpListMinimalIndent :: Simple Lens (ListInfo SrcTemplateStage) Int
@@ -102,11 +102,23 @@ 
 -- | An element of a source template for a singleton AST node.
 data SourceTemplateElem
-  = TextElem { _sourceTemplateText :: String } -- ^ Source text belonging to the current node
+  = TextElem { _sourceTemplateTextElem :: [SourceTemplateTextElem]
+             , _sourceTemplateTextRange :: SrcSpan
+             } -- ^ Source text belonging to the current node
   | ChildElem -- ^ Placeholder for the next children of the node
      deriving (Eq, Ord, Data)
 
+isStayingText :: SourceTemplateTextElem -> Bool
+isStayingText StayingText{} = True
+isStayingText _ = False
+
+data SourceTemplateTextElem
+  = NormalText { _sourceTemplateText :: String }
+  | StayingText { _sourceTemplateText :: String, _lineEndings :: String }
+     deriving (Eq, Ord, Data)
+
 makeReferences ''SourceTemplateElem
+makeReferences ''SourceTemplateTextElem
 
 instance HasRange (SpanInfo SrcTemplateStage) where
   getRange = (^. sourceTemplateNodeRange)
@@ -123,10 +135,14 @@ instance Show (SpanInfo SrcTemplateStage) where
   show (SourceTemplateNode _ sp _ _) = concatMap show sp
 instance Show (ListInfo SrcTemplateStage) where
-  show SourceTemplateList{..} = "<*" ++ show _srcTmpListBefore ++ " " ++ show _srcTmpDefaultSeparator ++ " " ++ show _srcTmpListAfter ++ "*>"
+  show SourceTemplateList{..} = "<*" ++ show _srcTmpListBefore ++ " " ++ show _srcTmpDefaultSeparator ++ " " ++ show _srcTmpListAfter ++ " " ++ show _srcTmpSeparators ++ "*>"
 instance Show (OptionalInfo SrcTemplateStage) where
   show SourceTemplateOpt{..} = "<?" ++ show _srcTmpOptBefore ++ " " ++ show _srcTmpOptAfter ++ "?>"
 
 instance Show SourceTemplateElem where
-  show (TextElem s) = s
+  show (TextElem s _) = show s
   show ChildElem = "<.>"
+
+instance Show SourceTemplateTextElem where
+  show (NormalText s) = show s
+  show (StayingText s _) = "|" ++ show s ++ "|"
Language/Haskell/Tools/Transform/SourceTemplateHelpers.hs view
@@ -16,7 +16,7 @@ type ASTMulti node dom = AnnListG node dom SrcTemplateStage
 
 instance IsString (SpanInfo SrcTemplateStage) where
-  fromString s = SourceTemplateNode noSrcSpan [TextElem s] 0 Nothing
+  fromString s = SourceTemplateNode noSrcSpan [TextElem [NormalText s] noSrcSpan] 0 Nothing
 
 -- * Basic elements
 child :: SpanInfo SrcTemplateStage
haskell-tools-prettyprint.cabal view
@@ -1,5 +1,5 @@ name:                haskell-tools-prettyprint
-version:             0.6.0.0
+version:             0.7.0.0
 synopsis:            Pretty printing of Haskell-Tools AST
 description:         Converts the Haskell-Tools AST to text. Prepares the AST for this conversion. If the AST was created from the GHC AST this pretty printing will result in the original source code. Generated AST parts will get the default formatting. Works using the source annotations that are present in the AST. Creates a rose tree first to simplify the conversion.
 homepage:            https://github.com/haskell-tools/haskell-tools
@@ -23,7 +23,6 @@                      , Language.Haskell.Tools.Transform.SourceTemplate
                      , Language.Haskell.Tools.Transform.SourceTemplateHelpers
                      , Language.Haskell.Tools.Transform.PlaceComments
-                     , Language.Haskell.Tools.Transform.FixCPPSpans
   build-depends:       base              >= 4.9  && < 4.10
                      , mtl               >= 2.2  && < 2.3
                      , containers        >= 0.5  && < 0.6
@@ -32,5 +31,5 @@                      , split             >= 0.2  && < 0.3
                      , text              >= 1.2  && < 1.3
                      , ghc               >= 8.0  && < 8.1
-                     , haskell-tools-ast >= 0.6  && < 0.7
+                     , haskell-tools-ast >= 0.7  && < 0.8
   default-language: Haskell2010