Text.PrettyPrint:从左边距开始缩进

时间:2012-03-15 02:43:29

标签: haskell pretty-print

我正在尝试使用Text.PrettyPrint生成Javascript。问题是nest在放在另一个漂亮元素旁边时会产生巨大的缩进。例如,在此代码中:

import Text.PrettyPrint

fun :: Doc
fun = vcat [ text "function" <+> lbrace
           , nest 4 $ vcat $ replicate 5 $ text "// foo"
           , rbrace
           ]

var :: Doc
var = text "var" <+> text "x"

test :: Doc
test = var <+> equals <+> fun <> semi

funtest中的第9列开始(因为它左边是var <+> equals <> empty),因此其后续行缩进了9 + 4 = 13列:

var x = function {
            // foo
            // foo
            // foo
            // foo
            // foo
        };

有没有办法从左边距渲染缩进,以便将上面的内容呈现为

var x = function {
    // foo
    // foo
    // foo
    // foo
    // foo
};

3 个答案:

答案 0 :(得分:2)

offset = 1 + length (render $ var <+> equals)
hang empty (negate offset) test

答案 1 :(得分:2)

解决方案确实是使用wl-pprint(并将nest替换为indent)。然后,给出的代码产生

var x = function {
    // foo
    // foo
    // foo
    // foo
    // foo
};

根据需要。对于仍然打算尝试攻击pretty的人,请注意虽然Doc的构造函数未公开,但您仍然可以通过Generic {{1}来获取它们}}:

-XPatternSynonyms

问题主要是没有违反图书馆的许多不变量。

作为旁注,我还发现了wl-pprint-annotated,这是对-- | Means of exposing the data constructors of `Doc` from `pretty` pattern GEmpty = M1 (L1 (L1 (L1 (M1 U1)))) pattern GNilAbove doc = M1 (L1 (L1 (R1 (M1 (M1 (K1 doc)))))) pattern GTextBeside d doc = M1 (L1 (R1 (L1 (M1 (M1 (K1 d) :*: M1 (K1 doc)))))) pattern GNest n doc = M1 (L1 (R1 (R1 (M1 (M1 (K1 n) :*: M1 (K1 doc)))))) pattern GUnion ldoc rdoc = M1 (R1 (L1 (L1 (M1 (M1 (K1 ldoc) :*: M1 (K1 rdoc)))))) pattern GNoDoc = M1 (R1 (L1 (R1 (M1 U1)))) pattern GBeside ldoc s rdoc = M1 (R1 (R1 (L1 (M1 (M1 (K1 ldoc) :*: M1 (K1 s) :*: M1 (K1 rdoc)))))) pattern GAbove ldoc b rdoc = M1 (R1 (R1 (R1 (M1 (M1 (K1 ldoc) :*: M1 (K1 b) :*: M1 (K1 rdoc)))))) 的现代重写,使用它可以访问底层数据构造函数(代价是需要记住不变量)参与)。这实际上是我最终会使用的包。

特别是,它允许我制作这种支撑块,如果它足够小,它只会在一行上出现:

wl-pprint

然后我得到了很好的结果,自动执行或不跨越多行:

-- | Asserts a 'Doc a' cannot render on multiple lines.
oneLine :: Doc a -> Bool
oneLine (WL.FlatAlt d _) = oneLine d
oneLine (WL.Cat a b) = oneLine a && oneLine b
oneLine (WL.Union a b) = oneLine a && oneLine b
oneLine (WL.Annotate _ d) = oneLine d
oneLine WL.Line = False
oneLine _ = True

-- | Make a curly-brace delimited block. When possible, permit fitting everything on one line
block :: Doc a -> Doc a
block b | oneLine b = hsep ["{", b, "}"] `WL.Union` vsep [ "{", indent 2 b, "}" ]
        | otherwise = vsep [ "{", indent 2 b, "}" ]

答案 2 :(得分:1)

通过将vcat应用于第一项还包含变量定义和赋值的列表,您可以获得所需的结果。

示例:

fun :: Doc
fun = vcat [ var <+> equals <+> text "function" <+> lbrace
           , nest 4 $ vcat $ replicate 5 $ text "// foo"
           , rbrace
           ]

var :: Doc
var = text "var" <+> text "x"

test :: Doc
test = fun <> semi