{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TupleSections #-}

module Matterhorn.Draw.PostListWindow where

import           Prelude ()
import           Matterhorn.Prelude

import           Brick
import           Brick.Widgets.Border
import           Brick.Widgets.Center
import           Control.Monad.Trans.Reader ( withReaderT )
import qualified Data.Text as T
import           Lens.Micro.Platform ( (%~), to )

import           Network.Mattermost.Lenses
import           Network.Mattermost.Types

import           Matterhorn.Draw.Messages
import           Matterhorn.Draw.Util
import           Matterhorn.Themes
import           Matterhorn.Types


hLimitWithPadding :: Int -> Widget n -> Widget n
hLimitWithPadding :: Int -> Widget n -> Widget n
hLimitWithPadding Int
pad Widget n
contents = Widget :: forall n. Size -> Size -> RenderM n (Result n) -> Widget n
Widget
  { hSize :: Size
hSize  = Size
Fixed
  , vSize :: Size
vSize  = (Widget n -> Size
forall n. Widget n -> Size
vSize Widget n
contents)
  , render :: RenderM n (Result n)
render =
      (Context n -> Context n)
-> RenderM n (Result n) -> RenderM n (Result n)
forall r' r (m :: * -> *) a.
(r' -> r) -> ReaderT r m a -> ReaderT r' m a
withReaderT (Context n -> (Context n -> Context n) -> Context n
forall a b. a -> (a -> b) -> b
& (Int -> Identity Int) -> Context n -> Identity (Context n)
forall n. Lens' (Context n) Int
availWidthL  ((Int -> Identity Int) -> Context n -> Identity (Context n))
-> (Int -> Int) -> Context n -> Context n
forall s t a b. ASetter s t a b -> (a -> b) -> s -> t
%~ (\ Int
n -> Int
n Int -> Int -> Int
forall a. Num a => a -> a -> a
- (Int
2 Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
pad))) (RenderM n (Result n) -> RenderM n (Result n))
-> RenderM n (Result n) -> RenderM n (Result n)
forall a b. (a -> b) -> a -> b
$ Widget n -> RenderM n (Result n)
forall n. Widget n -> RenderM n (Result n)
render (Widget n -> RenderM n (Result n))
-> Widget n -> RenderM n (Result n)
forall a b. (a -> b) -> a -> b
$ Widget n -> Widget n
forall n. Widget n -> Widget n
cropToContext Widget n
contents
  }

drawPostListWindow :: PostListContents -> ChatState -> TeamId -> Widget Name
drawPostListWindow :: PostListContents -> ChatState -> TeamId -> Widget Name
drawPostListWindow PostListContents
contents ChatState
st TeamId
tId = Widget Name -> Widget Name
forall n. Widget n -> Widget n
joinBorders (Widget Name -> Widget Name) -> Widget Name -> Widget Name
forall a b. (a -> b) -> a -> b
$ PostListContents -> ChatState -> TeamId -> Widget Name
drawPostsBox PostListContents
contents ChatState
st TeamId
tId

-- | Draw a PostListWindow as a floating window on top of whatever
-- is rendered beneath it
drawPostsBox :: PostListContents -> ChatState -> TeamId -> Widget Name
drawPostsBox :: PostListContents -> ChatState -> TeamId -> Widget Name
drawPostsBox PostListContents
contents ChatState
st TeamId
tId =
  Widget Name -> Widget Name
forall n. Widget n -> Widget n
centerLayer (Widget Name -> Widget Name) -> Widget Name -> Widget Name
forall a b. (a -> b) -> a -> b
$ Int -> Widget Name -> Widget Name
forall n. Int -> Widget n -> Widget n
hLimitWithPadding Int
10 (Widget Name -> Widget Name) -> Widget Name -> Widget Name
forall a b. (a -> b) -> a -> b
$ Widget Name -> Widget Name -> Widget Name
forall n. Widget n -> Widget n -> Widget n
borderWithLabel Widget Name
forall n. Widget n
contentHeader (Widget Name -> Widget Name) -> Widget Name -> Widget Name
forall a b. (a -> b) -> a -> b
$
    Padding -> Widget Name -> Widget Name
forall n. Padding -> Widget n -> Widget n
padRight (Int -> Padding
Pad Int
1) Widget Name
messageListContents
  where -- The 'window title' of the window
        hs :: HighlightSet
hs = ChatState -> TeamId -> HighlightSet
getHighlightSet ChatState
st TeamId
tId
        contentHeader :: Widget n
contentHeader = AttrName -> Widget n -> Widget n
forall n. AttrName -> Widget n -> Widget n
withAttr AttrName
channelListHeaderAttr (Widget n -> Widget n) -> Widget n -> Widget n
forall a b. (a -> b) -> a -> b
$ Text -> Widget n
forall n. Text -> Widget n
txt (Text -> Widget n) -> Text -> Widget n
forall a b. (a -> b) -> a -> b
$ case PostListContents
contents of
          PostListContents
PostListFlagged -> Text
"Flagged posts"
          PostListPinned ChannelId
cId ->
              let cName :: Text
cName = case ChannelId -> ClientChannels -> Maybe ClientChannel
findChannelById ChannelId
cId (ChatState
stChatState
-> Getting ClientChannels ChatState ClientChannels
-> ClientChannels
forall s a. s -> Getting a s a -> a
^.Getting ClientChannels ChatState ClientChannels
Lens' ChatState ClientChannels
csChannels) of
                      Maybe ClientChannel
Nothing -> Text
"<UNKNOWN>"
                      Just ClientChannel
cc -> ChatState -> ChannelInfo -> Text
mkChannelName ChatState
st (ClientChannel
ccClientChannel
-> Getting ChannelInfo ClientChannel ChannelInfo -> ChannelInfo
forall s a. s -> Getting a s a -> a
^.Getting ChannelInfo ClientChannel ChannelInfo
Lens' ClientChannel ChannelInfo
ccInfo)
              in Text
"Posts pinned in " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
cName
          PostListSearch Text
terms Bool
searching -> Text
"Search results" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> if Bool
searching
            then Text
": " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
terms
            else Text
" (" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> (String -> Text
T.pack (String -> Text)
-> (DirectionalSeq Chronological Message -> String)
-> DirectionalSeq Chronological Message
-> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> String
forall a. Show a => a -> String
show (Int -> String)
-> (DirectionalSeq Chronological Message -> Int)
-> DirectionalSeq Chronological Message
-> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. DirectionalSeq Chronological Message -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length) DirectionalSeq Chronological Message
entries Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"): " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
terms

        entries :: DirectionalSeq Chronological Message
entries = (Message -> Bool)
-> DirectionalSeq Chronological Message
-> DirectionalSeq Chronological Message
forall seq a.
SeqDirection seq =>
(a -> Bool) -> DirectionalSeq seq a -> DirectionalSeq seq a
filterMessages Message -> Bool
knownChannel (DirectionalSeq Chronological Message
 -> DirectionalSeq Chronological Message)
-> DirectionalSeq Chronological Message
-> DirectionalSeq Chronological Message
forall a b. (a -> b) -> a -> b
$ ChatState
stChatState
-> Getting
     (DirectionalSeq Chronological Message)
     ChatState
     (DirectionalSeq Chronological Message)
-> DirectionalSeq Chronological Message
forall s a. s -> Getting a s a -> a
^.TeamId -> Lens' ChatState TeamState
csTeam(TeamId
tId)((TeamState
  -> Const (DirectionalSeq Chronological Message) TeamState)
 -> ChatState
 -> Const (DirectionalSeq Chronological Message) ChatState)
-> ((DirectionalSeq Chronological Message
     -> Const
          (DirectionalSeq Chronological Message)
          (DirectionalSeq Chronological Message))
    -> TeamState
    -> Const (DirectionalSeq Chronological Message) TeamState)
-> Getting
     (DirectionalSeq Chronological Message)
     ChatState
     (DirectionalSeq Chronological Message)
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(PostListWindowState
 -> Const
      (DirectionalSeq Chronological Message) PostListWindowState)
-> TeamState
-> Const (DirectionalSeq Chronological Message) TeamState
Lens' TeamState PostListWindowState
tsPostListWindow((PostListWindowState
  -> Const
       (DirectionalSeq Chronological Message) PostListWindowState)
 -> TeamState
 -> Const (DirectionalSeq Chronological Message) TeamState)
-> ((DirectionalSeq Chronological Message
     -> Const
          (DirectionalSeq Chronological Message)
          (DirectionalSeq Chronological Message))
    -> PostListWindowState
    -> Const
         (DirectionalSeq Chronological Message) PostListWindowState)
-> (DirectionalSeq Chronological Message
    -> Const
         (DirectionalSeq Chronological Message)
         (DirectionalSeq Chronological Message))
-> TeamState
-> Const (DirectionalSeq Chronological Message) TeamState
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(DirectionalSeq Chronological Message
 -> Const
      (DirectionalSeq Chronological Message)
      (DirectionalSeq Chronological Message))
-> PostListWindowState
-> Const (DirectionalSeq Chronological Message) PostListWindowState
Lens' PostListWindowState (DirectionalSeq Chronological Message)
postListPosts
        messages :: DirectionalSeq Chronological Message
messages = DirectionalSeq Chronological Message
-> Text -> TimeZoneSeries -> DirectionalSeq Chronological Message
insertDateMarkers
                     DirectionalSeq Chronological Message
entries
                     (ChatState -> Text
getDateFormat ChatState
st)
                     (ChatState
stChatState
-> Getting TimeZoneSeries ChatState TimeZoneSeries
-> TimeZoneSeries
forall s a. s -> Getting a s a -> a
^.Getting TimeZoneSeries ChatState TimeZoneSeries
Lens' ChatState TimeZoneSeries
timeZone)

        knownChannel :: Message -> Bool
knownChannel Message
msg =
            case Message
msgMessage
-> Getting (Maybe ChannelId) Message (Maybe ChannelId)
-> Maybe ChannelId
forall s a. s -> Getting a s a -> a
^.Getting (Maybe ChannelId) Message (Maybe ChannelId)
Lens' Message (Maybe ChannelId)
mChannelId of
                Just ChannelId
cId | Maybe ClientChannel
Nothing <- ChatState
stChatState
-> Getting (First ClientChannel) ChatState ClientChannel
-> Maybe ClientChannel
forall s a. s -> Getting (First a) s a -> Maybe a
^?(ClientChannels -> Const (First ClientChannel) ClientChannels)
-> ChatState -> Const (First ClientChannel) ChatState
Lens' ChatState ClientChannels
csChannels((ClientChannels -> Const (First ClientChannel) ClientChannels)
 -> ChatState -> Const (First ClientChannel) ChatState)
-> ((ClientChannel -> Const (First ClientChannel) ClientChannel)
    -> ClientChannels -> Const (First ClientChannel) ClientChannels)
-> Getting (First ClientChannel) ChatState ClientChannel
forall b c a. (b -> c) -> (a -> b) -> a -> c
.ChannelId -> Traversal' ClientChannels ClientChannel
channelByIdL(ChannelId
cId) -> Bool
False
                Maybe ChannelId
_ -> Bool
True

        -- The overall contents, with a sensible default even if there
        -- are no messages
        messageListContents :: Widget Name
messageListContents
          | DirectionalSeq Chronological Message -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null DirectionalSeq Chronological Message
messages =
            Int -> Widget Name -> Widget Name
forall n. Int -> Widget n -> Widget n
padTopBottom Int
1 (Widget Name -> Widget Name) -> Widget Name -> Widget Name
forall a b. (a -> b) -> a -> b
$
            Widget Name -> Widget Name
forall n. Widget n -> Widget n
hCenter (Widget Name -> Widget Name) -> Widget Name -> Widget Name
forall a b. (a -> b) -> a -> b
$
            AttrName -> Widget Name -> Widget Name
forall n. AttrName -> Widget n -> Widget n
withDefAttr AttrName
clientEmphAttr (Widget Name -> Widget Name) -> Widget Name -> Widget Name
forall a b. (a -> b) -> a -> b
$
            String -> Widget Name
forall n. String -> Widget n
str (String -> Widget Name) -> String -> Widget Name
forall a b. (a -> b) -> a -> b
$ case PostListContents
contents of
              PostListContents
PostListFlagged -> String
"You have no flagged messages."
              PostListPinned ChannelId
_ -> String
"This channel has no pinned messages."
              PostListSearch Text
_ Bool
searching ->
                if Bool
searching
                  then String
"Searching ..."
                  else String
"No search results found"
          | Bool
otherwise = [Widget Name] -> Widget Name
forall n. [Widget n] -> Widget n
vBox [Widget Name]
renderedMessageList

        -- The render-message function we're using
        renderMessageForWindow :: Message -> ThreadState -> Name -> Widget Name
renderMessageForWindow Message
msg ThreadState
tState Name
tag =
          let renderedMsg :: Widget Name
renderedMsg = ChatState
-> HighlightSet
-> Bool
-> Maybe ServerTime
-> Message
-> ThreadState
-> Name
-> Widget Name
renderSingleMessage ChatState
st HighlightSet
hs Bool
True Maybe ServerTime
forall a. Maybe a
Nothing Message
msg ThreadState
tState Name
tag
          in case Message
msgMessage -> Getting (Maybe Post) Message (Maybe Post) -> Maybe Post
forall s a. s -> Getting a s a -> a
^.Getting (Maybe Post) Message (Maybe Post)
Lens' Message (Maybe Post)
mOriginalPost of
            -- We should factor out some of the channel name logic at
            -- some point, but we can do that later
            Just Post
post
              | Just ClientChannel
chan <- ChatState
stChatState
-> Getting (First ClientChannel) ChatState ClientChannel
-> Maybe ClientChannel
forall s a. s -> Getting (First a) s a -> Maybe a
^?(ClientChannels -> Const (First ClientChannel) ClientChannels)
-> ChatState -> Const (First ClientChannel) ChatState
Lens' ChatState ClientChannels
csChannels((ClientChannels -> Const (First ClientChannel) ClientChannels)
 -> ChatState -> Const (First ClientChannel) ChatState)
-> ((ClientChannel -> Const (First ClientChannel) ClientChannel)
    -> ClientChannels -> Const (First ClientChannel) ClientChannels)
-> Getting (First ClientChannel) ChatState ClientChannel
forall b c a. (b -> c) -> (a -> b) -> a -> c
.ChannelId -> Traversal' ClientChannels ClientChannel
channelByIdL(Post
postPost -> Getting ChannelId Post ChannelId -> ChannelId
forall s a. s -> Getting a s a -> a
^.Getting ChannelId Post ChannelId
Lens' Post ChannelId
postChannelIdL) ->
                 case ClientChannel
chanClientChannel -> Getting Type ClientChannel Type -> Type
forall s a. s -> Getting a s a -> a
^.(ChannelInfo -> Const Type ChannelInfo)
-> ClientChannel -> Const Type ClientChannel
Lens' ClientChannel ChannelInfo
ccInfo((ChannelInfo -> Const Type ChannelInfo)
 -> ClientChannel -> Const Type ClientChannel)
-> ((Type -> Const Type Type)
    -> ChannelInfo -> Const Type ChannelInfo)
-> Getting Type ClientChannel Type
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(Type -> Const Type Type) -> ChannelInfo -> Const Type ChannelInfo
Lens' ChannelInfo Type
cdType of
                  Type
Direct
                    | Just UserInfo
u <- (UserId -> ChatState -> Maybe UserInfo)
-> ChatState -> UserId -> Maybe UserInfo
forall a b c. (a -> b -> c) -> b -> a -> c
flip UserId -> ChatState -> Maybe UserInfo
userById ChatState
st (UserId -> Maybe UserInfo) -> Maybe UserId -> Maybe UserInfo
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< ClientChannel
chanClientChannel
-> Getting (Maybe UserId) ClientChannel (Maybe UserId)
-> Maybe UserId
forall s a. s -> Getting a s a -> a
^.(ChannelInfo -> Const (Maybe UserId) ChannelInfo)
-> ClientChannel -> Const (Maybe UserId) ClientChannel
Lens' ClientChannel ChannelInfo
ccInfo((ChannelInfo -> Const (Maybe UserId) ChannelInfo)
 -> ClientChannel -> Const (Maybe UserId) ClientChannel)
-> ((Maybe UserId -> Const (Maybe UserId) (Maybe UserId))
    -> ChannelInfo -> Const (Maybe UserId) ChannelInfo)
-> Getting (Maybe UserId) ClientChannel (Maybe UserId)
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(Maybe UserId -> Const (Maybe UserId) (Maybe UserId))
-> ChannelInfo -> Const (Maybe UserId) ChannelInfo
Lens' ChannelInfo (Maybe UserId)
cdDMUserId ->
                        (AttrName -> Widget Name -> Widget Name
forall n. AttrName -> Widget n -> Widget n
forceAttr AttrName
channelNameAttr (Text -> Widget Name
forall n. Text -> Widget n
txt (Text -> Text
addUserSigil (Text -> Text) -> Text -> Text
forall a b. (a -> b) -> a -> b
$ UserInfo
uUserInfo -> Getting Text UserInfo Text -> Text
forall s a. s -> Getting a s a -> a
^.Getting Text UserInfo Text
Lens' UserInfo Text
uiName)) Widget Name -> Widget Name -> Widget Name
forall n. Widget n -> Widget n -> Widget n
<=>
                          (String -> Widget Name
forall n. String -> Widget n
str String
"  " Widget Name -> Widget Name -> Widget Name
forall n. Widget n -> Widget n -> Widget n
<+> Widget Name
renderedMsg))
                  Type
_ -> (AttrName -> Widget Name -> Widget Name
forall n. AttrName -> Widget n -> Widget n
forceAttr AttrName
channelNameAttr (Text -> Widget Name
forall n. Text -> Widget n
txt (ClientChannel
chanClientChannel -> Getting Text ClientChannel Text -> Text
forall s a. s -> Getting a s a -> a
^.(ChannelInfo -> Const Text ChannelInfo)
-> ClientChannel -> Const Text ClientChannel
Lens' ClientChannel ChannelInfo
ccInfo((ChannelInfo -> Const Text ChannelInfo)
 -> ClientChannel -> Const Text ClientChannel)
-> ((Text -> Const Text Text)
    -> ChannelInfo -> Const Text ChannelInfo)
-> Getting Text ClientChannel Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(ChannelInfo -> Text) -> SimpleGetter ChannelInfo Text
forall s a. (s -> a) -> SimpleGetter s a
to (ChatState -> ChannelInfo -> Text
mkChannelName ChatState
st))) Widget Name -> Widget Name -> Widget Name
forall n. Widget n -> Widget n -> Widget n
<=>
                         (String -> Widget Name
forall n. String -> Widget n
str String
"  " Widget Name -> Widget Name -> Widget Name
forall n. Widget n -> Widget n -> Widget n
<+> Widget Name
renderedMsg))
            Maybe Post
_ | CP ClientPostType
_ <- Message
msgMessage -> Getting MessageType Message MessageType -> MessageType
forall s a. s -> Getting a s a -> a
^.Getting MessageType Message MessageType
Lens' Message MessageType
mType -> String -> Widget Name
forall n. String -> Widget n
str String
"[BUG: unknown channel]"
              | Bool
otherwise -> Widget Name
renderedMsg

        -- The full message list, rendered with the current selection
        renderedMessageList :: [Widget Name]
renderedMessageList =
          let (Maybe (Message, ThreadState)
s, (DirectionalSeq Retrograde (Message, ThreadState)
before, DirectionalSeq Chronological (Message, ThreadState)
after)) = ((Message, ThreadState) -> Bool)
-> DirectionalSeq Chronological (Message, ThreadState)
-> (Maybe (Message, ThreadState),
    (DirectionalSeq
       (ReverseDirection Chronological) (Message, ThreadState),
     DirectionalSeq Chronological (Message, ThreadState)))
forall d a.
SeqDirection d =>
(a -> Bool)
-> DirectionalSeq d a
-> (Maybe a,
    (DirectionalSeq (ReverseDirection d) a, DirectionalSeq d a))
splitDirSeqOn (Message, ThreadState) -> Bool
forall b. (Message, b) -> Bool
matchesMessage DirectionalSeq Chronological (Message, ThreadState)
messagesWithStates
              matchesMessage :: (Message, b) -> Bool
matchesMessage (Message
m, b
_) = Message
mMessage
-> Getting (Maybe MessageId) Message (Maybe MessageId)
-> Maybe MessageId
forall s a. s -> Getting a s a -> a
^.Getting (Maybe MessageId) Message (Maybe MessageId)
Lens' Message (Maybe MessageId)
mMessageId Maybe MessageId -> Maybe MessageId -> Bool
forall a. Eq a => a -> a -> Bool
== (PostId -> MessageId
MessagePostId (PostId -> MessageId) -> Maybe PostId -> Maybe MessageId
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ChatState
stChatState
-> Getting (Maybe PostId) ChatState (Maybe PostId) -> Maybe PostId
forall s a. s -> Getting a s a -> a
^.TeamId -> Lens' ChatState TeamState
csTeam(TeamId
tId)((TeamState -> Const (Maybe PostId) TeamState)
 -> ChatState -> Const (Maybe PostId) ChatState)
-> ((Maybe PostId -> Const (Maybe PostId) (Maybe PostId))
    -> TeamState -> Const (Maybe PostId) TeamState)
-> Getting (Maybe PostId) ChatState (Maybe PostId)
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(PostListWindowState -> Const (Maybe PostId) PostListWindowState)
-> TeamState -> Const (Maybe PostId) TeamState
Lens' TeamState PostListWindowState
tsPostListWindow((PostListWindowState -> Const (Maybe PostId) PostListWindowState)
 -> TeamState -> Const (Maybe PostId) TeamState)
-> ((Maybe PostId -> Const (Maybe PostId) (Maybe PostId))
    -> PostListWindowState -> Const (Maybe PostId) PostListWindowState)
-> (Maybe PostId -> Const (Maybe PostId) (Maybe PostId))
-> TeamState
-> Const (Maybe PostId) TeamState
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(Maybe PostId -> Const (Maybe PostId) (Maybe PostId))
-> PostListWindowState -> Const (Maybe PostId) PostListWindowState
Lens' PostListWindowState (Maybe PostId)
postListSelected)
              messagesWithStates :: DirectionalSeq Chronological (Message, ThreadState)
messagesWithStates = (, ThreadState
InThreadShowParent) (Message -> (Message, ThreadState))
-> DirectionalSeq Chronological Message
-> DirectionalSeq Chronological (Message, ThreadState)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> DirectionalSeq Chronological Message
messages
              tag :: Name
tag = Name
PostList
          in case Maybe (Message, ThreadState)
s of
            Maybe (Message, ThreadState)
Nothing ->
                ((Message, ThreadState) -> Widget Name)
-> [(Message, ThreadState)] -> [Widget Name]
forall a b. (a -> b) -> [a] -> [b]
map (\(Message
m, ThreadState
tst) -> Message -> ThreadState -> Name -> Widget Name
renderMessageForWindow Message
m ThreadState
tst Name
tag) (DirectionalSeq Chronological (Message, ThreadState)
-> [(Message, ThreadState)]
forall (t :: * -> *) a. Foldable t => t a -> [a]
toList DirectionalSeq Chronological (Message, ThreadState)
messagesWithStates)
            Just (Message, ThreadState)
curMsg ->
              [((Message, ThreadState),
 (DirectionalSeq Retrograde (Message, ThreadState),
  DirectionalSeq Chronological (Message, ThreadState)))
-> (Message -> ThreadState -> Name -> Widget Name)
-> Name
-> Widget Name
forall dir1 dir2.
(SeqDirection dir1, SeqDirection dir2) =>
((Message, ThreadState),
 (DirectionalSeq dir1 (Message, ThreadState),
  DirectionalSeq dir2 (Message, ThreadState)))
-> (Message -> ThreadState -> Name -> Widget Name)
-> Name
-> Widget Name
unsafeRenderMessageSelection ((Message, ThreadState)
curMsg, (DirectionalSeq Retrograde (Message, ThreadState)
before, DirectionalSeq Chronological (Message, ThreadState)
after)) Message -> ThreadState -> Name -> Widget Name
renderMessageForWindow Name
tag]