Fix #16; Improve layouting in two cases; Add comments

- the #16 fix is a one-liner:
  Throw `nub` at spacings before pruning.
- Expr/OpApp layouting: Force single-line for children in
  the params-in-multiple-lines-right-of-the-function case.
- Expr/HsIf layouting: Insert a SetBaseY to prevent
  "then"/"else" being placed left of "if".
pull/35/head
Lennart Spitzner 2017-03-16 23:02:11 +01:00
parent 19a05d01c4
commit a7e4bdc168
4 changed files with 97 additions and 20 deletions

View File

@ -690,10 +690,8 @@ showPackageDetailedInfo pkginfo =
, entry "Documentation" haddockHtml showIfInstalled text , entry "Documentation" haddockHtml showIfInstalled text
, entry "Cached" haveTarball alwaysShow dispYesNo , entry "Cached" haveTarball alwaysShow dispYesNo
, if not (hasLib pkginfo) , if not (hasLib pkginfo)
then then empty
empty else text "Modules:"
else
text "Modules:"
$+$ nest 4 (vcat (map disp . sort . modules $ pkginfo)) $+$ nest 4 (vcat (map disp . sort . modules $ pkginfo))
] ]
@ -710,6 +708,10 @@ foo = Reflex.runSpiderHost $ ReflexHost.hostApp $ do
liftIO . forkIO . forever $ getLine >>= inputFire liftIO . forkIO . forever $ getLine >>= inputFire
ReflexHost.performEvent_ $ fmap (liftIO . putStrLn) inputEvent ReflexHost.performEvent_ $ fmap (liftIO . putStrLn) inputEvent
#test issue 16
foldrDesc f z = unSwitchQueue $ \q ->
switch (Min.foldrDesc (f unTaggedF) z q) (Min.foldrAsc (f unTaggedF) z q)
############################################################################### ###############################################################################
############################################################################### ###############################################################################

View File

@ -109,24 +109,36 @@ layoutExpr lexpr@(L _ expr) = docWrapNode lexpr $ case expr of
headDoc <- docSharedWrapper layoutExpr headE headDoc <- docSharedWrapper layoutExpr headE
paramDocs <- docSharedWrapper layoutExpr `mapM` paramEs paramDocs <- docSharedWrapper layoutExpr `mapM` paramEs
docAlt docAlt
[ docCols ColApp [ -- foo x y
docCols ColApp
$ appSep (docForceSingleline headDoc) $ appSep (docForceSingleline headDoc)
: spacifyDocs (docForceSingleline <$> paramDocs) : spacifyDocs (docForceSingleline <$> paramDocs)
, docSeq , -- foo x
-- y
docSeq
[ appSep (docForceSingleline headDoc) [ appSep (docForceSingleline headDoc)
, docSetBaseY , docSetBaseY
$ docAddBaseY BrIndentRegular $ docAddBaseY BrIndentRegular
$ docLines $ docLines
$ paramDocs $ (docForceSingleline <$> paramDocs)
] ]
, docSetParSpacing , -- foo
-- x
-- y
docSetParSpacing
$ docAddBaseY BrIndentRegular $ docAddBaseY BrIndentRegular
$ docPar $ docPar
(docForceSingleline headDoc) (docForceSingleline headDoc)
( docNonBottomSpacing ( docNonBottomSpacing
$ docLines paramDocs $ docLines paramDocs
) )
, docAddBaseY BrIndentRegular , -- ( multi
-- line
-- function
-- )
-- x
-- y
docAddBaseY BrIndentRegular
$ docPar $ docPar
headDoc headDoc
( docNonBottomSpacing ( docNonBottomSpacing
@ -317,7 +329,8 @@ layoutExpr lexpr@(L _ expr) = docWrapNode lexpr $ case expr of
elseExprDoc <- docSharedWrapper layoutExpr elseExpr elseExprDoc <- docSharedWrapper layoutExpr elseExpr
hasComments <- hasAnyCommentsBelow lexpr hasComments <- hasAnyCommentsBelow lexpr
docAltFilter docAltFilter
[ (,) (not hasComments) [ -- if _ then _ else _
(,) (not hasComments)
$ docSeq $ docSeq
[ appSep $ docLit $ Text.pack "if" [ appSep $ docLit $ Text.pack "if"
, appSep $ docForceSingleline ifExprDoc , appSep $ docForceSingleline ifExprDoc
@ -326,7 +339,20 @@ layoutExpr lexpr@(L _ expr) = docWrapNode lexpr $ case expr of
, appSep $ docLit $ Text.pack "else" , appSep $ docLit $ Text.pack "else"
, docForceSingleline elseExprDoc , docForceSingleline elseExprDoc
] ]
, (,) True , -- either
-- if expr
-- then foo
-- bar
-- else foo
-- bar
-- or
-- if expr
-- then
-- stuff
-- else
-- stuff
-- note that this has par-spacing
(,) True
$ docSetParSpacing $ docSetParSpacing
$ docAddBaseY BrIndentRegular $ docAddBaseY BrIndentRegular
$ docPar $ docPar
@ -350,7 +376,24 @@ layoutExpr lexpr@(L _ expr) = docWrapNode lexpr $ case expr of
$ docPar (docLit $ Text.pack "else") elseExprDoc $ docPar (docLit $ Text.pack "else") elseExprDoc
] ]
]) ])
, (,) True , -- either
-- if multi
-- line
-- condition
-- then foo
-- bar
-- else foo
-- bar
-- or
-- if multi
-- line
-- condition
-- then
-- stuff
-- else
-- stuff
-- note that this does _not_ have par-spacing
(,) True
$ docAddBaseY BrIndentRegular $ docAddBaseY BrIndentRegular
$ docPar $ docPar
( docAddBaseY (BrIndentSpecial 3) ( docAddBaseY (BrIndentSpecial 3)
@ -374,6 +417,7 @@ layoutExpr lexpr@(L _ expr) = docWrapNode lexpr $ case expr of
] ]
]) ])
, (,) True , (,) True
$ docSetBaseY
$ docLines $ docLines
[ docAddBaseY (BrIndentSpecial 3) [ docAddBaseY (BrIndentSpecial 3)
$ docSeq $ docSeq

View File

@ -552,6 +552,11 @@ getSpacings
-> Memo.MemoT Int [VerticalSpacing] m [VerticalSpacing] -> Memo.MemoT Int [VerticalSpacing] m [VerticalSpacing]
getSpacings limit bridoc = preFilterLimit <$> rec bridoc getSpacings limit bridoc = preFilterLimit <$> rec bridoc
where where
-- when we do `take K . filter someCondition` on a list of spacings, we
-- need to first (also) limit the size of the input list, otherwise a
-- _large_ input with a similarly _large_ prefix not passing our filtering
-- process could lead to exponential runtime behaviour.
-- TODO: 3 is arbitrary.
preFilterLimit :: [VerticalSpacing] -> [VerticalSpacing] preFilterLimit :: [VerticalSpacing] -> [VerticalSpacing]
preFilterLimit = take (3*limit) preFilterLimit = take (3*limit)
memoWithKey :: Memo.MonadMemo k v m1 => k -> m1 v -> m1 v memoWithKey :: Memo.MonadMemo k v m1 => k -> m1 v -> m1 v
@ -565,15 +570,41 @@ getSpacings limit bridoc = preFilterLimit <$> rec bridoc
VerticalSpacingParNone -> True VerticalSpacingParNone -> True
VerticalSpacingParSome i -> i <= colMax VerticalSpacingParSome i -> i <= colMax
VerticalSpacingParAlways{} -> True VerticalSpacingParAlways{} -> True
let filterAndLimit :: [VerticalSpacing] -> [VerticalSpacing] let -- the standard function used to enforce a constant upper bound
-- on the number of elements returned for each node. Should be
-- applied whenever in a parent the combination of spacings from
-- its children might cause excess of the upper bound.
filterAndLimit :: [VerticalSpacing] -> [VerticalSpacing]
filterAndLimit = take limit filterAndLimit = take limit
-- prune so we always consider a constant
-- amount of spacings per node of the BriDoc.
. filter hasOkColCount . filter hasOkColCount
. preFilterLimit -- we need to limit here in case -- throw out any spacings (i.e. children) that
-- that the input list is -- already use more columns than available in
-- _large_ with a similarly _large_ -- total.
-- prefix not passing hasOkColCount . List.nub
-- predicate. -- In the end we want to know if there is at least
-- TODO: 3 is arbitrary. -- one valid spacing for any alternative.
-- If there are duplicates in the list, then these
-- will either all be valid (so having more than the
-- first is pointless) or all invalid (in which
-- case having any of them is pointless).
-- Nonetheless I think the order of spacings should
-- be preserved as it provides a deterministic
-- choice for which spacings to prune (which is
-- an argument against simly using a Set).
-- I have also considered `fmap head . group` which
-- seems to work similarly well for common cases
-- and which might behave even better when it comes
-- to determinism of the algorithm. But determinism
-- should not be overrated here either - in the end
-- this is about deterministic behaviour of the
-- pruning we do that potentially results in
-- non-optimal layouts, and we'd rather take optimal
-- layouts when we can than take non-optimal layouts
-- just to be consistent with other cases where
-- we'd choose non-optimal layouts.
. preFilterLimit
result <- case brdc of result <- case brdc of
-- BDWrapAnnKey _annKey bd -> rec bd -- BDWrapAnnKey _annKey bd -> rec bd
BDFEmpty -> BDFEmpty ->

View File

@ -412,7 +412,7 @@ data VerticalSpacing
, _vs_paragraph :: !VerticalSpacingPar , _vs_paragraph :: !VerticalSpacingPar
, _vs_parFlag :: !Bool , _vs_parFlag :: !Bool
} }
deriving Show deriving (Eq, Show)
newtype LineModeValidity a = LineModeValidity (Strict.Maybe a) newtype LineModeValidity a = LineModeValidity (Strict.Maybe a)
deriving (Functor, Applicative, Monad, Show, Alternative) deriving (Functor, Applicative, Monad, Show, Alternative)