{-# LANGUAGE OverloadedStrings #-}

module Cursor.Brick.Text where

import Brick.Types as Brick
import Brick.Widgets.Core as Brick
import Cursor.Text
import Data.Text (Text)
import qualified Data.Text as T

-- | Make a text cursor widget with a blink-y box.
--
-- This function does not wrap the given text.
--
-- Otherwise, because of the way indexes work, there would be rendering errors for text that crosses the side of the terminal.
selectedTextCursorWidget :: n -> TextCursor -> Widget n
selectedTextCursorWidget :: n -> TextCursor -> Widget n
selectedTextCursorWidget n
n TextCursor
tc =
  n -> Location -> Widget n -> Widget n
forall n. n -> Location -> Widget n -> Widget n
Brick.showCursor n
n ((Int, Int) -> Location
Brick.Location (TextCursor -> Int
textCursorIndex TextCursor
tc, Int
0)) (Widget n -> Widget n) -> Widget n -> Widget n
forall a b. (a -> b) -> a -> b
$
    TextCursor -> Widget n
forall n. TextCursor -> Widget n
textCursorWidget TextCursor
tc

-- | Make a text cursor widget without a blink-y box.
--
-- This function does not wrap the given text.
textCursorWidget :: TextCursor -> Widget n
textCursorWidget :: TextCursor -> Widget n
textCursorWidget TextCursor
tc =
  Text -> Widget n
forall n. Text -> Widget n
txt (Text -> Widget n) -> Text -> Widget n
forall a b. (a -> b) -> a -> b
$
    let t :: Text
t = Text -> Text
sanitiseText (Text -> Text) -> Text -> Text
forall a b. (a -> b) -> a -> b
$ TextCursor -> Text
rebuildTextCursor TextCursor
tc
     in if Text -> Bool
T.null Text
t
          then Text
" "
          else Text
t

-- | Draw an arbitrary Text, it will be sanitised.
textWidget :: Text -> Widget n
textWidget :: Text -> Widget n
textWidget = Text -> Widget n
forall n. Text -> Widget n
txt (Text -> Widget n) -> (Text -> Text) -> Text -> Widget n
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Text
nonNullLinesText (Text -> Text) -> (Text -> Text) -> Text -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Text
sanitiseText

-- | Draw an arbitrary Text (with wrapping), it will be sanitised.
textWidgetWrap :: Text -> Widget n
textWidgetWrap :: Text -> Widget n
textWidgetWrap = Text -> Widget n
forall n. Text -> Widget n
txtWrap (Text -> Widget n) -> (Text -> Text) -> Text -> Widget n
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Text
nonNullLinesText (Text -> Text) -> (Text -> Text) -> Text -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Text
sanitiseText

-- | Draw an arbitrary single-line Text, it will be sanitised.
textLineWidget :: Text -> Widget n
textLineWidget :: Text -> Widget n
textLineWidget = Text -> Widget n
forall n. Text -> Widget n
txt (Text -> Widget n) -> (Text -> Text) -> Text -> Widget n
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Text
nonNullText (Text -> Text) -> (Text -> Text) -> Text -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Text
sanitiseText

-- | Draw an arbitrary single-line Text (with wrapping), it will be sanitised.
textLineWidgetWrap :: Text -> Widget n
textLineWidgetWrap :: Text -> Widget n
textLineWidgetWrap = Text -> Widget n
forall n. Text -> Widget n
txtWrap (Text -> Widget n) -> (Text -> Text) -> Text -> Widget n
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Text
nonNullText (Text -> Text) -> (Text -> Text) -> Text -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Text
sanitiseText

-- | Makes every line of a Text non-empty using `nonNullText`
nonNullLinesText :: Text -> Text
nonNullLinesText :: Text -> Text
nonNullLinesText = Text -> [Text] -> Text
T.intercalate Text
"\n" ([Text] -> Text) -> (Text -> [Text]) -> Text -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Text -> Text) -> [Text] -> [Text]
forall a b. (a -> b) -> [a] -> [b]
map Text -> Text
nonNullText ([Text] -> [Text]) -> (Text -> [Text]) -> Text -> [Text]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Text -> [Text]
T.splitOn Text
"\n"

-- | Makes a text non-empty.
--
-- This turns the empty text into " " and leaves other text as-is.
nonNullText :: Text -> Text
nonNullText :: Text -> Text
nonNullText Text
"" = Text
" "
nonNullText Text
t = Text
t

-- | Replace tabs by spaces so that brick doesn't render nonsense.
--
-- See https://hackage.haskell.org/package/brick/docs/Brick-Widgets-Core.html#v:txt
sanitiseText :: Text -> Text
sanitiseText :: Text -> Text
sanitiseText =
  (Char -> Char) -> Text -> Text
T.map ((Char -> Char) -> Text -> Text) -> (Char -> Char) -> Text -> Text
forall a b. (a -> b) -> a -> b
$ \Char
c ->
    case Char
c of
      Char
'\t' -> Char
' '
      Char
_ -> Char
c