{-# Language BangPatterns #-}
module Client.Image.Textbox
( textboxImage
) where
import Client.Configuration
import Client.Commands
import Client.Commands.Arguments.Renderer
import Client.Commands.Arguments.Parser
import Client.Commands.Interpolation
import Client.Commands.Recognizer
import Client.Image.Message
import Client.Image.MircFormatting
import Client.Image.PackedImage
import Client.Image.Palette
import Client.State
import Client.State.Focus
import qualified Client.State.EditBox as Edit
import Control.Lens
import qualified Data.HashSet as HashSet
import Data.HashSet (HashSet)
import Data.List
import qualified Data.Text as Text
import Graphics.Vty.Attributes
import qualified Graphics.Vty.Image as Vty
import Irc.Identifier
textboxImage :: Int -> ClientState -> (Int, Int, Vty.Image)
textboxImage width st
= (newPos, newOffset, croppedImage)
where
macros = views (clientConfig . configMacros) (fmap macroSpec) st
(txt, content) =
renderContent st myNick nicks macros pal
(view (clientTextBox . Edit.content) st)
lineImage = unpackImage (beginning <> content <> ending)
leftOfCurWidth = 1 + txt
croppedImage = Vty.resizeWidth width
$ Vty.cropLeft (Vty.imageWidth lineImage - newOffset) lineImage
cursorAnchor = width * 3 `quot` 4
oldOffset = view clientTextBoxOffset st
oldPos = leftOfCurWidth - oldOffset
newOffset
| 0 <= oldPos, oldPos < width = oldOffset
| otherwise = max 0 (leftOfCurWidth - cursorAnchor)
newPos = leftOfCurWidth - newOffset
pal = clientPalette st
attr = view palTextBox pal
beginning = char attr '^'
ending = char attr '$'
(myNick,nicks) =
case view clientFocus st of
ChannelFocus network channel ->
(clientHighlightsNetwork network st,
HashSet.fromList (channelUserList network channel st)
)
_ -> (HashSet.empty, HashSet.empty)
renderContent ::
ClientState ->
HashSet Identifier ->
HashSet Identifier ->
Recognizer MacroSpec ->
Palette ->
Edit.Content ->
(Int, Image')
renderContent st myNick nicks macros pal c = (leftLen, wholeImg)
where
as = reverse (view Edit.above c)
bs = view Edit.below c
cur = view Edit.line c
curTxt = view Edit.text cur
leftCur = take (view Edit.pos cur) (view Edit.text cur)
leftLen = length leftImgs
+ sum (map imageWidth leftImgs)
+ imageWidth (parseIrcText' True (Text.pack leftCur))
rndr = renderLine st pal myNick nicks macros
leftImgs = map (rndr False) as
wholeImg = mconcat
$ intersperse (plainText "\n")
$ leftImgs
++ rndr True curTxt
: map (rndr False) bs
renderLine ::
ClientState ->
Palette ->
HashSet Identifier ->
HashSet Identifier ->
Recognizer MacroSpec ->
Bool ->
String ->
Image'
renderLine st pal myNick nicks macros focused input =
case span (' '==) input of
(spcs, '/':xs) -> string defAttr spcs <> char defAttr '/'
<> string attr cleanCmd <> continue rest
where
specAttr spec =
case parse st spec rest of
Nothing -> view palCommand pal
Just{} -> view palCommandReady pal
(cmd, rest) = break (' '==) xs
cleanCmd = map cleanChar cmd
allCommands = (Left <$> macros) <> (Right <$> commands)
(attr, continue)
= case recognize (Text.pack cmd) allCommands of
Exact (Right Command{cmdArgumentSpec = spec}) ->
( specAttr spec
, render pal st focused spec
)
Exact (Left (MacroSpec spec)) ->
( specAttr spec
, render pal st focused spec
)
Prefix _ ->
( view palCommandPrefix pal
, parseIrcTextWithNicks pal myNick nicks focused . Text.pack
)
Invalid ->
( view palCommandError pal
, parseIrcTextWithNicks pal myNick nicks focused . Text.pack
)
_ -> parseIrcTextWithNicks pal myNick nicks focused (Text.pack input)