rio-prettyprint 0.1.5.0 → 0.1.6.0
raw patch · 4 files changed
+430/−114 lines, 4 files
Files
- rio-prettyprint.cabal +2/−2
- src/RIO/PrettyPrint.hs +74/−22
- src/RIO/PrettyPrint/Types.hs +49/−37
- src/Text/PrettyPrint/Leijen/Extended.hs +305/−53
rio-prettyprint.cabal view
@@ -1,11 +1,11 @@ cabal-version: 1.12 --- This file has been generated from package.yaml by hpack version 0.35.4. +-- This file has been generated from package.yaml by hpack version 0.35.5. -- -- see: https://github.com/sol/hpack name: rio-prettyprint -version: 0.1.5.0 +version: 0.1.6.0 synopsis: Pretty-printing for RIO description: Combine RIO's log capabilities with pretty printing category: Development
src/RIO/PrettyPrint.hs view
@@ -12,27 +12,43 @@ , displayPlain , displayWithColor -- * Logging based on pretty-print typeclass + -- | The @pretty...@ functions come in three varieties: + -- + -- * The normal variety, with a single styled document; + -- * The @L@ variety. The listed styled documents are concatenated with + -- 'fillSep'; and + -- * The @S@ variety. 'flow' is applied to the 'String'. + -- + -- Pretty message at log level 'LevelDebug'. , prettyDebug - , prettyInfo - , prettyNote - , prettyWarn - , prettyError - , prettyWarnNoIndent - , prettyErrorNoIndent , prettyDebugL - , prettyInfoL - , prettyNoteL - , prettyWarnL - , prettyErrorL - , prettyWarnNoIndentL - , prettyErrorNoIndentL , prettyDebugS + -- | Pretty message at log level 'LevelInfo'. + , prettyInfo + , prettyInfoL , prettyInfoS + -- | Pretty messages at log level 'LevelInfo', starting on a new line with + -- label @Note:@, with the message indented after the label. + , prettyNote + , prettyNoteL , prettyNoteS + -- | Pretty messages at log level 'LevelWarn', starting on a new line with + -- label @Warning:@, with or without the message indented after the label. + , prettyWarn + , prettyWarnL , prettyWarnS - , prettyErrorS + , prettyWarnNoIndent + , prettyWarnNoIndentL , prettyWarnNoIndentS + -- | Pretty messages at log level 'LevelError', starting on a new line with + -- label @Error:@, with or without the message indented after the label. + , prettyError + , prettyErrorL + , prettyErrorS + , prettyErrorNoIndent + , prettyErrorNoIndentL , prettyErrorNoIndentS + -- * Semantic styling functions -- | These are used rather than applying colors or other styling directly, -- to provide consistency. @@ -41,8 +57,9 @@ , logLevelToStyle -- * Formatting utils , bulletedList - , mkNarrativeList , spacedBulletedList + , mkBulletedList + , mkNarrativeList , debugBracket -- * Re-exports from "Text.PrettyPrint.Leijen.Extended" , Pretty (..) @@ -185,7 +202,7 @@ indentAfterLabel :: StyleDoc -> StyleDoc indentAfterLabel = align --- | Make a 'Doc' from each word in a 'String' +-- | Make a 'StyleDoc' from each word in a 'String' wordDocs :: String -> [StyleDoc] wordDocs = map fromString . words @@ -193,6 +210,22 @@ flow :: String -> StyleDoc flow = fillSep . wordDocs +-- | @debug message action@ brackets any output of the specified @action@ with +-- an initial and final @message@ at log level 'LevelDebug'. The initial message +-- is prefixed with the label @Start:@. The final message is prefixed with +-- information about the duration of the action in milliseconds (ms) and, if +-- an exception is thrown by the action, the exception. For example: +-- +-- > Start: <message> +-- > <output of action> +-- > Finished in ...ms: <message> +-- +-- or: +-- +-- > Start: <message> +-- > <output of action> +-- > Finished with exception in ...ms: <message> +-- > Exception thrown: <exception_message> debugBracket :: (HasCallStack, HasTerm env, MonadReader env m, MonadIO m, MonadUnliftIO m) => StyleDoc -> m a -> m a debugBracket msg f = do @@ -215,19 +248,38 @@ output $ "Finished in" <+> displayMilliseconds diff <> ":" <+> msg return x --- |Annotate a 'StyleDoc' with a 'Style'. +-- | Annotate a 'StyleDoc' with a 'Style'. style :: Style -> StyleDoc -> StyleDoc style = styleAnn --- Display milliseconds. -displayMilliseconds :: Double -> StyleDoc +-- | Display as milliseconds in style 'Good'. +displayMilliseconds :: + Double + -- ^ Amount of time in seconds. + -> StyleDoc displayMilliseconds t = style Good $ fromString (show (round (t * 1000) :: Int)) <> "ms" --- | Display a bulleted list of 'StyleDoc'. +-- | Display a bulleted list of 'StyleDoc' with @*@ as the bullet point. bulletedList :: [StyleDoc] -> StyleDoc -bulletedList = mconcat . intersperse line . map (("*" <+>) . align) +bulletedList = mkBulletedList False '*' +-- | Display a bulleted list of 'StyleDoc', spaced with blank lines or not, +-- given a character for the bullet point. +-- +-- @since 0.1.6.0 +mkBulletedList :: + Bool + -- ^ Spaced with a blank line between each item? + -> Char + -- ^ The character to act as the bullet point. + -> [StyleDoc] + -> StyleDoc +mkBulletedList isSpaced bullet = + mconcat . intersperse spacer . map ((fromString [bullet] <+>) . align) + where + spacer = if isSpaced then line <> line else line + -- | A helper function to yield a narrative list from a list of items, with a -- final fullstop. For example, helps produce the output -- @\"apple, ball and cat.\"@ (no serial comma) or @\"apple, ball, and cat.\"@ @@ -255,9 +307,9 @@ : mkNarrativeList mStyle useSerialComma xs -- | Display a bulleted list of 'StyleDoc' with a blank line between --- each. +-- each and @*@ as the bullet point. spacedBulletedList :: [StyleDoc] -> StyleDoc -spacedBulletedList = mconcat . intersperse (line <> line) . map (("*" <+>) . align) +spacedBulletedList = mkBulletedList True '*' -- | The 'Style' intended to be associated with a 'LogLevel'. --
src/RIO/PrettyPrint/Types.hs view
@@ -17,44 +17,56 @@ import RIO import System.Console.ANSI.Types ( SGR ) --- | A style of rio-prettyprint's output. +-- | Type representing styles of output. data Style - = Error -- Should be used sparingly, not to style entire long messages. - -- For example, it's used to style the "Error:" or "[error]" label - -- for an error message, not the entire message. - | Warning -- Should be used sparingly, not to style entire long messages. - -- For example, it's used to style the "Warning:" or "[warn]" - -- label for a warning message, not the entire message. - | Info -- Should be used sparingly, not to style entire long messages. - -- For example, it's used to style the "[info]" label for an info - -- message, not the entire message. - | Debug -- Should be used sparingly, not to style entire long messages. - -- For example, it's used to style the "[debug]" label for a debug - -- message, not the entire message. - | OtherLevel -- Should be used sparingly, not to style entire long - -- messages. For example, it's used to style the "[...]" - -- label for an other log level message, not the entire - -- message. - | Good -- Style in a way to emphasize that it is a particularly good - -- thing. - | Shell -- Style as a shell command, i.e. when suggesting something to the - -- user that should be typed in directly as written. - | File -- Style as a filename. See 'Dir' for directories. - | Url -- Style as a URL. - | Dir -- Style as a directory name. See 'File' for files. - | Recommendation -- Style used to highlight part of a recommended course of - -- action. - | Current -- Style in a way that emphasizes that it is related to a current - -- thing. For example, could be used when talking about the current - -- package we're processing when outputting the name of it. - | Target -- TODO: figure out how to describe this - | Module -- Style as a module name. - | PkgComponent -- Style used to highlight the named component of a package. - | Secondary -- Style for secondary content. For example, it's used to style - -- timestamps. - | Highlight -- Should be used sparingly, not to style entire long messages. - -- For example, it's used to style the duration in a "Finished - -- process in ... ms" message. + = Error + -- ^ Intended to be used sparingly, not to style entire long messages. For + -- example, to style the @Error:@ or @[error]@ label for an error message, + -- not the entire message. + | Warning + -- ^ Intended to be used sparingly, not to style entire long messages. For + -- example, to style the @Warning:@ or @[warn]@ label for a warning message, + -- not the entire message. + | Info + -- ^ Intended to be used sparingly, not to style entire long messages. For + -- example, to style the @[info]@ label for an info message, not the entire + -- message. + | Debug + -- ^ Intended to be used sparingly, not to style entire long messages. For + -- example, to style the @[debug]@ label for a debug message, not the entire + -- message. + | OtherLevel + -- ^ Intended to be used sparingly, not to style entire long messages. For + -- example, to style the @[...]@ label for an other log level message, not + -- the entire message. + | Good + -- ^ Style in a way to emphasize that it is a particularly good thing. + | Shell + -- ^ Style as a shell command, i.e. when suggesting something to the user + -- that should be typed in directly as written. + | File + -- ^ Style as a filename. See 'Dir' for directories. + | Url + -- ^ Style as a URL. + | Dir + -- ^ Style as a directory name. See 'File' for files. + | Recommendation + -- ^ Style used to highlight part of a recommended course of action. + | Current + -- ^ Style in a way that emphasizes that it is related to a current thing. + -- For example, to report the current package that is being processed when + -- outputting the name of it. + | Target + -- ^ Style used the highlight the target of a course of action. + | Module + -- ^ Style as a module name. + | PkgComponent + -- ^ Style used to highlight the named component of a package. + | Secondary + -- ^ Style for secondary content. For example, to style timestamps. + | Highlight + -- ^ Intended to be used sparingly, not to style entire long messages. For + -- example, to style the duration in a @Finished process in ... ms@ message. deriving (Bounded, Enum, Eq, Ix, Ord, Show) -- | The first style overrides the second.
src/Text/PrettyPrint/Leijen/Extended.hs view
@@ -10,43 +10,47 @@ {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE UndecidableInstances #-} --- | This module re-exports some of the interface for --- "Text.PrettyPrint.Annotated.Leijen" along with additional definitions --- useful for stack. +-- | This module is based, in part, on some of the interface for +-- "Text.PrettyPrint.Annotated.Leijen". -- --- It defines a 'Monoid' instance for 'Doc'. module Text.PrettyPrint.Leijen.Extended ( -- * Pretty-print typeclass Pretty (..) - -- * Ansi terminal Doc - -- - -- See "System.Console.ANSI" for 'SGR' values to use beyond the colors - -- provided. + -- * Documents annotated by a style , StyleDoc (..) , StyleAnn(..) - -- hDisplayAnsi, , displayAnsi , displayPlain , renderDefault - -- * Selective re-exports from "Text.PrettyPrint.Annotated.Leijen" - -- - -- Documentation of omissions up-to-date with @annotated-wl-pprint-0.7.0@ + -- * Selective use of the "Text.PrettyPrint.Annotated.Leijen" interface + -- + -- | Documented omissions by reference to package + -- @annotated-wl-pprint-0.7.0@. - -- ** Documents, parametrized by their annotations - -- - -- Omitted compared to original: @putDoc, hPutDoc@ - -- Doc, + -- ** Documents, parametrized by their annotations + -- + -- | Omitted compared to original: + -- + -- @ + -- Doc, putDoc, hPutDoc + -- @ - -- ** Basic combinators - -- - -- Omitted compared to original: @empty, char, text, (<>)@ - -- - -- Instead of @text@ and @char@, use 'fromString'. - -- - -- Instead of @empty@, use 'mempty'. + -- ** Basic combinators + -- + -- | Omitted compared to the original: + -- + -- @ + -- empty, char, text, (<>) + -- @ + -- + -- Instead of @empty@, use 'mempty'. + -- + -- Instead of @char@ and @text@, use 'fromString'. + -- + -- A 'Monoid' instance for 'StyleDoc' is defined. , nest , line , linebreak @@ -54,28 +58,35 @@ , softline , softbreak - -- ** Alignment - -- - -- The combinators in this section can not be described by Wadler's - -- original combinators. They align their output relative to the - -- current output position - in contrast to @nest@ which always - -- aligns to the current nesting level. This deprives these - -- combinators from being \`optimal\'. In practice however they - -- prove to be very useful. The combinators in this section should - -- be used with care, since they are more expensive than the other - -- combinators. For example, @align@ shouldn't be used to pretty - -- print all top-level declarations of a language, but using @hang@ - -- for let expressions is fine. - -- - -- Omitted compared to original: @list, tupled, semiBraces@ + -- ** Alignment + -- + -- | The combinators in this section can not be described by Wadler's + -- original combinators. They align their output relative to the current + -- output position - in contrast to 'nest' which always aligns to the + -- current nesting level. This deprives these combinators from being + -- \`optimal\'. In practice however they prove to be very useful. The + -- combinators in this section should be used with care, since they are more + -- expensive than the other combinators. For example, 'align' shouldn't be + -- used to pretty print all top-level declarations of a language, but using + -- 'hang' for @let@ expressions is fine. + -- + -- Omitted compared to the original: + -- + -- @ + -- list, tupled, semiBraces + -- @ , align , hang , indent , encloseSep - -- ** Operators - -- - -- Omitted compared to original: @(<$>), (</>), (<$$>), (<//>)@ + -- ** Operators + -- + -- | Omitted compared to the original: + -- + -- @ + -- (\<$\>), (\<\/\>), (\<$$\>), (\<\/\/\>) + -- @ , (<+>) -- ** List combinators @@ -103,7 +114,7 @@ , brackets -- ** Character documents - -- Entirely omitted: + -- | Entirely omitted: -- -- @ -- lparen, rparen, langle, rangle, lbrace, rbrace, lbracket, rbracket, @@ -112,10 +123,10 @@ -- @ -- ** Primitive type documents - -- Omitted compared to the original: + -- | Omitted compared to the original: -- -- @ - -- int, integer, float, double, rational, bool, + -- int, integer, float, double, rational, bool -- @ , string @@ -125,14 +136,17 @@ , styleAnn -- ** Rendering - -- Original entirely omitted: + -- | Entirely omitted: + -- -- @ - -- SimpleDoc(..), renderPretty, renderCompact, displayDecorated, displayDecoratedA, display, displayS, displayIO, - -- SpanList(..), displaySpans + -- SimpleDoc (..), renderPretty, renderCompact, displayDecorated, + -- displayDecoratedA, display, displayS, displayIO, SpanList (..), + -- displaySpans -- @ -- ** Undocumented - -- Entirely omitted: + -- | Entirely omitted: + -- -- @ -- column, nesting, width -- @ @@ -198,7 +212,7 @@ -------------------------------------------------------------------------------- -- Style Doc --- |A style annotation. +-- | A style annotation. newtype StyleAnn = StyleAnn (Maybe Style) deriving (Eq, Show, Semigroup) @@ -206,15 +220,15 @@ mempty = StyleAnn Nothing mappend = (<>) --- |A document annotated by a style +-- | A document annotated by a style. newtype StyleDoc = StyleDoc { unStyleDoc :: Doc StyleAnn } deriving (IsString, Show) --- |An ANSI code(s) annotation. +-- | An ANSI code(s) annotation. newtype AnsiAnn = AnsiAnn [SGR] deriving (Eq, Show, Semigroup, Monoid) --- |Convert a 'SimpleDoc' annotated with 'StyleAnn' to one annotated with +-- | Convert a 'SimpleDoc' annotated with 'StyleAnn' to one annotated with -- 'AnsiAnn', by reference to a 'Styles'. toAnsiDoc :: Styles -> SimpleDoc StyleAnn -> SimpleDoc AnsiAnn toAnsiDoc styles = go @@ -398,36 +412,65 @@ getSGRTag SetRGBColor{} = TagRGBColor getSGRTag SetPaletteColor{} = TagPaletteColor +-- | The document @(x \<+\> y)@ concatenates document @x@ and @y@ with a +-- @(fromString \"\ \")@ in between. (infixr 6) (<+>) :: StyleDoc -> StyleDoc -> StyleDoc StyleDoc x <+> StyleDoc y = StyleDoc (x P.<+> y) +-- | The document @(align x)@ renders document @x@ with the nesting level set to +-- the current column. It is used for example to implement 'hang'. +-- +-- As an example, we will put a document right above another one, regardless of +-- the current nesting level: +-- +-- > x $$ y = align (x <> line <> y) +-- +-- > test = fromString "hi" <+> (fromString "nice" $$ fromString "world") +-- +-- which will be layed out as: +-- +-- @ +-- hi nice +-- world +-- @ align :: StyleDoc -> StyleDoc align = StyleDoc . P.align . unStyleDoc +-- | Strip annotations from a document. This is useful for re-using the textual +-- formatting of some sub-document, but applying a different high-level +-- annotation. noAnnotate :: StyleDoc -> StyleDoc noAnnotate = StyleDoc . P.noAnnotate . unStyleDoc +-- | Document @(braces x)@ encloses document @x@ in braces, \"{\" and \"}\". braces :: StyleDoc -> StyleDoc braces = StyleDoc . P.braces . unStyleDoc +-- | Document @(angles x)@ encloses document @x@ in angles, \"\<\" and \"\>\". angles :: StyleDoc -> StyleDoc angles = StyleDoc . P.angles . unStyleDoc +-- | Document @(parens x)@ encloses document @x@ in parenthesis, \"(\" and +-- \")\". parens :: StyleDoc -> StyleDoc parens = StyleDoc . P.parens . unStyleDoc +-- | Document @(dquotes x)@ encloses document @x@ with double quotes '\"'. dquotes :: StyleDoc -> StyleDoc dquotes = StyleDoc . P.dquotes . unStyleDoc +-- | Document @(squotes x)@ encloses document @x@ with single quotes \"'\". squotes :: StyleDoc -> StyleDoc squotes = StyleDoc . P.squotes . unStyleDoc +-- | Document @(brackets x)@ encloses document @x@ in square brackets, \"[\" and +-- \"]\". brackets :: StyleDoc -> StyleDoc brackets = StyleDoc . P.brackets . unStyleDoc -- | The document @string s@ concatenates all characters in @s@ using @line@ for --- newline characters and @char@ for all other characters. It is used whenever --- the text contains newline characters. +-- newline characters and @fromString@ for all other characters. It is used +-- whenever the text contains newline characters. -- -- @since 0.1.4.0 string :: String -> StyleDoc @@ -439,66 +482,275 @@ annotate :: StyleAnn -> StyleDoc -> StyleDoc annotate a = StyleDoc . P.annotate a . unStyleDoc +-- | The document @(nest i x)@ renders document @x@ with the current indentation +-- level increased by i (See also 'hang', 'align' and 'indent'). +-- +-- > nest 2 (fromString "hello" <> line <> fromString "world") +-- > <> line +-- > <> fromString "!" +-- +-- outputs as: +-- +-- @ +-- hello +-- world +-- ! +-- @ nest :: Int -> StyleDoc -> StyleDoc nest a = StyleDoc . P.nest a . unStyleDoc +-- | The @line@ document advances to the next line and indents to the current +-- nesting level. Document @line@ behaves like @(fromString \" \")@ if the line +-- break is undone by 'group'. line :: StyleDoc line = StyleDoc P.line +-- | The @linebreak@ document advances to the next line and indents to the +-- current nesting level. Document @linebreak@ behaves like 'mempty' if the line +-- break is undone by 'group'. linebreak :: StyleDoc linebreak = StyleDoc P.linebreak +-- | The document @(fill i x)@ renders document @x@. It than appends +-- @(fromString \"\ \")@s until the width is equal to @i@. If the width of @x@ +-- is already larger, nothing is appended. This combinator is quite useful in +-- practice to output a list of bindings. The following example demonstrates +-- this. +-- +-- > types = [ ("empty", "Doc a") +-- > , ("nest", "Int -> Doc a -> Doc a") +-- > , ("linebreak", "Doc a") +-- > ] +-- > +-- > ptype (name, tp) = +-- > fill 6 (fromString name) <+> fromString "::" <+> fromString tp +-- > +-- > test = fromString "let" <+> align (vcat (map ptype types)) +-- +-- Which is layed out as: +-- +-- @ +-- let empty :: Doc a +-- nest :: Int -> Doc a -> Doc a +-- linebreak :: Doc a +-- @ fill :: Int -> StyleDoc -> StyleDoc fill a = StyleDoc . P.fill a . unStyleDoc +-- | The document @(fillBreak i x)@ first renders document @x@. It then appends +-- @(fromString \"\ \")@s until the width is equal to @i@. If the width of @x@ +-- is already larger than @i@, the nesting level is increased by @i@ and a +-- @line@ is appended. When we redefine @ptype@ in the previous example to use +-- @fillBreak@, we get a useful variation of the previous output: +-- +-- > ptype (name, tp) = +-- > fillBreak 6 (fromString name) <+> fromString "::" <+> fromString tp +-- +-- The output will now be: +-- +-- @ +-- let empty :: Doc a +-- nest :: Int -> Doc a -> Doc a +-- linebreak +-- :: Doc a +-- @ fillBreak :: Int -> StyleDoc -> StyleDoc fillBreak a = StyleDoc . P.fillBreak a . unStyleDoc +-- | The document @(enclose l r x)@ encloses document @x@ between documents @l@ +-- and @r@ using @(\<\>)@. +-- +-- > enclose l r x = l <> x <> r enclose :: StyleDoc -> StyleDoc -> StyleDoc -> StyleDoc enclose l r x = l <> x <> r +-- | The document @(cat xs)@ concatenates all documents @xs@ either +-- horizontally with @(\<\>)@, if it fits the page, or vertically with +-- @(\<\> linebreak \<\>)@. +-- +-- > cat xs = group (vcat xs) cat :: [StyleDoc] -> StyleDoc cat = StyleDoc . P.cat . map unStyleDoc +-- | @(punctuate p xs)@ concatenates all documents in @xs@ with document @p@ +-- except for the last document. +-- +-- > someText = map fromString ["words", "in", "a", "tuple"] +-- > test = parens (align (cat (punctuate comma someText))) +-- +-- This is layed out on a page width of 20 as: +-- +-- @ +-- (words,in,a,tuple) +-- @ +-- +-- But when the page width is 15, it is layed out as: +-- +-- @ +-- (words, +-- in, +-- a, +-- tuple) +-- @ +-- +-- (If you want put the commas in front of their elements instead of at the end, +-- you should use 'encloseSep'.) punctuate :: StyleDoc -> [StyleDoc] -> [StyleDoc] punctuate (StyleDoc x) = map StyleDoc . P.punctuate x . map unStyleDoc +-- | The document @(fillCat xs)@ concatenates documents @xs@ horizontally with +-- @(\<\>)@ as long as its fits the page, than inserts a @linebreak@ and +-- continues doing that for all documents in @xs@. +-- +-- > fillCat xs = foldr (<> softbreak <>) mempty xs fillCat :: [StyleDoc] -> StyleDoc fillCat = StyleDoc . P.fillCat . map unStyleDoc +-- | The document @(hcat xs)@ concatenates all documents @xs@ horizontally with +-- @(\<\>)@. hcat :: [StyleDoc] -> StyleDoc hcat = StyleDoc . P.hcat . map unStyleDoc +-- | The document @(vcat xs)@ concatenates all documents @xs@ vertically with +-- @(\<\> linebreak \<\>)@. If a 'group' undoes the line breaks inserted by +-- 'vcat', all documents are directly concatenated. vcat :: [StyleDoc] -> StyleDoc vcat = StyleDoc . P.vcat . map unStyleDoc +-- | The document @(sep xs)@ concatenates all documents @xs@ either horizontally +-- with @(\<+\>)@, if it fits the page, or vertically with @(\<\> line \<\>)@. +-- +-- > sep xs = group (vsep xs) sep :: [StyleDoc] -> StyleDoc sep = StyleDoc . P.sep . map unStyleDoc +-- | The document @(vsep xs)@ concatenates all documents @xs@ vertically with +-- @(\<\> line \<\>)@. If a 'group' undoes the line breaks inserted by 'vsep', +-- all documents are separated with a space. +-- +-- > someText = map fromString (words ("text to lay out")) +-- > +-- > test = fromString "some" <+> vsep someText +-- +-- This is layed out as: +-- +-- @ +-- some text +-- to +-- lay +-- out +-- @ +-- +-- The 'align' combinator can be used to align the documents under their first +-- element +-- +-- > test = fromString "some" <+> align (vsep someText) +-- +-- Which is printed as: +-- +-- @ +-- some text +-- to +-- lay +-- out +-- @ vsep :: [StyleDoc] -> StyleDoc vsep = StyleDoc . P.vsep . map unStyleDoc +-- | The document @(hsep xs)@ concatenates all documents @xs@ horizontally with +-- @('<+>')@. hsep :: [StyleDoc] -> StyleDoc hsep = StyleDoc . P.hsep . map unStyleDoc +-- | The document @(fillSep xs)@ concatenates documents @xs@ horizontally with +-- @('<+>')@ as long as its fits the page, than inserts a 'line' and continues +-- doing that for all documents in @xs@. +-- +-- > fillSep xs = foldr (<> softline <>) mempty xs fillSep :: [StyleDoc] -> StyleDoc fillSep = StyleDoc . P.fillSep . map unStyleDoc +-- | The document @(encloseSep l r sep xs)@ concatenates the documents @xs@ +-- separated by @sep@ and encloses the resulting document by @l@ and @r@. The +-- documents are rendered horizontally if that fits the page. Otherwise they are +-- aligned vertically. All separators are put in front of the elements. For +-- example, the combinator 'list' can be defined with 'encloseSep': +-- +-- > list xs = encloseSep lbracket rbracket comma xs +-- > test = fromString "list" <+> (list (map int [10, 200, 3000])) +-- +-- Which is layed out with a page width of 20 as: +-- +-- @ +-- list [10,200,3000] +-- @ +-- +-- But when the page width is 15, it is layed out as: +-- +-- @ +-- list [10 +-- ,200 +-- ,3000] +-- @ encloseSep :: StyleDoc -> StyleDoc -> StyleDoc -> [StyleDoc] -> StyleDoc encloseSep (StyleDoc x) (StyleDoc y) (StyleDoc z) = StyleDoc . P.encloseSep x y z . map unStyleDoc +-- | The document @(indent i x)@ indents document @x@ with @i@ spaces. +-- +-- > test = indent 4 (fillSep (map fromString +-- > (words "the indent combinator indents these words !"))) +-- +-- Which lays out with a page width of 20 as: +-- +-- @ +-- the indent +-- combinator +-- indents these +-- words ! +-- @ indent :: Int -> StyleDoc -> StyleDoc indent a = StyleDoc . P.indent a . unStyleDoc +-- | The hang combinator implements hanging indentation. The document +-- @(hang i x)@ renders document @x@ with a nesting level set to the current +-- column plus @i@. The following example uses hanging indentation for some +-- text: +-- +-- > test = hang 4 (fillSep (map fromString +-- > (words "the hang combinator indents these words !"))) +-- +-- Which lays out on a page with a width of 20 characters as: +-- +-- @ +-- the hang combinator +-- indents these +-- words ! +-- @ +-- +-- The @hang@ combinator is implemented as: +-- +-- > hang i x = align (nest i x) hang :: Int -> StyleDoc -> StyleDoc hang a = StyleDoc . P.hang a . unStyleDoc +-- | The document @softbreak@ behaves like 'mempty' if the resulting output fits +-- the page, otherwise it behaves like 'line'. +-- +-- > softbreak = group linebreak softbreak :: StyleDoc softbreak = StyleDoc P.softbreak +-- | The document @softline@ behaves like @(fromString \"\ \")@ if the resulting +-- output fits the page, otherwise it behaves like 'line'. +-- +-- > softline = group line softline :: StyleDoc softline = StyleDoc P.softline +-- | The @group@ combinator is used to specify alternative layouts. The document +-- @(group x)@ undoes all line breaks in document @x@. The resulting line is +-- added to the current line if that fits the page. Otherwise, the document @x@ +-- is rendered without any changes. group :: StyleDoc -> StyleDoc group = StyleDoc . P.group . unStyleDoc