pretty-tree (empty) → 0.1.0.0
raw patch · 4 files changed
+261/−0 lines, 4 filesdep +basedep +boxesdep +containerssetup-changed
Dependencies added: base, boxes, containers
Files
- Data/Tree/Pretty.hs +209/−0
- LICENSE +30/−0
- Setup.hs +2/−0
- pretty-tree.cabal +20/−0
+ Data/Tree/Pretty.hs view
@@ -0,0 +1,209 @@+{- |+ Module : Data.Tree.Pretty+ Description : Pretty-print trees.+ Copyright : (c) Ivan Lazar Miljenovic+ License : 3-Clause BSD-style+ Maintainer : Ivan.Miljenovic@gmail.com++"Data.Tree" exports 'drawTree' and 'drawForest', which provide 2D+pretty-printing of rose-trees, but in a left-to-right fashion.++The functions here draw trees more \"naturally\" in a top-down fashion.++For example, consider the following tree:++> tree :: Tree String+> tree = Node "hello" [ Node "foo" []+> , Node "bars" [ Node "oi!" []+> , Node "baz" [ Node "a" [ Node "b" []+> , Node "c" []]+> , Node "d" [ Node "e" []]]]+> , Node "foobar" []]++Comparing 'drawTree' and 'drawVerticalTree':++>>> putStrLn $ drawTree tree+hello+|++- foo+|++- bars+| |+| +- oi!+| |+| `- baz+| |+| +- a+| | |+| | +- b+| | |+| | `- c+| |+| `- d+| |+| `- e+|+`- foobar++>>> putStrLn $ drawVerticalTree+ hello+ |+ -------------------+ / | \+foo bars foobar+ |+ ------+ / \+ oi! baz+ |+ ----+ / \+ a d+ | |+ -- e+ / \+ b c++Also consider the @Diagrams.TwoD.Layout.Tree@ module from+/diagrams-contrib/ for actual image rendering of rose-trees:+<http://hackage.haskell.org/package/diagrams-contrib>++ -}+module Data.Tree.Pretty+ ( -- * Drawing trees+ drawVerticalTree+ , drawVerticalTreeWith+ -- * Drawing forests+ , drawVerticalForest+ , drawVerticalForestWith+ -- * Widths of gaps between trees.+ , Width+ , defaultGap+ -- * Helper functions+ , treeToBox+ ) where++import Data.Tree+import Data.List(intersperse)+import Text.PrettyPrint.Boxes+import Control.Monad(ap, liftM2)++-- -----------------------------------------------------------------------------++-- | Draw a tree top-down.+drawVerticalTree :: Tree String -> String+drawVerticalTree = drawVerticalTreeWith defaultGap++-- | Draw a tree top-down using the specified gap between sub-trees.+drawVerticalTreeWith :: Width -> Tree String -> String+drawVerticalTreeWith gp = render . treeToBox gp++-- | Draw a forest with each tree being top-down.+drawVerticalForest :: Forest String -> String+drawVerticalForest = drawVerticalForestWith defaultGap++-- | Draw a forest with each tree being top-down and the specified+-- horizontal gap between trees.+drawVerticalForestWith :: Width -> Forest String -> String+drawVerticalForestWith gp = render . hsep gp top . map (treeToBox gp)++checkGap :: Width -> Width+checkGap = max 1++-- | This is exported in case you want to do further pretty-printing+-- using "Text.PrettyPrint.Boxes".+treeToBox :: Width -> Tree String -> Box+treeToBox = liftM2 (.) treeBox addWidthTree . checkGap++-- | The size of the gap to use. It is recommended that you use a+-- value @>=2@ for best results (with @2@ being the default).+type Width = Int++defaultGap :: Width+defaultGap = 2++-- -----------------------------------------------------------------------------+-- Pre-processing++-- | We need to know how wide the tree is.+data WidthLabel = WL { trWidth :: Width+ , numSub :: Int+ , label :: String+ }+ deriving (Eq, Ord, Show, Read)++type WidthTree = Tree WidthLabel+type WidthForest = Forest WidthLabel++addWidthTree :: Width -> Tree String -> WidthTree+addWidthTree gp (Node str ts) = Node (WL w ns str) ts'+ where+ ts' = addWidthsForest gp ts+ ns = length ts+ w = length str `max` forestWidth gp ts'++addWidthsForest :: Width -> Forest String -> WidthForest+addWidthsForest gp = map (addWidthTree gp)++-- -----------------------------------------------------------------------------+-- Drawing++treeBox :: Width -> WidthTree -> Box+treeBox gp (Node lbl ts)+ = case ts of+ [] -> lbl'+ -- Three vLines to get the gap right.+ [t] -> vcat' [lbl', vLine, treeBox gp t]+ _ -> vcat' [lbl', vLine, lnTs]+ where+ numTs = numSub lbl++ lbl' = text $ label lbl++ lnWidth = sum (interTreeSpacing gp ts) + numTs -- + the vertical lines++ iniGp = (`div` 2) . pred . trWidth . rootLabel $ head ts++ ln = moveRight (iniGp + 1) $ hcat top (replicate (lnWidth - 2) hLine)++ ts' = hsep gp top $ zipWith subT [1..] ts++ lnTs = ln // ts'++ subT n t = vcat' [vln, treeBox gp t]+ where+ vln | n == 1 = lBranch+ | n == numTs = rBranch+ | otherwise = vLine++treeWidth :: WidthTree -> Width+treeWidth = trWidth . rootLabel++forestWidth :: Width -> WidthForest -> Width+forestWidth gp = sum . intersperse gp . map treeWidth++-- | The width between the vertical lines coming into neighbouring sub-trees.+interTreeSpacing :: Width -> WidthForest -> [Width]+interTreeSpacing gp = (zipWith go `ap` tail) . map (pred . trWidth . rootLabel)+ where+ go l r = (l `divUp` 2) + gp + (r `div` 2)++-- -----------------------------------------------------------------------------++vLine :: Box+vLine = char '|'++hLine :: Box+hLine = char '-'++lBranch :: Box+lBranch = char '/'++rBranch :: Box+rBranch = char '\\'++divUp :: Int -> Int -> Int+a `divUp` b = negate $ (-a) `div` b++vcat' :: [Box] -> Box+vcat' = vcat center1
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright (c) 2012, Ivan Lazar Miljenovic++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++ * Redistributions of source code must retain the above copyright+ notice, this list of conditions and the following disclaimer.++ * Redistributions in binary form must reproduce the above+ copyright notice, this list of conditions and the following+ disclaimer in the documentation and/or other materials provided+ with the distribution.++ * Neither the name of Ivan Lazar Miljenovic nor the names of other+ contributors may be used to endorse or promote products derived+ from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ pretty-tree.cabal view
@@ -0,0 +1,20 @@+name: pretty-tree+version: 0.1.0.0+synopsis: Pretty-print trees+description: Alternative pretty-printing functions for Data.Tree.+license: BSD3+license-file: LICENSE+author: Ivan Lazar Miljenovic+maintainer: Ivan.Miljenovic@gmail.com+copyright: Ivan Lazar Miljenovic+category: Data+build-type: Simple+cabal-version: >=1.6++source-repository head+ type: darcs+ location: http://hub.darcs.net/ivanm/pretty-tree++library+ exposed-modules: Data.Tree.Pretty+ build-depends: base < 5, containers, boxes >= 0.1.1 && < 0.2