module Highlight
( highlightError
, highlight
, underline
, bold
, italic
, parenthesize
, strikethrough
, inverse
, getColor
) where
highlightError :: (Int, Int) -> (Int, Int) -> String -> String
highlightError :: (Int, Int) -> (Int, Int) -> String -> String
highlightError (Int
sLine, Int
sCol) (Int
eLine, Int
eCol) String
file =
let color :: String
color = String -> String
getColor String
"red"
in (Int, Int)
-> (Int, Int) -> String -> (String -> String) -> String -> String
highlight (Int
sLine, Int
sCol) (Int
eLine, Int
eCol) String
color String -> String
underline String
file
highlight :: (Int, Int) -> (Int, Int) -> String -> (String -> String) -> String -> String
highlight :: (Int, Int)
-> (Int, Int) -> String -> (String -> String) -> String -> String
highlight sPos :: (Int, Int)
sPos@(Int
sLine, Int
sCol) ePos :: (Int, Int)
ePos@(Int
eLine, Int
eCol) String
color String -> String
format String
file =
Bool -> String -> String -> String
forall a. Bool -> String -> a -> a
assert ((Int, Int) -> (Int, Int) -> Bool
isInBounds (Int, Int)
sPos (Int, Int)
ePos)
String
"Start position must be before or equal to end position" (String -> String) -> String -> String
forall a b. (a -> b) -> a -> b
$
let
linesList :: [String]
linesList = String -> [String]
lines String
file
numLen :: Int
numLen = String -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length (Int -> String
forall a. Show a => a -> String
show Int
eLine)
highlightLines :: [String] -> Int -> String
highlightLines :: [String] -> Int -> String
highlightLines [] Int
_ = String
""
highlightLines (String
line : [String]
rest) Int
num
| Int
num Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
sLine = [String] -> Int -> String
highlightLines [String]
rest (Int
num Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1)
| Int
num Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
eLine = String
""
| Bool
otherwise =
let
targetStartCol :: Int
targetStartCol = if Int
num Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
sLine then Int
sCol Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1 else Int
0
adjustedCol :: Int
adjustedCol = if Int
num Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
eLine then Int
eCol Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1 else String -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length String
line
targetEndCol :: Int
targetEndCol = Int -> Int -> Int
forall a. Ord a => a -> a -> a
min Int
adjustedCol (String -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length String
line)
reset :: String
reset = String -> String
getColor String
"reset"
(String
before, String
restLine) = Int -> String -> (String, String)
forall a. Int -> [a] -> ([a], [a])
splitAt Int
targetStartCol String
line
(String
target, String
after) = Int -> String -> (String, String)
forall a. Int -> [a] -> ([a], [a])
splitAt (Int
targetEndCol Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
targetStartCol) String
restLine
formattedTarget :: String
formattedTarget = String -> String
format String
target
numStr :: String
numStr = Int -> String -> String
pad Int
numLen (Int -> String
forall a. Show a => a -> String
show Int
num)
highlightedLine :: String
highlightedLine =
if String -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null String
target
then String
numStr String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" | " String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
before String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
after String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"\n"
else String
numStr String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" | " String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
before String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
color String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
formattedTarget String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
reset String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
after String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"\n"
in String
highlightedLine String -> String -> String
forall a. [a] -> [a] -> [a]
++ [String] -> Int -> String
highlightLines [String]
rest (Int
num Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1)
in [String] -> Int -> String
highlightLines [String]
linesList Int
1
pad :: Int
-> String
-> String
pad :: Int -> String -> String
pad Int
len String
txt = Int -> Char -> String
forall a. Int -> a -> [a]
replicate (Int -> Int -> Int
forall a. Ord a => a -> a -> a
max (Int
len Int -> Int -> Int
forall a. Num a => a -> a -> a
- String -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length String
txt) Int
0) Char
' ' String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
txt
isInBounds :: (Int, Int) -> (Int, Int) -> Bool
isInBounds :: (Int, Int) -> (Int, Int) -> Bool
isInBounds (Int
sLine, Int
sCol) (Int
eLine, Int
eCol) =
Int
sLine Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
eLine Bool -> Bool -> Bool
|| (Int
sLine Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
eLine Bool -> Bool -> Bool
&& Int
sCol Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
eCol)
assert :: Bool
-> String
-> a
-> a
assert :: forall a. Bool -> String -> a -> a
assert Bool
True String
_ a
x = a
x
assert Bool
False String
msg a
_ = String -> a
forall a. HasCallStack => String -> a
error String
msg
getColor :: String
-> String
getColor :: String -> String
getColor String
color = case String
color of
String
"red" -> String
"\x1b[31m"
String
"green" -> String
"\x1b[32m"
String
"yellow" -> String
"\x1b[33m"
String
"blue" -> String
"\x1b[34m"
String
"magenta" -> String
"\x1b[35m"
String
"cyan" -> String
"\x1b[36m"
String
"white" -> String
"\x1b[37m"
String
"reset" -> String
"\x1b[0m"
String
_ -> String
"\x1b[0m"
underline :: String
-> String
underline :: String -> String
underline String
text = String
"\x1b[4m" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
text String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"\x1b[24m"
bold :: String
-> String
bold :: String -> String
bold String
text = String
"\x1b[1m" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
text String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"\x1b[22m"
italic :: String
-> String
italic :: String -> String
italic String
text = String
"\x1b[3m" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
text String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"\x1b[23m"
parenthesize :: String
-> String
parenthesize :: String -> String
parenthesize String
text = String
"(" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
text String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
")"
strikethrough :: String
-> String
strikethrough :: String -> String
strikethrough String
text = String
"\x1b[9m" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
text String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"\x1b[29m"
inverse :: String
-> String
inverse :: String -> String
inverse String
text = String
"\x1b[7m" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
text String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"\x1b[27m"