@@ -36,12 +36,23 @@ type Table = ([Cell], [[Cell]]) --header, body
36addRow :: [Cell] -> Table -> Table
36addRow :: [Cell] -> Table -> Table
37addRow cells (header,body) = (header, body ++ [cells])
37addRow cells (header,body) = (header, body ++ [cells])
39−columnLocations :: Table -> [Int]
39+--calculate maximum per-row and per-column sizes
40−columnLocations (header, body) = foldl sizeFolder (head cellSizes) cellSizes
40+
41+cellLocations :: Table -> ([Int],[Int]) --column size, row size
42+cellLocations tab@(header, body) = (maxWidths, maxHeights)
44+ cellSizeMatrix = cellSizes tab
45+ maxWidths = foldl mergeMax (baseSize (length cellSizeMatrix)) (map fst cellSizeMatrix)
46+ baseSize num = take num (repeat 0)
47+ rowHeights = map snd cellSizeMatrix
48+ maxHeights = map (L.maximumBy compare) rowHeights
49+ mergeMax a b = map (\(a,b) -> max a b) (zip a b)
51+cellSizes :: Table -> [([Int], [Int])]
52+cellSizes (header, body) = map (\row -> (map maxRowWidth row, map (length . lines) row)) allRows
42− cellSizes = map (\row -> map length row) (body ++ [header]) --bar padding
54+ maxRowWidth row = L.maximumBy compare (map length (lines row))
43− sizeFolder acc row = mergeMax row acc
55+ allRows = [header] ++ body
44− mergeMax a b = map (\(x,y) -> if x > y then x else y) (zip a b)
46relationAsTable :: Relation -> Table
57relationAsTable :: Relation -> Table
47relationAsTable rel@(Relation attributes tupleSet) = (header, body)
58relationAsTable rel@(Relation attributes tupleSet) = (header, body)
@@ -58,31 +69,38 @@ showAtom (IntAtom i) = show i
58showAtom (RelationAtom rel) = renderTable $ relationAsTable rel
69showAtom (RelationAtom rel) = renderTable $ relationAsTable rel
60renderTable :: Table -> String
71renderTable :: Table -> String
61−renderTable table = renderHeader table colLocations ++ renderBody (snd table) colLocations
72+renderTable table = renderHeader table (fst cellLocs) ++ renderBody (snd table) cellLocs
63− colLocations = columnLocations table
74+ cellLocs = cellLocations table
65renderHeader :: Table -> [Int] -> String
76renderHeader :: Table -> [Int] -> String
66renderHeader (header, body) columnLocations = renderTopBar ++ renderHeaderNames ++ renderBottomBar ++ "\n"
77renderHeader (header, body) columnLocations = renderTopBar ++ renderHeaderNames ++ renderBottomBar ++ "\n"
68 renderTopBar = boxTL ++ concat (L.intersperse boxTB (map (\x -> repeatString x boxH) columnLocations)) ++ boxTR ++ "\n"
79 renderTopBar = boxTL ++ concat (L.intersperse boxTB (map (\x -> repeatString x boxH) columnLocations)) ++ boxTR ++ "\n"
69− renderHeaderNames = renderRow header columnLocations boxV
80+ renderHeaderNames = renderRow header columnLocations 1 boxV
70 renderBottomBar = if length body == 0 then ""
81 renderBottomBar = if length body == 0 then ""
71 else renderHBar boxLB boxC boxRB columnLocations
82 else renderHBar boxLB boxC boxRB columnLocations
73renderHBar :: String -> String -> String -> [Int] -> String
84renderHBar :: String -> String -> String -> [Int] -> String
74renderHBar left middle end columnLocations = left ++ concat (L.intersperse middle (map (\x -> repeatString x boxH) columnLocations)) ++ end
85renderHBar left middle end columnLocations = left ++ concat (L.intersperse middle (map (\x -> repeatString x boxH) columnLocations)) ++ end
76−leftPaddedString :: Int -> String -> String
87+leftPaddedString :: Int -> Int -> String -> String
77−leftPaddedString size str = str ++ repeatString (size - length str) " "
88+leftPaddedString lineNum size str = paddedLines !! lineNum
90+ paddedLines = map (\s -> s ++ repeatString (size - length s) " ") (lines str ++ repeat "")
79−renderRow :: [Cell] -> [Int] -> String -> String
92+renderRow :: [Cell] -> [Int] -> Int -> String -> String
93+renderRow cells columnLocations rowHeight interspersed = unlines $ map renderOneLine [0..rowHeight-1]
80−renderRow cells columnLocations interspersed = boxV ++ concat (L.intersperse interspersed (map (\(size, value) -> leftPaddedString size value) (zip columnLocations cells))) ++ boxV ++ "\n"
95+ renderOneLine lineNum = boxV ++ concat (L.intersperse interspersed (map (\(size, value) -> leftPaddedString lineNum size value) (zip columnLocations cells))) ++ boxV
82−renderBody :: [[Cell]] -> [Int] -> String
97+renderBody :: [[Cell]] -> ([Int],[Int]) -> String
83−renderBody cellMatrix columnLocations = renderRows ++ renderBottomBar
98+renderBody cellMatrix cellLocations = renderRows ++ renderBottomBar
100+ columnLocations = fst cellLocations
101+ rowLocations = snd cellLocations
85− renderRows = concat (map (\r-> renderRow r columnLocations boxV) cellMatrix)
102+ renderRows = concat (map (\(row, rowHeight)-> renderRow row columnLocations rowHeight boxV) rowHeightMatrix)
103+ rowHeightMatrix = zip cellMatrix (tail rowLocations)
86 renderBottomBar = renderHBar boxBL boxBB boxBR columnLocations
104 renderBottomBar = renderHBar boxBL boxBB boxBR columnLocations
88orderedAttributeNames :: Relation -> [AttributeName]
106orderedAttributeNames :: Relation -> [AttributeName]
@@ -97,6 +115,7 @@ showRelation rel
97 | rel == relationFalse = "false"
115 | rel == relationFalse = "false"
98 | otherwise = renderTable (relationAsTable rel)
116 | otherwise = renderTable (relationAsTable rel)
120+groupedExample = case group (S.fromList ["CITY"]) "CITYREL" s of {Right rel -> rel}