aftovolio-0.7.0.0: Aftovolio/Halfsplit.hs
{-# LANGUAGE NoImplicitPrelude #-}
{-# OPTIONS_HADDOCK -show-extensions #-}
{- |
Module : Aftovolio.Halfsplit
Copyright : (c) OleksandrZhabenko 2023
License : MIT
Stability : Experimental
Maintainer : oleksandr.zhabenko@yahoo.com
-}
module Aftovolio.Halfsplit where
import Data.Char (isDigit)
import Data.List hiding (foldr)
import Data.Tuple (fst)
import GHC.Base
import GHC.Enum (fromEnum)
import GHC.Int (Int8)
import GHC.Num (abs, (+), (-))
import GHC.Real (quot, quotRem)
import System.IO (getLine, putStr, putStrLn)
import Text.Read (readMaybe)
import Data.Maybe (Maybe,fromMaybe)
import Text.Show (Show (..))
import Debug.Trace
-- | Converts the data that is an instance of 'Show' typeclass to be printed in two-column way.
halfsplit ::
(Show a, Eq b) =>
(a -> b) ->
-- | Whether to filter out all groups of \'={digits}\' from the lines.
Bool ->
Int8 ->
[a] ->
String
halfsplit g filtering = halfsplit1G g filtering ""
{-# INLINE halfsplit #-}
{- | Converts the data that is an instance of 'Show' typeclass to be printed in two-column way with
customizable ending of each line. Filters out all groups of \'={digits}\' from the lines.
-}
halfsplit1G ::
(Show a, Eq b) =>
(a -> b) ->
-- | Whether to filter out all groups of \'={digits}\' from the lines.
Bool ->
-- | Additional 'String' added to every line before the \"\\n\" character.
String ->
Int8 ->
[a] ->
String
halfsplit1G g filtering appendstr m xs
| null xs = []
| otherwise =
let (n, rr2) = quotRem (fromEnum m) (if m < 0 then -10 else 10)
r =
case abs rr2 of
1 ->
let us = reverse ts
in ((if rrr == 0 then id else (replicate l0 ' ' :)) $ map show ys, map show us)
2 -> (reverse y10s, t10s)
3 -> (y10s, reverse t10s)
4 -> (reverse y20s, t20s)
5 -> (y20s, reverse t20s)
_ ->
let us = reverse ys
in ((if rrr == 0 then id else (replicate l0 ' ' :)) $ map show us, map show ts)
in (if filtering then removeChangesOfDurations else id) $
((\(rs, qs) -> mergePartsLine n (appendstr `mappend` "\n") rs qs) r)
`mappend` appendstr
where
(ys, ts) = splitAt l xs -- Is used for basic splitting
(l, rrr) = length xs `quotRem` 2 -- For basic splitting
l0 = length . show . head $ xs -- For all cases for a whitespace placeholder
rss = map (map show) . groupBy (\x y -> g x == g y) $ xs -- For basic groupping
(l2, r20) = (sum . map length $ rss) `quotRem` 2
(y100s, t10s) = splitAt l2 . concat $ rss
y10s
| r20 == 0 = y100s
| otherwise = replicate l0 ' ' : y100s
r1ss = intersperse [replicate l0 ' '] rss -- For groupping with empty lines
(l3, r30) = (sum . map length $ r1ss) `quotRem` 2
(y200s, t20s) = splitAt l3 . concat $ r1ss
y20s
| r30 == 0 = y200s
| otherwise = replicate l0 ' ' : y200s
-- | A generalized version of 'halfsplit3G' with the possibility to prepend and append strings to it. These 'String's are not filtered out for the groups of \'={digits}\' from the prepending and appending 'String's.
halfsplit2G ::
(Show a, Eq b) =>
(a -> b) ->
-- | Whether to filter out all groups of \'={digits}\' from the lines.
Bool ->
-- | Additional 'String' added to every line before the \"\\n\" character.
String ->
-- | A 'String' that is prepended to the 'halfsplit1G' result.
String ->
-- | A 'String' that is appended to the 'halfsplit1G' result.
String ->
Int8 ->
[a] ->
String
halfsplit2G g filtering appendstr prestr poststr m xs = prestr `mappend` halfsplit1G g filtering appendstr m xs `mappend` poststr
{-# INLINEABLE halfsplit2G #-}
-- | Filters out all groups of \'={digits}\' from the 'String'
removeChangesOfDurations :: String -> String
removeChangesOfDurations ('=' : xs) = removeChangesOfDurations (dropWhile isDigit xs)
removeChangesOfDurations (x : xs) = x : removeChangesOfDurations xs
removeChangesOfDurations _ = []
mergePartsLine :: Int -> String -> [String] -> [String] -> String
mergePartsLine n newlined xs ys =
intercalate newlined
. zipWith
(\x y -> x `mappend` (replicate n (if n < 0 then '\t' else ' ')) `mappend` y)
xs $
ys
splitGroups :: Int -> [[a]] -> ([[a]], [[a]], Int)
splitGroups l tss = foldr h ([], [], 0) tss
where
h js (rss, mss, k)
| k < l = (rss, js : mss, k + length js)
| otherwise = (js : rss, mss, k + length js)
showWithSpaces :: (Show a) => Int -> a -> String
showWithSpaces n x
| l < n = xs `mappend` replicate (n - l) ' '
| otherwise = xs
where
xs = show x
l = length xs
print23 :: Bool -> String -> String -> Int -> [String] -> IO ()
print23 filtering prestr poststr n xss = do
putStrLn prestr
let linez = zip xss [1 ..]
if n >= 2 && n <= l - 1
then do
let linez3 =
(\(x : y : t : xs) -> x : (' ' : y) : (' ' : ' ' : t) : xs)
. map fst
. filter (\(ts, m) -> m `elem` [n - 1 .. n + 1]) $
linez
mapM putSLn linez3 >> putStrLn poststr
else
( case n of
1 -> putStr " " >> mapM putSLn (take 2 xss)
m ->
if m == l
then mapM putSLn ((\(x : y : xs) -> x : (' ' : y) : xs) . drop (l - 2) $ xss)
else pure []
)
>> putStrLn poststr
where
l = length xss
putSLn = putStrLn . (if filtering then removeChangesOfDurations else id)
readNums :: [String] -> [Int]
readNums = concatMap readNs
where readNs :: String -> [Int]
readNs xs
| any (== '-') xs =
let (ys, ts) = break (== '-') xs
us = dropWhile (not . isDigit) ts
in [(fromMaybe 1 (readMaybe ys:: Maybe Int))..(fromMaybe 1 (readMaybe us:: Maybe Int))]
| otherwise = [fromMaybe 1 (readMaybe xs:: Maybe Int)]
{-# INLINE readNums #-}