> module PrettyPrint (prettyPrint) where > import Type_Data > import Opts Call the appropriate printing function > prettyPrint :: MyOptions -> [FileInfo] -> [(String, Int)] -> IO() > prettyPrint opts fis sis > = if (long_output opts) > then long_print fis sis > else if comma_list opts > then print_comma_list opts sis 0 > else if one_per_line opts > then printnlinesstd opts len len sis > else case (prettyprintdir opts) of > Down -> printnlinesstd opts len 1 sis > Across -> printnperlinealt opts 2 sis > where len = length sis ===== Print detailed info, one file per line with total blocks at the top > long_print :: [FileInfo] -> [(String, Int)] -> IO() > long_print fis sis = putStr "total " > >> (putStr $ show $ total_blolen fis) > >> putStr "\n" > >> (long_print_files $ map fst sis) Returns the total number of blocks used by a directory > total_blolen :: [FileInfo] -> Int > total_blolen fis = foldr (\(_,_,sb,_,_,_) tot -> sb + tot) 0 fis Print output in the long format, i.e. each entry on it's own line > long_print_files :: [String] -> IO() > long_print_files [] = putStr "" > long_print_files (s:ss) = putStr (s ++ "\n") >> long_print_files ss ===== Increase the number of entries in each column (n) up to a maximum of maxl until it fits, then call reallyprint to print it > printnlinesstd :: MyOptions -> Int -> Int -> [(String, Int)] -> IO() > printnlinesstd opts maxl n xs > = if (maxl == n) > then reallyprint opts maxlengths $ map (\a -> [a]) xs > else if too_wide (screen_width opts + 2) 0 lists > then printnlinesstd opts maxl (n + 1) xs > else reallyprint opts maxlengths lists > where maxlengths = findmaxlengths lists > lists = nlists n xs PrettyPrint> nlists 3 [1,2,3,4,5,6,7,8,9,10] [[1,4,7,10],[2,5,8],[3,6,9]] > nlists :: Int -> [a] -> [[a]] > {-# SPECIALIZE nlists :: Int -> [(String, Int)] -> [[(String, Int)]] #-} > nlists n [] = replicate n [] > nlists n xs = merg this rest > where rest = nlists n other > (this, other) = splitAt n xs > merg (a:as) (bs:bss) = (a:bs):(merg as bss) > merg as [] = map (\a -> [a]) as > merg [] _ = [] ===== Keep going until we go too far and we can't fit it any more so print the previous one - note, start off with 2 not 1 in case 1 doesn't fit > printnperlinealt :: MyOptions -> Int -> [(String, Int)] -> IO() > printnperlinealt opts n xs > = if too_wide (screen_width opts + 2) 0 lists > then reallyprint opts (findmaxlengths lists') lists' > else if n == length xs > then reallyprint opts (findmaxlengths lists) lists > else printnperlinealt opts (n + 1) xs > where lists = groupalt n xs > lists' = groupalt (n-1) xs PrettyPrint> groupalt 3 [1,2,3,4,5,6,7,8,9,10] [[1,2,3],[4,5,6],[7,8,9],[10]] > groupalt :: Int -> [a] -> [[a]] > {-# SPECIALIZE groupalt :: Int -> [(String, Int)] -> [[(String, Int)]] #-} > groupalt _ [] = [] > groupalt n xs = this:(groupalt n rest) > where (this, rest) = splitAt n xs ===== Print the files in a comma seperated list, as many as possible on each line > print_comma_list :: MyOptions -> [(String, Int)] -> Int -> IO() > print_comma_list _ [] _ = putStr "" > print_comma_list opts ((s, l):xs) sofar > = if sofar + l + 2 > sw > then putStr "\n" >> this >> rest l > else this >> rest (sofar + l) > where sw = screen_width opts > this = putStr s >> putStr ", " > rest n = print_comma_list opts xs (n + 2) ===== Given the width of the screen, the amount of space used up so far and a list of list of text,length pairs, with each list being a row, tells you if the text is too wide or not > too_wide :: Int -> Int -> [[(String, Int)]] -> Bool > too_wide _ _ ([]:_) = False > too_wide sw sofar xss = if now > sw then True > else too_wide sw now $ map tailp xss > where now = 2 + sofar + (foldr1 max $ map (snd.headp) xss) > headp [] = ("", 0) > headp (x:_) = x > tailp [] = [] > tailp (_:xs) = xs findmaxlengths: Find the maximum lengths plus 2 of a list of string/ints. Examples: PrettyPrint> findmaxlengths [[("1",1), ("22",2), ("55555",5)], [("333",3), ("22",2), ("4444",4)]] [5,4,7] PrettyPrint> findmaxlengths [[("1",1), ("22",2), ("55555",5)], [("333",3), ("22",2)]] [5,4,7] = [3+2,2+2,5+2] > findmaxlengths :: (Num b, Ord b) => [[(a, b)]] -> [b] > {-# SPECIALIZE findmaxlengths :: [[(String, Int)]] -> [Int] #-} > {-# INLINE findmaxlengths #-} > findmaxlengths xs = foldr1 maxlist $ (map.map) snd xs maxlist: Given two lists a and b (length a >= length b) return a list c (length c = length a) whose value in position n is the maximum of the corresponding values in a and b (or just a if n > length b). Examples: Main> maxlist [1,8,3] [6,2,3] [6,8,3] Main> maxlist [1,8,3] [6,2] [6,8,3] > maxlist :: (Ord a) => [a] -> [a] -> [a] > {-# SPECIALIZE maxlist :: [Int] -> [Int] -> [Int] #-} > maxlist [] ys = ys > maxlist xs [] = xs > maxlist (x:xs) (y:ys) = (max x y):(maxlist xs ys) [] ys can't happen - should fail reallyprint: Simple frontend to reallyprintline to print a list of lines instead of just the one. > reallyprint :: MyOptions -> [Int] -> [[(String, Int)]] -> IO() > reallyprint _ _ [] = putStr "" > reallyprint opts lengths xs > = foldr1 (>>) (map (reallyprintline t real_ls) xs) > where real_ls = (map ((+) 2) $ init lengths) ++ [0] > t = tabstop opts Actually print a line > reallyprintline :: Int -> [Int] -> [(String, Int)] -> IO() > reallyprintline t ls xs = (snd $ foldl (tabs_spaces t) (0, putStr "") $ zip xs ls) > >> putStr "\n" Print out any necessary tabs and spaces along with the text > tabs_spaces :: Int -> (Int, IO()) -> ((String, Int), Int) -> (Int, IO()) > tabs_spaces t (dist_so_far, io) ((x, len), col_len) = (dist_so_far + col_len, io') > where io' = io >> (putStr x) >> (putStr tabs) >> (putStr spaces) > dist1 = dist_so_far + len > ntabs = (div (dist_so_far + col_len) t) - (div dist1 t) > tabs = if col_len == 0 then "" else replicate ntabs '\t' > dist2 = if ntabs == 0 then dist1 > else t * ((div dist1 t) + ntabs) > nspaces = dist_so_far + col_len - dist2 > spaces = if col_len == 0 then "" else replicate nspaces ' '