module Ghcitui.Util
    ( showT
    , splitBy
    , linesToText
    , clamp
    , getNumDigits
    , formatDigits
    , dropMiddleToFitText
    , revealNewlines
    ) where

import Data.Text (Text, breakOn, drop, length, pack, replace, take, takeEnd)
import Prelude hiding (drop, length, take)

-- | Split text based on a delimiter.
splitBy
    :: Text
    -- ^ Delimeter.
    -> Text
    -- ^ Text to split on.
    -> [Text]
splitBy :: Text -> Text -> [Text]
splitBy Text
"" Text
source = [Text
source]
splitBy Text
delim Text
source =
    case HasCallStack => Text -> Text -> (Text, Text)
Text -> Text -> (Text, Text)
breakOn Text
delim Text
source of
        (Text
l, Text
"") -> [Text
l]
        (Text
l, Text
r) -> Text
l Text -> [Text] -> [Text]
forall a. a -> [a] -> [a]
: Text -> Text -> [Text]
splitBy Text
delim (Int -> Text -> Text
drop (Text -> Int
length Text
delim) Text
r)

-- | Convert Strings to Text.
linesToText :: [String] -> Text
linesToText :: [String] -> Text
linesToText = String -> Text
pack (String -> Text) -> ([String] -> String) -> [String] -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [String] -> String
Prelude.unlines

-- | 'show' but to Text.
showT :: (Show a) => a -> Text
showT :: forall a. Show a => a -> Text
showT = String -> Text
pack (String -> Text) -> (a -> String) -> a -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> String
forall a. Show a => a -> String
show

-- | Return the number of digits in a given integral
getNumDigits :: (Integral a) => a -> Int
getNumDigits :: forall a. Integral a => a -> Int
getNumDigits a
0 = Int
1
getNumDigits a
num = Double -> Int
forall b. Integral b => Double -> b
forall a b. (RealFrac a, Integral b) => a -> b
truncate (Double -> Double -> Double
forall a. Floating a => a -> a -> a
logBase Double
10 (a -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral a
num) :: Double) Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1

-- | Format digits into a string with padding.
formatDigits
    :: Int
    -- ^ Number of spaces
    -> Int
    -- ^ Number to format digits of
    -> Text
    -- ^ Formatted Text
formatDigits :: Int -> Int -> Text
formatDigits Int
spacing Int
num = String -> Text
pack (Int -> Char -> String
forall a. Int -> a -> [a]
replicate Int
amount Char
' ') Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> String -> Text
pack (Int -> String
forall a. Show a => a -> String
show Int
num)
  where
    amount :: Int
amount = Int
spacing Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int -> Int
forall a. Integral a => a -> Int
getNumDigits Int
num

clamp
    :: (Ord a)
    => (a, a)
    -- ^ The minimum and maximum (inclusive).
    -> a
    -- ^ Value to clamp.
    -> a
    -- ^ Result.
clamp :: forall a. Ord a => (a, a) -> a -> a
clamp (a
mi, a
mx) a
v
    | a
v a -> a -> Bool
forall a. Ord a => a -> a -> Bool
< a
mi = a
mi
    | a
v a -> a -> Bool
forall a. Ord a => a -> a -> Bool
> a
mx = a
mx
    | Bool
otherwise = a
v

-- | Remove the inner characters of a Text to fit within a maximum width.
dropMiddleToFitText
    :: Int
    -- ^ Maximum length to trim to.
    -> Text
    -- ^ Text to shorten.
    -> Text
    -- ^ Result.
dropMiddleToFitText :: Int -> Text -> Text
dropMiddleToFitText Int
w Text
text
    | Text -> Int
length Text
text Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
w = Text
text
    | Bool
otherwise = Text
prefix Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"…" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
suffix
  where
    halfWidth :: Float
halfWidth = Int -> Float
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int
w Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1) Float -> Float -> Float
forall a. Fractional a => a -> a -> a
/ Float
2.0 :: Float
    prefix :: Text
prefix = Int -> Text -> Text
take (Float -> Int
forall b. Integral b => Float -> b
forall a b. (RealFrac a, Integral b) => a -> b
floor Float
halfWidth) Text
text
    suffix :: Text
suffix = Int -> Text -> Text
takeEnd (Float -> Int
forall b. Integral b => Float -> b
forall a b. (RealFrac a, Integral b) => a -> b
ceiling Float
halfWidth) Text
text

revealNewlines :: Text -> Text
revealNewlines :: Text -> Text
revealNewlines = HasCallStack => Text -> Text -> Text -> Text
Text -> Text -> Text -> Text
replace Text
"\n" Text
"↓"