{-# LANGUAGE MultiWayIf #-}
module Matterhorn.State.ChannelSelect
  ( beginChannelSelect
  , updateChannelSelectMatches
  , channelSelectNext
  , channelSelectPrevious
  )
where

import           Prelude ()
import           Matterhorn.Prelude

import           Brick.Widgets.Edit ( getEditContents )
import           Data.Char ( isUpper )
import qualified Data.Text as T
import           Lens.Micro.Platform

import qualified Network.Mattermost.Types as MM

import           Matterhorn.Constants ( userSigil, normalChannelSigil )
import           Matterhorn.Types
import qualified Matterhorn.Zipper as Z

beginChannelSelect :: MH ()
beginChannelSelect :: MH ()
beginChannelSelect = do
    Mode -> MH ()
setMode Mode
ChannelSelect
    TeamId
tId <- Getting TeamId ChatState TeamId -> MH TeamId
forall s (m :: * -> *) a. MonadState s m => Getting a s a -> m a
use Getting TeamId ChatState TeamId
SimpleGetter ChatState TeamId
csCurrentTeamId
    (TeamState -> Identity TeamState)
-> ChatState -> Identity ChatState
Lens' ChatState TeamState
csCurrentTeam((TeamState -> Identity TeamState)
 -> ChatState -> Identity ChatState)
-> ((ChannelSelectState -> Identity ChannelSelectState)
    -> TeamState -> Identity TeamState)
-> (ChannelSelectState -> Identity ChannelSelectState)
-> ChatState
-> Identity ChatState
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(ChannelSelectState -> Identity ChannelSelectState)
-> TeamState -> Identity TeamState
Lens' TeamState ChannelSelectState
tsChannelSelectState ((ChannelSelectState -> Identity ChannelSelectState)
 -> ChatState -> Identity ChatState)
-> ChannelSelectState -> MH ()
forall s (m :: * -> *) a b.
MonadState s m =>
ASetter s s a b -> b -> m ()
.= TeamId -> ChannelSelectState
emptyChannelSelectState TeamId
tId
    MH ()
updateChannelSelectMatches

    -- Preserve the current channel selection when initializing channel
    -- selection mode
    Zipper ChannelListGroup ChannelListEntry
zipper <- Getting
  (Zipper ChannelListGroup ChannelListEntry)
  ChatState
  (Zipper ChannelListGroup ChannelListEntry)
-> MH (Zipper ChannelListGroup ChannelListEntry)
forall s (m :: * -> *) a. MonadState s m => Getting a s a -> m a
use ((TeamState
 -> Const (Zipper ChannelListGroup ChannelListEntry) TeamState)
-> ChatState
-> Const (Zipper ChannelListGroup ChannelListEntry) ChatState
Lens' ChatState TeamState
csCurrentTeam((TeamState
  -> Const (Zipper ChannelListGroup ChannelListEntry) TeamState)
 -> ChatState
 -> Const (Zipper ChannelListGroup ChannelListEntry) ChatState)
-> ((Zipper ChannelListGroup ChannelListEntry
     -> Const
          (Zipper ChannelListGroup ChannelListEntry)
          (Zipper ChannelListGroup ChannelListEntry))
    -> TeamState
    -> Const (Zipper ChannelListGroup ChannelListEntry) TeamState)
-> Getting
     (Zipper ChannelListGroup ChannelListEntry)
     ChatState
     (Zipper ChannelListGroup ChannelListEntry)
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(Zipper ChannelListGroup ChannelListEntry
 -> Const
      (Zipper ChannelListGroup ChannelListEntry)
      (Zipper ChannelListGroup ChannelListEntry))
-> TeamState
-> Const (Zipper ChannelListGroup ChannelListEntry) TeamState
Lens' TeamState (Zipper ChannelListGroup ChannelListEntry)
tsFocus)
    let isCurrentFocus :: ChannelSelectMatch -> Bool
isCurrentFocus ChannelSelectMatch
m = ChannelListEntry -> Maybe ChannelListEntry
forall a. a -> Maybe a
Just (ChannelSelectMatch -> ChannelListEntry
matchEntry ChannelSelectMatch
m) Maybe ChannelListEntry -> Maybe ChannelListEntry -> Bool
forall a. Eq a => a -> a -> Bool
== Zipper ChannelListGroup ChannelListEntry -> Maybe ChannelListEntry
forall a b. Zipper a b -> Maybe b
Z.focus Zipper ChannelListGroup ChannelListEntry
zipper
    (TeamState -> Identity TeamState)
-> ChatState -> Identity ChatState
Lens' ChatState TeamState
csCurrentTeam((TeamState -> Identity TeamState)
 -> ChatState -> Identity ChatState)
-> ((Zipper ChannelListGroup ChannelSelectMatch
     -> Identity (Zipper ChannelListGroup ChannelSelectMatch))
    -> TeamState -> Identity TeamState)
-> (Zipper ChannelListGroup ChannelSelectMatch
    -> Identity (Zipper ChannelListGroup ChannelSelectMatch))
-> ChatState
-> Identity ChatState
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(ChannelSelectState -> Identity ChannelSelectState)
-> TeamState -> Identity TeamState
Lens' TeamState ChannelSelectState
tsChannelSelectState((ChannelSelectState -> Identity ChannelSelectState)
 -> TeamState -> Identity TeamState)
-> ((Zipper ChannelListGroup ChannelSelectMatch
     -> Identity (Zipper ChannelListGroup ChannelSelectMatch))
    -> ChannelSelectState -> Identity ChannelSelectState)
-> (Zipper ChannelListGroup ChannelSelectMatch
    -> Identity (Zipper ChannelListGroup ChannelSelectMatch))
-> TeamState
-> Identity TeamState
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(Zipper ChannelListGroup ChannelSelectMatch
 -> Identity (Zipper ChannelListGroup ChannelSelectMatch))
-> ChannelSelectState -> Identity ChannelSelectState
Lens'
  ChannelSelectState (Zipper ChannelListGroup ChannelSelectMatch)
channelSelectMatches ((Zipper ChannelListGroup ChannelSelectMatch
  -> Identity (Zipper ChannelListGroup ChannelSelectMatch))
 -> ChatState -> Identity ChatState)
-> (Zipper ChannelListGroup ChannelSelectMatch
    -> Zipper ChannelListGroup ChannelSelectMatch)
-> MH ()
forall s (m :: * -> *) a b.
MonadState s m =>
ASetter s s a b -> (a -> b) -> m ()
%= (ChannelSelectMatch -> Bool)
-> Zipper ChannelListGroup ChannelSelectMatch
-> Zipper ChannelListGroup ChannelSelectMatch
forall b a. (b -> Bool) -> Zipper a b -> Zipper a b
Z.findRight ChannelSelectMatch -> Bool
isCurrentFocus

-- Select the next match in channel selection mode.
channelSelectNext :: MH ()
channelSelectNext :: MH ()
channelSelectNext = (Zipper ChannelListGroup ChannelSelectMatch
 -> Zipper ChannelListGroup ChannelSelectMatch)
-> MH ()
updateSelectedMatch Zipper ChannelListGroup ChannelSelectMatch
-> Zipper ChannelListGroup ChannelSelectMatch
forall a b. Zipper a b -> Zipper a b
Z.right

-- Select the previous match in channel selection mode.
channelSelectPrevious :: MH ()
channelSelectPrevious :: MH ()
channelSelectPrevious = (Zipper ChannelListGroup ChannelSelectMatch
 -> Zipper ChannelListGroup ChannelSelectMatch)
-> MH ()
updateSelectedMatch Zipper ChannelListGroup ChannelSelectMatch
-> Zipper ChannelListGroup ChannelSelectMatch
forall a b. Zipper a b -> Zipper a b
Z.left

updateChannelSelectMatches :: MH ()
updateChannelSelectMatches :: MH ()
updateChannelSelectMatches = do
    ChatState
st <- Getting ChatState ChatState ChatState -> MH ChatState
forall s (m :: * -> *) a. MonadState s m => Getting a s a -> m a
use Getting ChatState ChatState ChatState
forall a. a -> a
id

    Editor Text Name
input <- Getting (Editor Text Name) ChatState (Editor Text Name)
-> MH (Editor Text Name)
forall s (m :: * -> *) a. MonadState s m => Getting a s a -> m a
use ((TeamState -> Const (Editor Text Name) TeamState)
-> ChatState -> Const (Editor Text Name) ChatState
Lens' ChatState TeamState
csCurrentTeam((TeamState -> Const (Editor Text Name) TeamState)
 -> ChatState -> Const (Editor Text Name) ChatState)
-> ((Editor Text Name
     -> Const (Editor Text Name) (Editor Text Name))
    -> TeamState -> Const (Editor Text Name) TeamState)
-> Getting (Editor Text Name) ChatState (Editor Text Name)
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(ChannelSelectState -> Const (Editor Text Name) ChannelSelectState)
-> TeamState -> Const (Editor Text Name) TeamState
Lens' TeamState ChannelSelectState
tsChannelSelectState((ChannelSelectState
  -> Const (Editor Text Name) ChannelSelectState)
 -> TeamState -> Const (Editor Text Name) TeamState)
-> ((Editor Text Name
     -> Const (Editor Text Name) (Editor Text Name))
    -> ChannelSelectState
    -> Const (Editor Text Name) ChannelSelectState)
-> (Editor Text Name
    -> Const (Editor Text Name) (Editor Text Name))
-> TeamState
-> Const (Editor Text Name) TeamState
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(Editor Text Name -> Const (Editor Text Name) (Editor Text Name))
-> ChannelSelectState
-> Const (Editor Text Name) ChannelSelectState
Lens' ChannelSelectState (Editor Text Name)
channelSelectInput)
    Maybe ClientConfig
cconfig <- Getting (Maybe ClientConfig) ChatState (Maybe ClientConfig)
-> MH (Maybe ClientConfig)
forall s (m :: * -> *) a. MonadState s m => Getting a s a -> m a
use Getting (Maybe ClientConfig) ChatState (Maybe ClientConfig)
Lens' ChatState (Maybe ClientConfig)
csClientConfig
    UserPreferences
prefs <- Getting UserPreferences ChatState UserPreferences
-> MH UserPreferences
forall s (m :: * -> *) a. MonadState s m => Getting a s a -> m a
use ((ChatResources -> Const UserPreferences ChatResources)
-> ChatState -> Const UserPreferences ChatState
Lens' ChatState ChatResources
csResources((ChatResources -> Const UserPreferences ChatResources)
 -> ChatState -> Const UserPreferences ChatState)
-> ((UserPreferences -> Const UserPreferences UserPreferences)
    -> ChatResources -> Const UserPreferences ChatResources)
-> Getting UserPreferences ChatState UserPreferences
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(UserPreferences -> Const UserPreferences UserPreferences)
-> ChatResources -> Const UserPreferences ChatResources
Lens' ChatResources UserPreferences
crUserPreferences)

    let pat :: Maybe ChannelSelectPattern
pat = Text -> Maybe ChannelSelectPattern
parseChannelSelectPattern (Text -> Maybe ChannelSelectPattern)
-> Text -> Maybe ChannelSelectPattern
forall a b. (a -> b) -> a -> b
$ [Text] -> Text
T.concat ([Text] -> Text) -> [Text] -> Text
forall a b. (a -> b) -> a -> b
$ Editor Text Name -> [Text]
forall t n. Monoid t => Editor t n -> [t]
getEditContents Editor Text Name
input
        chanNameMatches :: ChannelListEntry -> Text -> Maybe ChannelSelectMatch
chanNameMatches ChannelListEntry
e = case Maybe ChannelSelectPattern
pat of
            Maybe ChannelSelectPattern
Nothing -> Maybe ChannelSelectMatch -> Text -> Maybe ChannelSelectMatch
forall a b. a -> b -> a
const Maybe ChannelSelectMatch
forall a. Maybe a
Nothing
            Just ChannelSelectPattern
p -> ChannelSelectPattern
-> ChannelListEntry -> Text -> Maybe ChannelSelectMatch
applySelectPattern ChannelSelectPattern
p ChannelListEntry
e
        patTy :: Maybe MatchType
patTy = case Maybe ChannelSelectPattern
pat of
            Maybe ChannelSelectPattern
Nothing -> Maybe MatchType
forall a. Maybe a
Nothing
            Just ChannelSelectPattern
CSPAny -> Maybe MatchType
forall a. Maybe a
Nothing
            Just (CSP MatchType
ty Text
_) -> MatchType -> Maybe MatchType
forall a. a -> Maybe a
Just MatchType
ty

    let chanMatches :: ChannelListEntry -> ClientChannel -> Maybe ChannelSelectMatch
chanMatches ChannelListEntry
e ClientChannel
chan =
            if Maybe MatchType
patTy Maybe MatchType -> Maybe MatchType -> Bool
forall a. Eq a => a -> a -> Bool
== MatchType -> Maybe MatchType
forall a. a -> Maybe a
Just MatchType
PrefixDMOnly
            then Maybe ChannelSelectMatch
forall a. Maybe a
Nothing
            else if 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 Type -> Type -> Bool
forall a. Eq a => a -> a -> Bool
/= Type
MM.Group
                 then ChannelListEntry -> Text -> Maybe ChannelSelectMatch
chanNameMatches ChannelListEntry
e (Text -> Maybe ChannelSelectMatch)
-> Text -> Maybe ChannelSelectMatch
forall a b. (a -> b) -> a -> b
$ 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
.(Text -> Const Text Text) -> ChannelInfo -> Const Text ChannelInfo
Lens' ChannelInfo Text
cdDisplayName
                 else Maybe ChannelSelectMatch
forall a. Maybe a
Nothing
        groupChanMatches :: ChannelListEntry -> ClientChannel -> Maybe ChannelSelectMatch
groupChanMatches ChannelListEntry
e ClientChannel
chan =
            if Maybe MatchType
patTy Maybe MatchType -> Maybe MatchType -> Bool
forall a. Eq a => a -> a -> Bool
== MatchType -> Maybe MatchType
forall a. a -> Maybe a
Just MatchType
PrefixNonDMOnly
            then Maybe ChannelSelectMatch
forall a. Maybe a
Nothing
            else if 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 Type -> Type -> Bool
forall a. Eq a => a -> a -> Bool
== Type
MM.Group
                 then ChannelListEntry -> Text -> Maybe ChannelSelectMatch
chanNameMatches ChannelListEntry
e (Text -> Maybe ChannelSelectMatch)
-> Text -> Maybe ChannelSelectMatch
forall a b. (a -> b) -> a -> b
$ 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
.(Text -> Const Text Text) -> ChannelInfo -> Const Text ChannelInfo
Lens' ChannelInfo Text
cdDisplayName
                 else Maybe ChannelSelectMatch
forall a. Maybe a
Nothing
        displayName :: UserInfo -> Text
displayName UserInfo
uInfo = UserInfo -> Maybe ClientConfig -> UserPreferences -> Text
displayNameForUser UserInfo
uInfo Maybe ClientConfig
cconfig UserPreferences
prefs
        userMatches :: ChannelListEntry -> UserInfo -> Maybe ChannelSelectMatch
userMatches ChannelListEntry
e UserInfo
uInfo =
            if Maybe MatchType
patTy Maybe MatchType -> Maybe MatchType -> Bool
forall a. Eq a => a -> a -> Bool
== MatchType -> Maybe MatchType
forall a. a -> Maybe a
Just MatchType
PrefixNonDMOnly
            then Maybe ChannelSelectMatch
forall a. Maybe a
Nothing
            else (ChannelListEntry -> Text -> Maybe ChannelSelectMatch
chanNameMatches ChannelListEntry
e (Text -> Maybe ChannelSelectMatch)
-> (UserInfo -> Text) -> UserInfo -> Maybe ChannelSelectMatch
forall b c a. (b -> c) -> (a -> b) -> a -> c
. UserInfo -> Text
displayName) UserInfo
uInfo
        matches :: ChannelListEntry -> Maybe ChannelSelectMatch
matches ChannelListEntry
e =
            let cId :: ChannelId
cId = ChannelListEntry -> ChannelId
channelListEntryChannelId ChannelListEntry
e
            in case ChannelListEntry -> ChannelListEntryType
channelListEntryType ChannelListEntry
e of
                ChannelListEntryType
CLChannel    -> 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) Maybe ClientChannel
-> (ClientChannel -> Maybe ChannelSelectMatch)
-> Maybe ChannelSelectMatch
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= ChannelListEntry -> ClientChannel -> Maybe ChannelSelectMatch
chanMatches ChannelListEntry
e
                CLUserDM UserId
uId -> UserId -> ChatState -> Maybe UserInfo
userById UserId
uId ChatState
st Maybe UserInfo
-> (UserInfo -> Maybe ChannelSelectMatch)
-> Maybe ChannelSelectMatch
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= ChannelListEntry -> UserInfo -> Maybe ChannelSelectMatch
userMatches ChannelListEntry
e
                ChannelListEntryType
CLGroupDM    -> 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) Maybe ClientChannel
-> (ClientChannel -> Maybe ChannelSelectMatch)
-> Maybe ChannelSelectMatch
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= ChannelListEntry -> ClientChannel -> Maybe ChannelSelectMatch
groupChanMatches ChannelListEntry
e

        preserveFocus :: Maybe ChannelSelectMatch -> ChannelSelectMatch -> Bool
preserveFocus Maybe ChannelSelectMatch
Nothing ChannelSelectMatch
_ = Bool
False
        preserveFocus (Just ChannelSelectMatch
m) ChannelSelectMatch
m2 = ChannelSelectMatch -> ChannelListEntry
matchEntry ChannelSelectMatch
m ChannelListEntry -> ChannelListEntry -> Bool
forall a. Eq a => a -> a -> Bool
== ChannelSelectMatch -> ChannelListEntry
matchEntry ChannelSelectMatch
m2

    (TeamState -> Identity TeamState)
-> ChatState -> Identity ChatState
Lens' ChatState TeamState
csCurrentTeam((TeamState -> Identity TeamState)
 -> ChatState -> Identity ChatState)
-> ((Zipper ChannelListGroup ChannelSelectMatch
     -> Identity (Zipper ChannelListGroup ChannelSelectMatch))
    -> TeamState -> Identity TeamState)
-> (Zipper ChannelListGroup ChannelSelectMatch
    -> Identity (Zipper ChannelListGroup ChannelSelectMatch))
-> ChatState
-> Identity ChatState
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(ChannelSelectState -> Identity ChannelSelectState)
-> TeamState -> Identity TeamState
Lens' TeamState ChannelSelectState
tsChannelSelectState((ChannelSelectState -> Identity ChannelSelectState)
 -> TeamState -> Identity TeamState)
-> ((Zipper ChannelListGroup ChannelSelectMatch
     -> Identity (Zipper ChannelListGroup ChannelSelectMatch))
    -> ChannelSelectState -> Identity ChannelSelectState)
-> (Zipper ChannelListGroup ChannelSelectMatch
    -> Identity (Zipper ChannelListGroup ChannelSelectMatch))
-> TeamState
-> Identity TeamState
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(Zipper ChannelListGroup ChannelSelectMatch
 -> Identity (Zipper ChannelListGroup ChannelSelectMatch))
-> ChannelSelectState -> Identity ChannelSelectState
Lens'
  ChannelSelectState (Zipper ChannelListGroup ChannelSelectMatch)
channelSelectMatches ((Zipper ChannelListGroup ChannelSelectMatch
  -> Identity (Zipper ChannelListGroup ChannelSelectMatch))
 -> ChatState -> Identity ChatState)
-> (Zipper ChannelListGroup ChannelSelectMatch
    -> Zipper ChannelListGroup ChannelSelectMatch)
-> MH ()
forall s (m :: * -> *) a b.
MonadState s m =>
ASetter s s a b -> (a -> b) -> m ()
%=
        ((Maybe ChannelSelectMatch -> ChannelSelectMatch -> Bool)
-> [(ChannelListGroup, [ChannelSelectMatch])]
-> Zipper ChannelListGroup ChannelSelectMatch
-> Zipper ChannelListGroup ChannelSelectMatch
forall b a.
Eq b =>
(Maybe b -> b -> Bool) -> [(a, [b])] -> Zipper a b -> Zipper a b
Z.updateListBy Maybe ChannelSelectMatch -> ChannelSelectMatch -> Bool
preserveFocus ([(ChannelListGroup, [ChannelSelectMatch])]
 -> Zipper ChannelListGroup ChannelSelectMatch
 -> Zipper ChannelListGroup ChannelSelectMatch)
-> [(ChannelListGroup, [ChannelSelectMatch])]
-> Zipper ChannelListGroup ChannelSelectMatch
-> Zipper ChannelListGroup ChannelSelectMatch
forall a b. (a -> b) -> a -> b
$ Zipper ChannelListGroup ChannelSelectMatch
-> [(ChannelListGroup, [ChannelSelectMatch])]
forall a b. Zipper a b -> [(a, [b])]
Z.toList (Zipper ChannelListGroup ChannelSelectMatch
 -> [(ChannelListGroup, [ChannelSelectMatch])])
-> Zipper ChannelListGroup ChannelSelectMatch
-> [(ChannelListGroup, [ChannelSelectMatch])]
forall a b. (a -> b) -> a -> b
$ (ChannelListEntry -> Maybe ChannelSelectMatch)
-> Zipper ChannelListGroup ChannelListEntry
-> Zipper ChannelListGroup ChannelSelectMatch
forall c b a. Eq c => (b -> Maybe c) -> Zipper a b -> Zipper a c
Z.maybeMapZipper ChannelListEntry -> Maybe ChannelSelectMatch
matches (ChatState
stChatState
-> Getting
     (Zipper ChannelListGroup ChannelListEntry)
     ChatState
     (Zipper ChannelListGroup ChannelListEntry)
-> Zipper ChannelListGroup ChannelListEntry
forall s a. s -> Getting a s a -> a
^.(TeamState
 -> Const (Zipper ChannelListGroup ChannelListEntry) TeamState)
-> ChatState
-> Const (Zipper ChannelListGroup ChannelListEntry) ChatState
Lens' ChatState TeamState
csCurrentTeam((TeamState
  -> Const (Zipper ChannelListGroup ChannelListEntry) TeamState)
 -> ChatState
 -> Const (Zipper ChannelListGroup ChannelListEntry) ChatState)
-> ((Zipper ChannelListGroup ChannelListEntry
     -> Const
          (Zipper ChannelListGroup ChannelListEntry)
          (Zipper ChannelListGroup ChannelListEntry))
    -> TeamState
    -> Const (Zipper ChannelListGroup ChannelListEntry) TeamState)
-> Getting
     (Zipper ChannelListGroup ChannelListEntry)
     ChatState
     (Zipper ChannelListGroup ChannelListEntry)
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(Zipper ChannelListGroup ChannelListEntry
 -> Const
      (Zipper ChannelListGroup ChannelListEntry)
      (Zipper ChannelListGroup ChannelListEntry))
-> TeamState
-> Const (Zipper ChannelListGroup ChannelListEntry) TeamState
Lens' TeamState (Zipper ChannelListGroup ChannelListEntry)
tsFocus))

applySelectPattern :: ChannelSelectPattern -> ChannelListEntry -> Text -> Maybe ChannelSelectMatch
applySelectPattern :: ChannelSelectPattern
-> ChannelListEntry -> Text -> Maybe ChannelSelectMatch
applySelectPattern ChannelSelectPattern
CSPAny ChannelListEntry
entry Text
chanName = do
    ChannelSelectMatch -> Maybe ChannelSelectMatch
forall (m :: * -> *) a. Monad m => a -> m a
return (ChannelSelectMatch -> Maybe ChannelSelectMatch)
-> ChannelSelectMatch -> Maybe ChannelSelectMatch
forall a b. (a -> b) -> a -> b
$ Text
-> Text -> Text -> Text -> ChannelListEntry -> ChannelSelectMatch
ChannelSelectMatch Text
"" Text
"" Text
chanName Text
chanName ChannelListEntry
entry
applySelectPattern (CSP MatchType
ty Text
pat) ChannelListEntry
entry Text
chanName = do
    let applyType :: MatchType -> Maybe (Text, Text, Text)
applyType MatchType
Infix | Text
pat Text -> Text -> Bool
`T.isInfixOf` Text
normalizedChanName =
            case Text -> Text -> (Text, Text)
T.breakOn Text
pat Text
normalizedChanName of
                (Text
pre, Text
_) ->
                    (Text, Text, Text) -> Maybe (Text, Text, Text)
forall (m :: * -> *) a. Monad m => a -> m a
return ( Int -> Text -> Text
T.take (Text -> Int
T.length Text
pre) Text
chanName
                           , Int -> Text -> Text
T.take (Text -> Int
T.length Text
pat) (Text -> Text) -> Text -> Text
forall a b. (a -> b) -> a -> b
$ Int -> Text -> Text
T.drop (Text -> Int
T.length Text
pre) Text
chanName
                           , Int -> Text -> Text
T.drop (Text -> Int
T.length Text
pat Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Text -> Int
T.length Text
pre) Text
chanName
                           )

        applyType MatchType
Prefix | Text
pat Text -> Text -> Bool
`T.isPrefixOf` Text
normalizedChanName = do
            let (Text
b, Text
a) = Int -> Text -> (Text, Text)
T.splitAt (Text -> Int
T.length Text
pat) Text
chanName
            (Text, Text, Text) -> Maybe (Text, Text, Text)
forall (m :: * -> *) a. Monad m => a -> m a
return (Text
"", Text
b, Text
a)

        applyType MatchType
PrefixDMOnly | Text
pat Text -> Text -> Bool
`T.isPrefixOf` Text
normalizedChanName = do
            let (Text
b, Text
a) = Int -> Text -> (Text, Text)
T.splitAt (Text -> Int
T.length Text
pat) Text
chanName
            (Text, Text, Text) -> Maybe (Text, Text, Text)
forall (m :: * -> *) a. Monad m => a -> m a
return (Text
"", Text
b, Text
a)

        applyType MatchType
PrefixNonDMOnly | Text
pat Text -> Text -> Bool
`T.isPrefixOf` Text
normalizedChanName = do
            let (Text
b, Text
a) = Int -> Text -> (Text, Text)
T.splitAt (Text -> Int
T.length Text
pat) Text
chanName
            (Text, Text, Text) -> Maybe (Text, Text, Text)
forall (m :: * -> *) a. Monad m => a -> m a
return (Text
"", Text
b, Text
a)

        applyType MatchType
Suffix | Text
pat Text -> Text -> Bool
`T.isSuffixOf` Text
normalizedChanName = do
            let (Text
b, Text
a) = Int -> Text -> (Text, Text)
T.splitAt (Text -> Int
T.length Text
chanName Int -> Int -> Int
forall a. Num a => a -> a -> a
- Text -> Int
T.length Text
pat) Text
chanName
            (Text, Text, Text) -> Maybe (Text, Text, Text)
forall (m :: * -> *) a. Monad m => a -> m a
return (Text
b, Text
a, Text
"")

        applyType MatchType
Equal  | Text
pat Text -> Text -> Bool
forall a. Eq a => a -> a -> Bool
== Text
normalizedChanName =
            (Text, Text, Text) -> Maybe (Text, Text, Text)
forall (m :: * -> *) a. Monad m => a -> m a
return (Text
"", Text
chanName, Text
"")

        applyType MatchType
_ = Maybe (Text, Text, Text)
forall a. Maybe a
Nothing

        caseSensitive :: Bool
caseSensitive = (Char -> Bool) -> Text -> Bool
T.any Char -> Bool
isUpper Text
pat
        normalizedChanName :: Text
normalizedChanName = if Bool
caseSensitive
                             then Text
chanName
                             else Text -> Text
T.toLower Text
chanName

    (Text
pre, Text
m, Text
post) <- MatchType -> Maybe (Text, Text, Text)
applyType MatchType
ty
    ChannelSelectMatch -> Maybe ChannelSelectMatch
forall (m :: * -> *) a. Monad m => a -> m a
return (ChannelSelectMatch -> Maybe ChannelSelectMatch)
-> ChannelSelectMatch -> Maybe ChannelSelectMatch
forall a b. (a -> b) -> a -> b
$ Text
-> Text -> Text -> Text -> ChannelListEntry -> ChannelSelectMatch
ChannelSelectMatch Text
pre Text
m Text
post Text
chanName ChannelListEntry
entry

parseChannelSelectPattern :: Text -> Maybe ChannelSelectPattern
parseChannelSelectPattern :: Text -> Maybe ChannelSelectPattern
parseChannelSelectPattern Text
"" = ChannelSelectPattern -> Maybe ChannelSelectPattern
forall (m :: * -> *) a. Monad m => a -> m a
return ChannelSelectPattern
CSPAny
parseChannelSelectPattern Text
pat = do
    let only :: Maybe ChannelSelectPattern
only = if | Text
userSigil Text -> Text -> Bool
`T.isPrefixOf` Text
pat -> ChannelSelectPattern -> Maybe ChannelSelectPattern
forall a. a -> Maybe a
Just (ChannelSelectPattern -> Maybe ChannelSelectPattern)
-> ChannelSelectPattern -> Maybe ChannelSelectPattern
forall a b. (a -> b) -> a -> b
$ MatchType -> Text -> ChannelSelectPattern
CSP MatchType
PrefixDMOnly (Text -> ChannelSelectPattern) -> Text -> ChannelSelectPattern
forall a b. (a -> b) -> a -> b
$ Text -> Text
T.tail Text
pat
                  | Text
normalChannelSigil Text -> Text -> Bool
`T.isPrefixOf` Text
pat -> ChannelSelectPattern -> Maybe ChannelSelectPattern
forall a. a -> Maybe a
Just (ChannelSelectPattern -> Maybe ChannelSelectPattern)
-> ChannelSelectPattern -> Maybe ChannelSelectPattern
forall a b. (a -> b) -> a -> b
$ MatchType -> Text -> ChannelSelectPattern
CSP MatchType
PrefixNonDMOnly (Text -> ChannelSelectPattern) -> Text -> ChannelSelectPattern
forall a b. (a -> b) -> a -> b
$ Text -> Text
T.tail Text
pat
                  | Bool
otherwise -> Maybe ChannelSelectPattern
forall a. Maybe a
Nothing

    (Text
pat1, Maybe MatchType
pfx) <- case Text
"^" Text -> Text -> Bool
`T.isPrefixOf` Text
pat of
        Bool
True  -> (Text, Maybe MatchType) -> Maybe (Text, Maybe MatchType)
forall (m :: * -> *) a. Monad m => a -> m a
return (Text -> Text
T.tail Text
pat, MatchType -> Maybe MatchType
forall a. a -> Maybe a
Just MatchType
Prefix)
        Bool
False -> (Text, Maybe MatchType) -> Maybe (Text, Maybe MatchType)
forall (m :: * -> *) a. Monad m => a -> m a
return (Text
pat, Maybe MatchType
forall a. Maybe a
Nothing)

    (Text
pat2, Maybe MatchType
sfx) <- case Text
"$" Text -> Text -> Bool
`T.isSuffixOf` Text
pat1 of
        Bool
True  -> (Text, Maybe MatchType) -> Maybe (Text, Maybe MatchType)
forall (m :: * -> *) a. Monad m => a -> m a
return (Text -> Text
T.init Text
pat1, MatchType -> Maybe MatchType
forall a. a -> Maybe a
Just MatchType
Suffix)
        Bool
False -> (Text, Maybe MatchType) -> Maybe (Text, Maybe MatchType)
forall (m :: * -> *) a. Monad m => a -> m a
return (Text
pat1, Maybe MatchType
forall a. Maybe a
Nothing)

    Maybe ChannelSelectPattern
only Maybe ChannelSelectPattern
-> Maybe ChannelSelectPattern -> Maybe ChannelSelectPattern
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> case (Maybe MatchType
pfx, Maybe MatchType
sfx) of
        (Maybe MatchType
Nothing, Maybe MatchType
Nothing)         -> ChannelSelectPattern -> Maybe ChannelSelectPattern
forall (m :: * -> *) a. Monad m => a -> m a
return (ChannelSelectPattern -> Maybe ChannelSelectPattern)
-> ChannelSelectPattern -> Maybe ChannelSelectPattern
forall a b. (a -> b) -> a -> b
$ MatchType -> Text -> ChannelSelectPattern
CSP MatchType
Infix  Text
pat2
        (Just MatchType
Prefix, Maybe MatchType
Nothing)     -> ChannelSelectPattern -> Maybe ChannelSelectPattern
forall (m :: * -> *) a. Monad m => a -> m a
return (ChannelSelectPattern -> Maybe ChannelSelectPattern)
-> ChannelSelectPattern -> Maybe ChannelSelectPattern
forall a b. (a -> b) -> a -> b
$ MatchType -> Text -> ChannelSelectPattern
CSP MatchType
Prefix Text
pat2
        (Maybe MatchType
Nothing, Just MatchType
Suffix)     -> ChannelSelectPattern -> Maybe ChannelSelectPattern
forall (m :: * -> *) a. Monad m => a -> m a
return (ChannelSelectPattern -> Maybe ChannelSelectPattern)
-> ChannelSelectPattern -> Maybe ChannelSelectPattern
forall a b. (a -> b) -> a -> b
$ MatchType -> Text -> ChannelSelectPattern
CSP MatchType
Suffix Text
pat2
        (Just MatchType
Prefix, Just MatchType
Suffix) -> ChannelSelectPattern -> Maybe ChannelSelectPattern
forall (m :: * -> *) a. Monad m => a -> m a
return (ChannelSelectPattern -> Maybe ChannelSelectPattern)
-> ChannelSelectPattern -> Maybe ChannelSelectPattern
forall a b. (a -> b) -> a -> b
$ MatchType -> Text -> ChannelSelectPattern
CSP MatchType
Equal  Text
pat2
        (Maybe MatchType, Maybe MatchType)
tys                        -> [Char] -> Maybe ChannelSelectPattern
forall a. HasCallStack => [Char] -> a
error ([Char] -> Maybe ChannelSelectPattern)
-> [Char] -> Maybe ChannelSelectPattern
forall a b. (a -> b) -> a -> b
$ [Char]
"BUG: invalid channel select case: " [Char] -> [Char] -> [Char]
forall a. Semigroup a => a -> a -> a
<> (Maybe MatchType, Maybe MatchType) -> [Char]
forall a. Show a => a -> [Char]
show (Maybe MatchType, Maybe MatchType)
tys

-- Update the channel selection mode match cursor. The argument function
-- determines how to navigate to the next item.
updateSelectedMatch :: (Z.Zipper ChannelListGroup ChannelSelectMatch -> Z.Zipper ChannelListGroup ChannelSelectMatch)
                    -> MH ()
updateSelectedMatch :: (Zipper ChannelListGroup ChannelSelectMatch
 -> Zipper ChannelListGroup ChannelSelectMatch)
-> MH ()
updateSelectedMatch Zipper ChannelListGroup ChannelSelectMatch
-> Zipper ChannelListGroup ChannelSelectMatch
nextItem =
    (TeamState -> Identity TeamState)
-> ChatState -> Identity ChatState
Lens' ChatState TeamState
csCurrentTeam((TeamState -> Identity TeamState)
 -> ChatState -> Identity ChatState)
-> ((Zipper ChannelListGroup ChannelSelectMatch
     -> Identity (Zipper ChannelListGroup ChannelSelectMatch))
    -> TeamState -> Identity TeamState)
-> (Zipper ChannelListGroup ChannelSelectMatch
    -> Identity (Zipper ChannelListGroup ChannelSelectMatch))
-> ChatState
-> Identity ChatState
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(ChannelSelectState -> Identity ChannelSelectState)
-> TeamState -> Identity TeamState
Lens' TeamState ChannelSelectState
tsChannelSelectState((ChannelSelectState -> Identity ChannelSelectState)
 -> TeamState -> Identity TeamState)
-> ((Zipper ChannelListGroup ChannelSelectMatch
     -> Identity (Zipper ChannelListGroup ChannelSelectMatch))
    -> ChannelSelectState -> Identity ChannelSelectState)
-> (Zipper ChannelListGroup ChannelSelectMatch
    -> Identity (Zipper ChannelListGroup ChannelSelectMatch))
-> TeamState
-> Identity TeamState
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(Zipper ChannelListGroup ChannelSelectMatch
 -> Identity (Zipper ChannelListGroup ChannelSelectMatch))
-> ChannelSelectState -> Identity ChannelSelectState
Lens'
  ChannelSelectState (Zipper ChannelListGroup ChannelSelectMatch)
channelSelectMatches ((Zipper ChannelListGroup ChannelSelectMatch
  -> Identity (Zipper ChannelListGroup ChannelSelectMatch))
 -> ChatState -> Identity ChatState)
-> (Zipper ChannelListGroup ChannelSelectMatch
    -> Zipper ChannelListGroup ChannelSelectMatch)
-> MH ()
forall s (m :: * -> *) a b.
MonadState s m =>
ASetter s s a b -> (a -> b) -> m ()
%= Zipper ChannelListGroup ChannelSelectMatch
-> Zipper ChannelListGroup ChannelSelectMatch
nextItem