{-# LANGUAGE MultiWayIf #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE RankNTypes #-}
module Matterhorn.State.Editing
  ( requestSpellCheck
  , editingKeybindings
  , editingKeyHandlers
  , toggleMultilineEditing
  , invokeExternalEditor
  , handlePaste
  , handleInputSubmission
  , getEditorContent
  , handleEditingInput
  , cancelAutocompleteOrReplyOrEdit
  , replyToLatestMessage
  , Direction(..)
  , tabComplete
  )
where

import           Prelude ()
import           Matterhorn.Prelude

import           Brick.Main ( invalidateCache )
import           Brick.Widgets.Edit ( Editor, applyEdit , handleEditorEvent
                                    , getEditContents, editContentsL )
import qualified Brick.Widgets.List as L
import qualified Codec.Binary.UTF8.Generic as UTF8
import           Control.Arrow
import qualified Control.Concurrent.STM as STM
import qualified Data.ByteString as BS
import           Data.Char ( isSpace )
import qualified Data.Foldable as F
import           Data.Maybe ( fromJust )
import qualified Data.Set as S
import qualified Data.Text as T
import qualified Data.Text.Encoding as T
import qualified Data.Text.Zipper as Z
import qualified Data.Text.Zipper.Generic.Words as Z
import           Data.Time ( getCurrentTime )
import           Graphics.Vty ( Event(..), Key(..) )
import           Lens.Micro.Platform ( Traversal', Lens', (%=), (.=), (.~), to, _Just )
import qualified System.Environment as Sys
import qualified System.Exit as Sys
import qualified System.IO as Sys
import qualified System.IO.Temp as Sys
import qualified System.Process as Sys
import           Text.Aspell ( Aspell, AspellResponse(..), mistakeWord, askAspell )

import           Network.Mattermost.Types ( Post(..) )

import           Matterhorn.Config
import {-# SOURCE #-} Matterhorn.Command ( dispatchCommand )
import           Matterhorn.InputHistory
import           Matterhorn.Events.Keybindings
import           Matterhorn.State.Common
import           Matterhorn.State.Autocomplete
import {-# SOURCE #-} Matterhorn.State.Messages
import {-# SOURCE #-} Matterhorn.State.ThreadWindow
import           Matterhorn.Types hiding ( newState )
import           Matterhorn.Types.Common ( sanitizeUserText' )


startMultilineEditing :: Lens' ChatState (EditState Name) -> MH ()
startMultilineEditing :: Lens' ChatState (EditState Name) -> MH ()
startMultilineEditing Lens' ChatState (EditState Name)
which = do
    EventM Name () -> MH ()
forall a. EventM Name a -> MH a
mh EventM Name ()
forall n. Ord n => EventM n ()
invalidateCache
    (EditState Name -> Identity (EditState Name))
-> ChatState -> Identity ChatState
Lens' ChatState (EditState Name)
which((EditState Name -> Identity (EditState Name))
 -> ChatState -> Identity ChatState)
-> ((Bool -> Identity Bool)
    -> EditState Name -> Identity (EditState Name))
-> (Bool -> Identity Bool)
-> ChatState
-> Identity ChatState
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(EphemeralEditState -> Identity EphemeralEditState)
-> EditState Name -> Identity (EditState Name)
forall n. Lens' (EditState n) EphemeralEditState
esEphemeral((EphemeralEditState -> Identity EphemeralEditState)
 -> EditState Name -> Identity (EditState Name))
-> ((Bool -> Identity Bool)
    -> EphemeralEditState -> Identity EphemeralEditState)
-> (Bool -> Identity Bool)
-> EditState Name
-> Identity (EditState Name)
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(Bool -> Identity Bool)
-> EphemeralEditState -> Identity EphemeralEditState
Lens' EphemeralEditState Bool
eesMultiline ((Bool -> Identity Bool) -> ChatState -> Identity ChatState)
-> Bool -> MH ()
forall s (m :: * -> *) a b.
MonadState s m =>
ASetter s s a b -> b -> m ()
.= Bool
True

toggleMultilineEditing :: Lens' ChatState (EditState Name) -> MH ()
toggleMultilineEditing :: Lens' ChatState (EditState Name) -> MH ()
toggleMultilineEditing Lens' ChatState (EditState Name)
which = do
    EventM Name () -> MH ()
forall a. EventM Name a -> MH a
mh EventM Name ()
forall n. Ord n => EventM n ()
invalidateCache
    (EditState Name -> Identity (EditState Name))
-> ChatState -> Identity ChatState
Lens' ChatState (EditState Name)
which((EditState Name -> Identity (EditState Name))
 -> ChatState -> Identity ChatState)
-> ((Bool -> Identity Bool)
    -> EditState Name -> Identity (EditState Name))
-> (Bool -> Identity Bool)
-> ChatState
-> Identity ChatState
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(EphemeralEditState -> Identity EphemeralEditState)
-> EditState Name -> Identity (EditState Name)
forall n. Lens' (EditState n) EphemeralEditState
esEphemeral((EphemeralEditState -> Identity EphemeralEditState)
 -> EditState Name -> Identity (EditState Name))
-> ((Bool -> Identity Bool)
    -> EphemeralEditState -> Identity EphemeralEditState)
-> (Bool -> Identity Bool)
-> EditState Name
-> Identity (EditState Name)
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(Bool -> Identity Bool)
-> EphemeralEditState -> Identity EphemeralEditState
Lens' EphemeralEditState Bool
eesMultiline ((Bool -> Identity Bool) -> ChatState -> Identity ChatState)
-> (Bool -> Bool) -> MH ()
forall s (m :: * -> *) a b.
MonadState s m =>
ASetter s s a b -> (a -> b) -> m ()
%= Bool -> Bool
not

    -- If multiline is now disabled and there is more than one line in
    -- the editor, that means we're showing the multiline message status
    -- (see Draw.Main.renderUserCommandBox.commandBox) so we want to be
    -- sure no autocomplete UI is present in case the cursor was left on
    -- a word that would otherwise show completion alternatives.
    Bool
multiline <- Getting Bool ChatState Bool -> MH Bool
forall s (m :: * -> *) a. MonadState s m => Getting a s a -> m a
use ((EditState Name -> Const Bool (EditState Name))
-> ChatState -> Const Bool ChatState
Lens' ChatState (EditState Name)
which((EditState Name -> Const Bool (EditState Name))
 -> ChatState -> Const Bool ChatState)
-> ((Bool -> Const Bool Bool)
    -> EditState Name -> Const Bool (EditState Name))
-> Getting Bool ChatState Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(EphemeralEditState -> Const Bool EphemeralEditState)
-> EditState Name -> Const Bool (EditState Name)
forall n. Lens' (EditState n) EphemeralEditState
esEphemeral((EphemeralEditState -> Const Bool EphemeralEditState)
 -> EditState Name -> Const Bool (EditState Name))
-> ((Bool -> Const Bool Bool)
    -> EphemeralEditState -> Const Bool EphemeralEditState)
-> (Bool -> Const Bool Bool)
-> EditState Name
-> Const Bool (EditState Name)
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(Bool -> Const Bool Bool)
-> EphemeralEditState -> Const Bool EphemeralEditState
Lens' EphemeralEditState Bool
eesMultiline)
    Int
numLines <- Getting Int ChatState Int -> MH Int
forall s (m :: * -> *) a. MonadState s m => Getting a s a -> m a
use ((EditState Name -> Const Int (EditState Name))
-> ChatState -> Const Int ChatState
Lens' ChatState (EditState Name)
which((EditState Name -> Const Int (EditState Name))
 -> ChatState -> Const Int ChatState)
-> ((Int -> Const Int Int)
    -> EditState Name -> Const Int (EditState Name))
-> Getting Int ChatState Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(Editor Text Name -> Const Int (Editor Text Name))
-> EditState Name -> Const Int (EditState Name)
forall n. Lens' (EditState n) (Editor Text n)
esEditor((Editor Text Name -> Const Int (Editor Text Name))
 -> EditState Name -> Const Int (EditState Name))
-> ((Int -> Const Int Int)
    -> Editor Text Name -> Const Int (Editor Text Name))
-> (Int -> Const Int Int)
-> EditState Name
-> Const Int (EditState Name)
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(Editor Text Name -> [Text])
-> SimpleGetter (Editor Text Name) [Text]
forall s a. (s -> a) -> SimpleGetter s a
to Editor Text Name -> [Text]
forall t n. Monoid t => Editor t n -> [t]
getEditContentsGetting Int (Editor Text Name) [Text]
-> ((Int -> Const Int Int) -> [Text] -> Const Int [Text])
-> (Int -> Const Int Int)
-> Editor Text Name
-> Const Int (Editor Text Name)
forall b c a. (b -> c) -> (a -> b) -> a -> c
.([Text] -> Int) -> SimpleGetter [Text] Int
forall s a. (s -> a) -> SimpleGetter s a
to [Text] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length)
    Bool -> MH () -> MH ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Bool -> Bool
not Bool
multiline Bool -> Bool -> Bool
&& Int
numLines Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
1) (Traversal' ChatState (EditState Name) -> MH ()
forall n. Traversal' ChatState (EditState n) -> MH ()
resetAutocomplete Lens' ChatState (EditState Name)
Traversal' ChatState (EditState Name)
which)

invokeExternalEditor :: Lens' ChatState (EditState Name) -> MH ()
invokeExternalEditor :: Lens' ChatState (EditState Name) -> MH ()
invokeExternalEditor Lens' ChatState (EditState Name)
which = do
    -- If EDITOR is in the environment, write the current message to a
    -- temp file, invoke EDITOR on it, read the result, remove the temp
    -- file, and update the program state.
    --
    -- If EDITOR is not present, fall back to 'vi'.
    Maybe String
mEnv <- IO (Maybe String) -> MH (Maybe String)
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO (Maybe String) -> MH (Maybe String))
-> IO (Maybe String) -> MH (Maybe String)
forall a b. (a -> b) -> a -> b
$ String -> IO (Maybe String)
Sys.lookupEnv String
"EDITOR"
    let editorProgram :: String
editorProgram = String -> (String -> String) -> Maybe String -> String
forall b a. b -> (a -> b) -> Maybe a -> b
maybe String
"vi" String -> String
forall a. a -> a
id Maybe String
mEnv

    (ChatState -> IO ChatState) -> MH ()
mhSuspendAndResume ((ChatState -> IO ChatState) -> MH ())
-> (ChatState -> IO ChatState) -> MH ()
forall a b. (a -> b) -> a -> b
$ \ ChatState
st -> do
      String -> (String -> Handle -> IO ChatState) -> IO ChatState
forall (m :: * -> *) a.
(MonadIO m, MonadMask m) =>
String -> (String -> Handle -> m a) -> m a
Sys.withSystemTempFile String
"matterhorn_editor.md" ((String -> Handle -> IO ChatState) -> IO ChatState)
-> (String -> Handle -> IO ChatState) -> IO ChatState
forall a b. (a -> b) -> a -> b
$ \String
tmpFileName Handle
tmpFileHandle -> do
        -- Write the current message to the temp file
        Handle -> String -> IO ()
Sys.hPutStr Handle
tmpFileHandle (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$ Text -> String
T.unpack (Text -> String) -> Text -> String
forall a b. (a -> b) -> a -> b
$ Text -> [Text] -> Text
T.intercalate Text
"\n" ([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 -> [Text]) -> Editor Text Name -> [Text]
forall a b. (a -> b) -> a -> b
$ ChatState
stChatState
-> Getting (Editor Text Name) ChatState (Editor Text Name)
-> Editor Text Name
forall s a. s -> Getting a s a -> a
^.(EditState Name -> Const (Editor Text Name) (EditState Name))
-> ChatState -> Const (Editor Text Name) ChatState
Lens' ChatState (EditState Name)
which((EditState Name -> Const (Editor Text Name) (EditState Name))
 -> ChatState -> Const (Editor Text Name) ChatState)
-> ((Editor Text Name
     -> Const (Editor Text Name) (Editor Text Name))
    -> EditState Name -> Const (Editor Text Name) (EditState Name))
-> Getting (Editor Text Name) ChatState (Editor Text Name)
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(Editor Text Name -> Const (Editor Text Name) (Editor Text Name))
-> EditState Name -> Const (Editor Text Name) (EditState Name)
forall n. Lens' (EditState n) (Editor Text n)
esEditor
        Handle -> IO ()
Sys.hClose Handle
tmpFileHandle

        -- Run the editor
        ExitCode
status <- String -> IO ExitCode
Sys.system (String
editorProgram String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
" " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
tmpFileName)

        -- On editor exit, if exited with zero status, read temp file.
        -- If non-zero status, skip temp file read.
        case ExitCode
status of
            ExitCode
Sys.ExitSuccess -> do
                ByteString
tmpBytes <- String -> IO ByteString
BS.readFile String
tmpFileName
                case ByteString -> Either UnicodeException Text
T.decodeUtf8' ByteString
tmpBytes of
                    Left UnicodeException
_ -> do
                        Text -> ChatState -> IO ChatState
postErrorMessageIO Text
"Failed to decode file contents as UTF-8" ChatState
st
                    Right Text
t -> do
                        let tmpLines :: [Text]
tmpLines = Text -> [Text]
T.lines (Text -> [Text]) -> Text -> [Text]
forall a b. (a -> b) -> a -> b
$ Text -> Text
sanitizeUserText' Text
t
                        ChatState -> IO ChatState
forall (m :: * -> *) a. Monad m => a -> m a
return (ChatState -> IO ChatState) -> ChatState -> IO ChatState
forall a b. (a -> b) -> a -> b
$ ChatState
st ChatState -> (ChatState -> ChatState) -> ChatState
forall a b. a -> (a -> b) -> b
& (EditState Name -> Identity (EditState Name))
-> ChatState -> Identity ChatState
Lens' ChatState (EditState Name)
which((EditState Name -> Identity (EditState Name))
 -> ChatState -> Identity ChatState)
-> ((TextZipper Text -> Identity (TextZipper Text))
    -> EditState Name -> Identity (EditState Name))
-> (TextZipper Text -> Identity (TextZipper Text))
-> ChatState
-> Identity ChatState
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(Editor Text Name -> Identity (Editor Text Name))
-> EditState Name -> Identity (EditState Name)
forall n. Lens' (EditState n) (Editor Text n)
esEditor((Editor Text Name -> Identity (Editor Text Name))
 -> EditState Name -> Identity (EditState Name))
-> ((TextZipper Text -> Identity (TextZipper Text))
    -> Editor Text Name -> Identity (Editor Text Name))
-> (TextZipper Text -> Identity (TextZipper Text))
-> EditState Name
-> Identity (EditState Name)
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(TextZipper Text -> Identity (TextZipper Text))
-> Editor Text Name -> Identity (Editor Text Name)
forall t1 n t2.
Lens (Editor t1 n) (Editor t2 n) (TextZipper t1) (TextZipper t2)
editContentsL ((TextZipper Text -> Identity (TextZipper Text))
 -> ChatState -> Identity ChatState)
-> TextZipper Text -> ChatState -> ChatState
forall s t a b. ASetter s t a b -> b -> s -> t
.~ ([Text] -> Maybe Int -> TextZipper Text
Z.textZipper [Text]
tmpLines Maybe Int
forall a. Maybe a
Nothing)
            Sys.ExitFailure Int
_ -> ChatState -> IO ChatState
forall (m :: * -> *) a. Monad m => a -> m a
return ChatState
st

handlePaste :: Lens' ChatState (EditState Name) -> BS.ByteString -> MH ()
handlePaste :: Lens' ChatState (EditState Name) -> ByteString -> MH ()
handlePaste Lens' ChatState (EditState Name)
which ByteString
bytes = do
  let pasteStr :: Text
pasteStr = String -> Text
T.pack (ByteString -> String
forall b s. UTF8Bytes b s => b -> String
UTF8.toString ByteString
bytes)
  (EditState Name -> Identity (EditState Name))
-> ChatState -> Identity ChatState
Lens' ChatState (EditState Name)
which((EditState Name -> Identity (EditState Name))
 -> ChatState -> Identity ChatState)
-> ((Editor Text Name -> Identity (Editor Text Name))
    -> EditState Name -> Identity (EditState Name))
-> (Editor Text Name -> Identity (Editor Text Name))
-> ChatState
-> Identity ChatState
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(Editor Text Name -> Identity (Editor Text Name))
-> EditState Name -> Identity (EditState Name)
forall n. Lens' (EditState n) (Editor Text n)
esEditor ((Editor Text Name -> Identity (Editor Text Name))
 -> ChatState -> Identity ChatState)
-> (Editor Text Name -> Editor Text Name) -> MH ()
forall s (m :: * -> *) a b.
MonadState s m =>
ASetter s s a b -> (a -> b) -> m ()
%= (TextZipper Text -> TextZipper Text)
-> Editor Text Name -> Editor Text Name
forall t n.
(TextZipper t -> TextZipper t) -> Editor t n -> Editor t n
applyEdit (Text -> TextZipper Text -> TextZipper Text
forall a. Monoid a => a -> TextZipper a -> TextZipper a
Z.insertMany (Text -> Text
sanitizeUserText' Text
pasteStr))
  [Text]
contents <- Getting [Text] ChatState [Text] -> MH [Text]
forall s (m :: * -> *) a. MonadState s m => Getting a s a -> m a
use ((EditState Name -> Const [Text] (EditState Name))
-> ChatState -> Const [Text] ChatState
Lens' ChatState (EditState Name)
which((EditState Name -> Const [Text] (EditState Name))
 -> ChatState -> Const [Text] ChatState)
-> (([Text] -> Const [Text] [Text])
    -> EditState Name -> Const [Text] (EditState Name))
-> Getting [Text] ChatState [Text]
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(Editor Text Name -> Const [Text] (Editor Text Name))
-> EditState Name -> Const [Text] (EditState Name)
forall n. Lens' (EditState n) (Editor Text n)
esEditor((Editor Text Name -> Const [Text] (Editor Text Name))
 -> EditState Name -> Const [Text] (EditState Name))
-> (([Text] -> Const [Text] [Text])
    -> Editor Text Name -> Const [Text] (Editor Text Name))
-> ([Text] -> Const [Text] [Text])
-> EditState Name
-> Const [Text] (EditState Name)
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(Editor Text Name -> [Text])
-> SimpleGetter (Editor Text Name) [Text]
forall s a. (s -> a) -> SimpleGetter s a
to Editor Text Name -> [Text]
forall t n. Monoid t => Editor t n -> [t]
getEditContents)
  case [Text] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Text]
contents Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
1 of
      Bool
True -> Lens' ChatState (EditState Name) -> MH ()
startMultilineEditing Lens' ChatState (EditState Name)
which
      Bool
False -> () -> MH ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()

editingPermitted :: ChatState -> Lens' ChatState (EditState Name) -> Bool
editingPermitted :: ChatState -> Lens' ChatState (EditState Name) -> Bool
editingPermitted ChatState
st Lens' ChatState (EditState Name)
which =
    ([Text] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length (Editor Text Name -> [Text]
forall t n. Monoid t => Editor t n -> [t]
getEditContents (Editor Text Name -> [Text]) -> Editor Text Name -> [Text]
forall a b. (a -> b) -> a -> b
$ ChatState
stChatState
-> Getting (Editor Text Name) ChatState (Editor Text Name)
-> Editor Text Name
forall s a. s -> Getting a s a -> a
^.(EditState Name -> Const (Editor Text Name) (EditState Name))
-> ChatState -> Const (Editor Text Name) ChatState
Lens' ChatState (EditState Name)
which((EditState Name -> Const (Editor Text Name) (EditState Name))
 -> ChatState -> Const (Editor Text Name) ChatState)
-> ((Editor Text Name
     -> Const (Editor Text Name) (Editor Text Name))
    -> EditState Name -> Const (Editor Text Name) (EditState Name))
-> Getting (Editor Text Name) ChatState (Editor Text Name)
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(Editor Text Name -> Const (Editor Text Name) (Editor Text Name))
-> EditState Name -> Const (Editor Text Name) (EditState Name)
forall n. Lens' (EditState n) (Editor Text n)
esEditor) Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
1) Bool -> Bool -> Bool
||
    ChatState
stChatState -> Getting Bool ChatState Bool -> Bool
forall s a. s -> Getting a s a -> a
^.(EditState Name -> Const Bool (EditState Name))
-> ChatState -> Const Bool ChatState
Lens' ChatState (EditState Name)
which((EditState Name -> Const Bool (EditState Name))
 -> ChatState -> Const Bool ChatState)
-> ((Bool -> Const Bool Bool)
    -> EditState Name -> Const Bool (EditState Name))
-> Getting Bool ChatState Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(EphemeralEditState -> Const Bool EphemeralEditState)
-> EditState Name -> Const Bool (EditState Name)
forall n. Lens' (EditState n) EphemeralEditState
esEphemeral((EphemeralEditState -> Const Bool EphemeralEditState)
 -> EditState Name -> Const Bool (EditState Name))
-> ((Bool -> Const Bool Bool)
    -> EphemeralEditState -> Const Bool EphemeralEditState)
-> (Bool -> Const Bool Bool)
-> EditState Name
-> Const Bool (EditState Name)
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(Bool -> Const Bool Bool)
-> EphemeralEditState -> Const Bool EphemeralEditState
Lens' EphemeralEditState Bool
eesMultiline

editingKeybindings :: Lens' ChatState (Editor T.Text Name) -> KeyConfig -> KeyHandlerMap
editingKeybindings :: Lens' ChatState (Editor Text Name) -> KeyConfig -> KeyHandlerMap
editingKeybindings Lens' ChatState (Editor Text Name)
editor = [KeyEventHandler] -> KeyConfig -> KeyHandlerMap
mkKeybindings ([KeyEventHandler] -> KeyConfig -> KeyHandlerMap)
-> [KeyEventHandler] -> KeyConfig -> KeyHandlerMap
forall a b. (a -> b) -> a -> b
$ Lens' ChatState (Editor Text Name) -> [KeyEventHandler]
editingKeyHandlers Lens' ChatState (Editor Text Name)
editor

editingKeyHandlers :: Lens' ChatState (Editor T.Text Name) -> [KeyEventHandler]
editingKeyHandlers :: Lens' ChatState (Editor Text Name) -> [KeyEventHandler]
editingKeyHandlers Lens' ChatState (Editor Text Name)
editor =
  [ KeyEvent -> Text -> MH () -> KeyEventHandler
mkKb KeyEvent
EditorTransposeCharsEvent
    Text
"Transpose the final two characters"
    ((Editor Text Name -> Identity (Editor Text Name))
-> ChatState -> Identity ChatState
Lens' ChatState (Editor Text Name)
editor ((Editor Text Name -> Identity (Editor Text Name))
 -> ChatState -> Identity ChatState)
-> (Editor Text Name -> Editor Text Name) -> MH ()
forall s (m :: * -> *) a b.
MonadState s m =>
ASetter s s a b -> (a -> b) -> m ()
%= (TextZipper Text -> TextZipper Text)
-> Editor Text Name -> Editor Text Name
forall t n.
(TextZipper t -> TextZipper t) -> Editor t n -> Editor t n
applyEdit TextZipper Text -> TextZipper Text
forall a. Monoid a => TextZipper a -> TextZipper a
Z.transposeChars)
  , KeyEvent -> Text -> MH () -> KeyEventHandler
mkKb KeyEvent
EditorBolEvent
    Text
"Go to the start of the current line"
    ((Editor Text Name -> Identity (Editor Text Name))
-> ChatState -> Identity ChatState
Lens' ChatState (Editor Text Name)
editor ((Editor Text Name -> Identity (Editor Text Name))
 -> ChatState -> Identity ChatState)
-> (Editor Text Name -> Editor Text Name) -> MH ()
forall s (m :: * -> *) a b.
MonadState s m =>
ASetter s s a b -> (a -> b) -> m ()
%= (TextZipper Text -> TextZipper Text)
-> Editor Text Name -> Editor Text Name
forall t n.
(TextZipper t -> TextZipper t) -> Editor t n -> Editor t n
applyEdit TextZipper Text -> TextZipper Text
forall a. Monoid a => TextZipper a -> TextZipper a
Z.gotoBOL)
  , KeyEvent -> Text -> MH () -> KeyEventHandler
mkKb KeyEvent
EditorEolEvent
    Text
"Go to the end of the current line"
    ((Editor Text Name -> Identity (Editor Text Name))
-> ChatState -> Identity ChatState
Lens' ChatState (Editor Text Name)
editor ((Editor Text Name -> Identity (Editor Text Name))
 -> ChatState -> Identity ChatState)
-> (Editor Text Name -> Editor Text Name) -> MH ()
forall s (m :: * -> *) a b.
MonadState s m =>
ASetter s s a b -> (a -> b) -> m ()
%= (TextZipper Text -> TextZipper Text)
-> Editor Text Name -> Editor Text Name
forall t n.
(TextZipper t -> TextZipper t) -> Editor t n -> Editor t n
applyEdit TextZipper Text -> TextZipper Text
forall a. Monoid a => TextZipper a -> TextZipper a
Z.gotoEOL)
  , KeyEvent -> Text -> MH () -> KeyEventHandler
mkKb KeyEvent
EditorDeleteCharacter
    Text
"Delete the character at the cursor"
    ((Editor Text Name -> Identity (Editor Text Name))
-> ChatState -> Identity ChatState
Lens' ChatState (Editor Text Name)
editor ((Editor Text Name -> Identity (Editor Text Name))
 -> ChatState -> Identity ChatState)
-> (Editor Text Name -> Editor Text Name) -> MH ()
forall s (m :: * -> *) a b.
MonadState s m =>
ASetter s s a b -> (a -> b) -> m ()
%= (TextZipper Text -> TextZipper Text)
-> Editor Text Name -> Editor Text Name
forall t n.
(TextZipper t -> TextZipper t) -> Editor t n -> Editor t n
applyEdit TextZipper Text -> TextZipper Text
forall a. Monoid a => TextZipper a -> TextZipper a
Z.deleteChar)
  , KeyEvent -> Text -> MH () -> KeyEventHandler
mkKb KeyEvent
EditorKillToBolEvent
    Text
"Delete from the cursor to the start of the current line"
    ((Editor Text Name -> Identity (Editor Text Name))
-> ChatState -> Identity ChatState
Lens' ChatState (Editor Text Name)
editor ((Editor Text Name -> Identity (Editor Text Name))
 -> ChatState -> Identity ChatState)
-> (Editor Text Name -> Editor Text Name) -> MH ()
forall s (m :: * -> *) a b.
MonadState s m =>
ASetter s s a b -> (a -> b) -> m ()
%= (TextZipper Text -> TextZipper Text)
-> Editor Text Name -> Editor Text Name
forall t n.
(TextZipper t -> TextZipper t) -> Editor t n -> Editor t n
applyEdit TextZipper Text -> TextZipper Text
forall a. Monoid a => TextZipper a -> TextZipper a
Z.killToBOL)
  , KeyEvent -> Text -> MH () -> KeyEventHandler
mkKb KeyEvent
EditorNextCharEvent
    Text
"Move one character to the right"
    ((Editor Text Name -> Identity (Editor Text Name))
-> ChatState -> Identity ChatState
Lens' ChatState (Editor Text Name)
editor ((Editor Text Name -> Identity (Editor Text Name))
 -> ChatState -> Identity ChatState)
-> (Editor Text Name -> Editor Text Name) -> MH ()
forall s (m :: * -> *) a b.
MonadState s m =>
ASetter s s a b -> (a -> b) -> m ()
%= (TextZipper Text -> TextZipper Text)
-> Editor Text Name -> Editor Text Name
forall t n.
(TextZipper t -> TextZipper t) -> Editor t n -> Editor t n
applyEdit TextZipper Text -> TextZipper Text
forall a. Monoid a => TextZipper a -> TextZipper a
Z.moveRight)
  , KeyEvent -> Text -> MH () -> KeyEventHandler
mkKb KeyEvent
EditorPrevCharEvent
    Text
"Move one character to the left"
    ((Editor Text Name -> Identity (Editor Text Name))
-> ChatState -> Identity ChatState
Lens' ChatState (Editor Text Name)
editor ((Editor Text Name -> Identity (Editor Text Name))
 -> ChatState -> Identity ChatState)
-> (Editor Text Name -> Editor Text Name) -> MH ()
forall s (m :: * -> *) a b.
MonadState s m =>
ASetter s s a b -> (a -> b) -> m ()
%= (TextZipper Text -> TextZipper Text)
-> Editor Text Name -> Editor Text Name
forall t n.
(TextZipper t -> TextZipper t) -> Editor t n -> Editor t n
applyEdit TextZipper Text -> TextZipper Text
forall a. Monoid a => TextZipper a -> TextZipper a
Z.moveLeft)
  , KeyEvent -> Text -> MH () -> KeyEventHandler
mkKb KeyEvent
EditorNextWordEvent
    Text
"Move one word to the right"
    ((Editor Text Name -> Identity (Editor Text Name))
-> ChatState -> Identity ChatState
Lens' ChatState (Editor Text Name)
editor ((Editor Text Name -> Identity (Editor Text Name))
 -> ChatState -> Identity ChatState)
-> (Editor Text Name -> Editor Text Name) -> MH ()
forall s (m :: * -> *) a b.
MonadState s m =>
ASetter s s a b -> (a -> b) -> m ()
%= (TextZipper Text -> TextZipper Text)
-> Editor Text Name -> Editor Text Name
forall t n.
(TextZipper t -> TextZipper t) -> Editor t n -> Editor t n
applyEdit TextZipper Text -> TextZipper Text
forall a. GenericTextZipper a => TextZipper a -> TextZipper a
Z.moveWordRight)
  , KeyEvent -> Text -> MH () -> KeyEventHandler
mkKb KeyEvent
EditorPrevWordEvent
    Text
"Move one word to the left"
    ((Editor Text Name -> Identity (Editor Text Name))
-> ChatState -> Identity ChatState
Lens' ChatState (Editor Text Name)
editor ((Editor Text Name -> Identity (Editor Text Name))
 -> ChatState -> Identity ChatState)
-> (Editor Text Name -> Editor Text Name) -> MH ()
forall s (m :: * -> *) a b.
MonadState s m =>
ASetter s s a b -> (a -> b) -> m ()
%= (TextZipper Text -> TextZipper Text)
-> Editor Text Name -> Editor Text Name
forall t n.
(TextZipper t -> TextZipper t) -> Editor t n -> Editor t n
applyEdit TextZipper Text -> TextZipper Text
forall a. GenericTextZipper a => TextZipper a -> TextZipper a
Z.moveWordLeft)
  , KeyEvent -> Text -> MH () -> KeyEventHandler
mkKb KeyEvent
EditorDeletePrevWordEvent
    Text
"Delete the word to the left of the cursor" (MH () -> KeyEventHandler) -> MH () -> KeyEventHandler
forall a b. (a -> b) -> a -> b
$ do
    (Editor Text Name -> Identity (Editor Text Name))
-> ChatState -> Identity ChatState
Lens' ChatState (Editor Text Name)
editor ((Editor Text Name -> Identity (Editor Text Name))
 -> ChatState -> Identity ChatState)
-> (Editor Text Name -> Editor Text Name) -> MH ()
forall s (m :: * -> *) a b.
MonadState s m =>
ASetter s s a b -> (a -> b) -> m ()
%= (TextZipper Text -> TextZipper Text)
-> Editor Text Name -> Editor Text Name
forall t n.
(TextZipper t -> TextZipper t) -> Editor t n -> Editor t n
applyEdit TextZipper Text -> TextZipper Text
forall a.
(Eq a, GenericTextZipper a) =>
TextZipper a -> TextZipper a
Z.deletePrevWord
  , KeyEvent -> Text -> MH () -> KeyEventHandler
mkKb KeyEvent
EditorDeleteNextWordEvent
    Text
"Delete the word to the right of the cursor" (MH () -> KeyEventHandler) -> MH () -> KeyEventHandler
forall a b. (a -> b) -> a -> b
$ do
    (Editor Text Name -> Identity (Editor Text Name))
-> ChatState -> Identity ChatState
Lens' ChatState (Editor Text Name)
editor ((Editor Text Name -> Identity (Editor Text Name))
 -> ChatState -> Identity ChatState)
-> (Editor Text Name -> Editor Text Name) -> MH ()
forall s (m :: * -> *) a b.
MonadState s m =>
ASetter s s a b -> (a -> b) -> m ()
%= (TextZipper Text -> TextZipper Text)
-> Editor Text Name -> Editor Text Name
forall t n.
(TextZipper t -> TextZipper t) -> Editor t n -> Editor t n
applyEdit TextZipper Text -> TextZipper Text
forall a. GenericTextZipper a => TextZipper a -> TextZipper a
Z.deleteWord
  , KeyEvent -> Text -> MH () -> KeyEventHandler
mkKb KeyEvent
EditorHomeEvent
    Text
"Move the cursor to the beginning of the input" (MH () -> KeyEventHandler) -> MH () -> KeyEventHandler
forall a b. (a -> b) -> a -> b
$ do
    (Editor Text Name -> Identity (Editor Text Name))
-> ChatState -> Identity ChatState
Lens' ChatState (Editor Text Name)
editor ((Editor Text Name -> Identity (Editor Text Name))
 -> ChatState -> Identity ChatState)
-> (Editor Text Name -> Editor Text Name) -> MH ()
forall s (m :: * -> *) a b.
MonadState s m =>
ASetter s s a b -> (a -> b) -> m ()
%= (TextZipper Text -> TextZipper Text)
-> Editor Text Name -> Editor Text Name
forall t n.
(TextZipper t -> TextZipper t) -> Editor t n -> Editor t n
applyEdit TextZipper Text -> TextZipper Text
gotoHome
  , KeyEvent -> Text -> MH () -> KeyEventHandler
mkKb KeyEvent
EditorEndEvent
    Text
"Move the cursor to the end of the input" (MH () -> KeyEventHandler) -> MH () -> KeyEventHandler
forall a b. (a -> b) -> a -> b
$ do
    (Editor Text Name -> Identity (Editor Text Name))
-> ChatState -> Identity ChatState
Lens' ChatState (Editor Text Name)
editor ((Editor Text Name -> Identity (Editor Text Name))
 -> ChatState -> Identity ChatState)
-> (Editor Text Name -> Editor Text Name) -> MH ()
forall s (m :: * -> *) a b.
MonadState s m =>
ASetter s s a b -> (a -> b) -> m ()
%= (TextZipper Text -> TextZipper Text)
-> Editor Text Name -> Editor Text Name
forall t n.
(TextZipper t -> TextZipper t) -> Editor t n -> Editor t n
applyEdit TextZipper Text -> TextZipper Text
gotoEnd
  , KeyEvent -> Text -> MH () -> KeyEventHandler
mkKb KeyEvent
EditorKillToEolEvent
    Text
"Kill the line to the right of the current position and copy it" (MH () -> KeyEventHandler) -> MH () -> KeyEventHandler
forall a b. (a -> b) -> a -> b
$ do
      TextZipper Text
z <- Getting (TextZipper Text) ChatState (TextZipper Text)
-> MH (TextZipper Text)
forall s (m :: * -> *) a. MonadState s m => Getting a s a -> m a
use ((Editor Text Name -> Const (TextZipper Text) (Editor Text Name))
-> ChatState -> Const (TextZipper Text) ChatState
Lens' ChatState (Editor Text Name)
editor((Editor Text Name -> Const (TextZipper Text) (Editor Text Name))
 -> ChatState -> Const (TextZipper Text) ChatState)
-> ((TextZipper Text -> Const (TextZipper Text) (TextZipper Text))
    -> Editor Text Name -> Const (TextZipper Text) (Editor Text Name))
-> Getting (TextZipper Text) ChatState (TextZipper Text)
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(TextZipper Text -> Const (TextZipper Text) (TextZipper Text))
-> Editor Text Name -> Const (TextZipper Text) (Editor Text Name)
forall t1 n t2.
Lens (Editor t1 n) (Editor t2 n) (TextZipper t1) (TextZipper t2)
editContentsL)
      let restOfLine :: Text
restOfLine = TextZipper Text -> Text
forall a. Monoid a => TextZipper a -> a
Z.currentLine (TextZipper Text -> TextZipper Text
forall a. Monoid a => TextZipper a -> TextZipper a
Z.killToBOL TextZipper Text
z)
      (GlobalEditState -> Identity GlobalEditState)
-> ChatState -> Identity ChatState
Lens' ChatState GlobalEditState
csGlobalEditState((GlobalEditState -> Identity GlobalEditState)
 -> ChatState -> Identity ChatState)
-> ((Text -> Identity Text)
    -> GlobalEditState -> Identity GlobalEditState)
-> (Text -> Identity Text)
-> ChatState
-> Identity ChatState
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(Text -> Identity Text)
-> GlobalEditState -> Identity GlobalEditState
Lens' GlobalEditState Text
gedYankBuffer ((Text -> Identity Text) -> ChatState -> Identity ChatState)
-> Text -> MH ()
forall s (m :: * -> *) a b.
MonadState s m =>
ASetter s s a b -> b -> m ()
.= Text
restOfLine
      (Editor Text Name -> Identity (Editor Text Name))
-> ChatState -> Identity ChatState
Lens' ChatState (Editor Text Name)
editor ((Editor Text Name -> Identity (Editor Text Name))
 -> ChatState -> Identity ChatState)
-> (Editor Text Name -> Editor Text Name) -> MH ()
forall s (m :: * -> *) a b.
MonadState s m =>
ASetter s s a b -> (a -> b) -> m ()
%= (TextZipper Text -> TextZipper Text)
-> Editor Text Name -> Editor Text Name
forall t n.
(TextZipper t -> TextZipper t) -> Editor t n -> Editor t n
applyEdit TextZipper Text -> TextZipper Text
forall a. Monoid a => TextZipper a -> TextZipper a
Z.killToEOL
  , KeyEvent -> Text -> MH () -> KeyEventHandler
mkKb KeyEvent
EditorYankEvent
    Text
"Paste the current buffer contents at the cursor" (MH () -> KeyEventHandler) -> MH () -> KeyEventHandler
forall a b. (a -> b) -> a -> b
$ do
        Text
buf <- Getting Text ChatState Text -> MH Text
forall s (m :: * -> *) a. MonadState s m => Getting a s a -> m a
use ((GlobalEditState -> Const Text GlobalEditState)
-> ChatState -> Const Text ChatState
Lens' ChatState GlobalEditState
csGlobalEditState((GlobalEditState -> Const Text GlobalEditState)
 -> ChatState -> Const Text ChatState)
-> ((Text -> Const Text Text)
    -> GlobalEditState -> Const Text GlobalEditState)
-> Getting Text ChatState Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(Text -> Const Text Text)
-> GlobalEditState -> Const Text GlobalEditState
Lens' GlobalEditState Text
gedYankBuffer)
        (Editor Text Name -> Identity (Editor Text Name))
-> ChatState -> Identity ChatState
Lens' ChatState (Editor Text Name)
editor ((Editor Text Name -> Identity (Editor Text Name))
 -> ChatState -> Identity ChatState)
-> (Editor Text Name -> Editor Text Name) -> MH ()
forall s (m :: * -> *) a b.
MonadState s m =>
ASetter s s a b -> (a -> b) -> m ()
%= (TextZipper Text -> TextZipper Text)
-> Editor Text Name -> Editor Text Name
forall t n.
(TextZipper t -> TextZipper t) -> Editor t n -> Editor t n
applyEdit (Text -> TextZipper Text -> TextZipper Text
forall a. Monoid a => a -> TextZipper a -> TextZipper a
Z.insertMany Text
buf)
  ]

getEditorContent :: Lens' ChatState (EditState Name) -> MH Text
getEditorContent :: Lens' ChatState (EditState Name) -> MH Text
getEditorContent Lens' ChatState (EditState Name)
which = do
    Editor Text Name
cmdLine <- 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 ((EditState Name -> Const (Editor Text Name) (EditState Name))
-> ChatState -> Const (Editor Text Name) ChatState
Lens' ChatState (EditState Name)
which((EditState Name -> Const (Editor Text Name) (EditState Name))
 -> ChatState -> Const (Editor Text Name) ChatState)
-> ((Editor Text Name
     -> Const (Editor Text Name) (Editor Text Name))
    -> EditState Name -> Const (Editor Text Name) (EditState Name))
-> Getting (Editor Text Name) ChatState (Editor Text Name)
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(Editor Text Name -> Const (Editor Text Name) (Editor Text Name))
-> EditState Name -> Const (Editor Text Name) (EditState Name)
forall n. Lens' (EditState n) (Editor Text n)
esEditor)
    let (Text
line, [Text]
rest) = case Editor Text Name -> [Text]
forall t n. Monoid t => Editor t n -> [t]
getEditContents Editor Text Name
cmdLine of
            (Text
a:[Text]
as) -> (Text
a, [Text]
as)
            [Text]
_ -> String -> (Text, [Text])
forall a. HasCallStack => String -> a
error String
"BUG: getEditorContent: got empty edit contents"
    Text -> MH Text
forall (m :: * -> *) a. Monad m => a -> m a
return (Text -> MH Text) -> Text -> MH Text
forall a b. (a -> b) -> a -> b
$ Text -> [Text] -> Text
T.intercalate Text
"\n" ([Text] -> Text) -> [Text] -> Text
forall a b. (a -> b) -> a -> b
$ Text
line Text -> [Text] -> [Text]
forall a. a -> [a] -> [a]
: [Text]
rest

-- | Handle an input submission in the message editor.
--
-- This handles the specified input text as if it were user input for
-- the specified channel. This means that if the specified input text
-- contains a command ("/...") then it is executed as normal. Otherwise
-- the text is sent as a message to the specified channel.
--
-- However, this function assumes that the message editor is the
-- *source* of the text, so it also takes care of clearing the editor,
-- resetting the edit mode, updating the input history for the specified
-- channel, etc.
handleInputSubmission :: Lens' ChatState (EditState Name)
                      -> Text
                      -> MH ()
handleInputSubmission :: Lens' ChatState (EditState Name) -> Text -> MH ()
handleInputSubmission Lens' ChatState (EditState Name)
editWhich Text
content = do
    ChannelId
cId <- Getting ChannelId ChatState ChannelId -> MH ChannelId
forall s (m :: * -> *) a. MonadState s m => Getting a s a -> m a
use ((EditState Name -> Const ChannelId (EditState Name))
-> ChatState -> Const ChannelId ChatState
Lens' ChatState (EditState Name)
editWhich((EditState Name -> Const ChannelId (EditState Name))
 -> ChatState -> Const ChannelId ChatState)
-> ((ChannelId -> Const ChannelId ChannelId)
    -> EditState Name -> Const ChannelId (EditState Name))
-> Getting ChannelId ChatState ChannelId
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(ChannelId -> Const ChannelId ChannelId)
-> EditState Name -> Const ChannelId (EditState Name)
forall n. Lens' (EditState n) ChannelId
esChannelId)

    -- We clean up before dispatching the command or sending the message
    -- since otherwise the command could change the state and then doing
    -- cleanup afterwards could clean up the wrong things.
    (EditState Name -> Identity (EditState Name))
-> ChatState -> Identity ChatState
Lens' ChatState (EditState Name)
editWhich((EditState Name -> Identity (EditState Name))
 -> ChatState -> Identity ChatState)
-> ((Editor Text Name -> Identity (Editor Text Name))
    -> EditState Name -> Identity (EditState Name))
-> (Editor Text Name -> Identity (Editor Text Name))
-> ChatState
-> Identity ChatState
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(Editor Text Name -> Identity (Editor Text Name))
-> EditState Name -> Identity (EditState Name)
forall n. Lens' (EditState n) (Editor Text n)
esEditor ((Editor Text Name -> Identity (Editor Text Name))
 -> ChatState -> Identity ChatState)
-> (Editor Text Name -> Editor Text Name) -> MH ()
forall s (m :: * -> *) a b.
MonadState s m =>
ASetter s s a b -> (a -> b) -> m ()
%= (TextZipper Text -> TextZipper Text)
-> Editor Text Name -> Editor Text Name
forall t n.
(TextZipper t -> TextZipper t) -> Editor t n -> Editor t n
applyEdit TextZipper Text -> TextZipper Text
forall a. Monoid a => TextZipper a -> TextZipper a
Z.clearZipper
    (EditState Name -> Identity (EditState Name))
-> ChatState -> Identity ChatState
Lens' ChatState (EditState Name)
editWhich((EditState Name -> Identity (EditState Name))
 -> ChatState -> Identity ChatState)
-> ((Maybe Int -> Identity (Maybe Int))
    -> EditState Name -> Identity (EditState Name))
-> (Maybe Int -> Identity (Maybe Int))
-> ChatState
-> Identity ChatState
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(EphemeralEditState -> Identity EphemeralEditState)
-> EditState Name -> Identity (EditState Name)
forall n. Lens' (EditState n) EphemeralEditState
esEphemeral((EphemeralEditState -> Identity EphemeralEditState)
 -> EditState Name -> Identity (EditState Name))
-> ((Maybe Int -> Identity (Maybe Int))
    -> EphemeralEditState -> Identity EphemeralEditState)
-> (Maybe Int -> Identity (Maybe Int))
-> EditState Name
-> Identity (EditState Name)
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(Maybe Int -> Identity (Maybe Int))
-> EphemeralEditState -> Identity EphemeralEditState
Lens' EphemeralEditState (Maybe Int)
eesInputHistoryPosition ((Maybe Int -> Identity (Maybe Int))
 -> ChatState -> Identity ChatState)
-> Maybe Int -> MH ()
forall s (m :: * -> *) a b.
MonadState s m =>
ASetter s s a b -> b -> m ()
.= Maybe Int
forall a. Maybe a
Nothing

    (InputHistory -> Identity InputHistory)
-> ChatState -> Identity ChatState
Lens' ChatState InputHistory
csInputHistory ((InputHistory -> Identity InputHistory)
 -> ChatState -> Identity ChatState)
-> (InputHistory -> InputHistory) -> MH ()
forall s (m :: * -> *) a b.
MonadState s m =>
ASetter s s a b -> (a -> b) -> m ()
%= Text -> ChannelId -> InputHistory -> InputHistory
addHistoryEntry Text
content ChannelId
cId

    case Text -> Maybe (Char, Text)
T.uncons Text
content of
      Just (Char
'/', Text
cmd) -> do
          TeamId
tId <- do
              Maybe TeamId
mTid <- Getting (Maybe TeamId) ChatState (Maybe TeamId)
-> MH (Maybe TeamId)
forall s (m :: * -> *) a. MonadState s m => Getting a s a -> m a
use ((EditState Name -> Const (Maybe TeamId) (EditState Name))
-> ChatState -> Const (Maybe TeamId) ChatState
Lens' ChatState (EditState Name)
editWhich((EditState Name -> Const (Maybe TeamId) (EditState Name))
 -> ChatState -> Const (Maybe TeamId) ChatState)
-> ((Maybe TeamId -> Const (Maybe TeamId) (Maybe TeamId))
    -> EditState Name -> Const (Maybe TeamId) (EditState Name))
-> Getting (Maybe TeamId) ChatState (Maybe TeamId)
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(Maybe TeamId -> Const (Maybe TeamId) (Maybe TeamId))
-> EditState Name -> Const (Maybe TeamId) (EditState Name)
forall n. Lens' (EditState n) (Maybe TeamId)
esTeamId)
              Just TeamId
curTid <- Getting (Maybe TeamId) ChatState (Maybe TeamId)
-> MH (Maybe TeamId)
forall s (m :: * -> *) a. MonadState s m => Getting a s a -> m a
use Getting (Maybe TeamId) ChatState (Maybe TeamId)
SimpleGetter ChatState (Maybe TeamId)
csCurrentTeamId
              TeamId -> MH TeamId
forall (m :: * -> *) a. Monad m => a -> m a
return (TeamId -> MH TeamId) -> TeamId -> MH TeamId
forall a b. (a -> b) -> a -> b
$ TeamId -> Maybe TeamId -> TeamId
forall a. a -> Maybe a -> a
fromMaybe TeamId
curTid Maybe TeamId
mTid
          TeamId -> Text -> MH ()
dispatchCommand TeamId
tId Text
cmd
      Maybe (Char, Text)
_ -> do
          Vector AttachmentData
attachments <- Getting (Vector AttachmentData) ChatState (Vector AttachmentData)
-> MH (Vector AttachmentData)
forall s (m :: * -> *) a. MonadState s m => Getting a s a -> m a
use ((EditState Name -> Const (Vector AttachmentData) (EditState Name))
-> ChatState -> Const (Vector AttachmentData) ChatState
Lens' ChatState (EditState Name)
editWhich((EditState Name -> Const (Vector AttachmentData) (EditState Name))
 -> ChatState -> Const (Vector AttachmentData) ChatState)
-> ((Vector AttachmentData
     -> Const (Vector AttachmentData) (Vector AttachmentData))
    -> EditState Name
    -> Const (Vector AttachmentData) (EditState Name))
-> Getting
     (Vector AttachmentData) ChatState (Vector AttachmentData)
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(List Name AttachmentData
 -> Const (Vector AttachmentData) (List Name AttachmentData))
-> EditState Name -> Const (Vector AttachmentData) (EditState Name)
forall n. Lens' (EditState n) (List n AttachmentData)
esAttachmentList((List Name AttachmentData
  -> Const (Vector AttachmentData) (List Name AttachmentData))
 -> EditState Name
 -> Const (Vector AttachmentData) (EditState Name))
-> ((Vector AttachmentData
     -> Const (Vector AttachmentData) (Vector AttachmentData))
    -> List Name AttachmentData
    -> Const (Vector AttachmentData) (List Name AttachmentData))
-> (Vector AttachmentData
    -> Const (Vector AttachmentData) (Vector AttachmentData))
-> EditState Name
-> Const (Vector AttachmentData) (EditState Name)
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(Vector AttachmentData
 -> Const (Vector AttachmentData) (Vector AttachmentData))
-> List Name AttachmentData
-> Const (Vector AttachmentData) (List Name AttachmentData)
forall n (t1 :: * -> *) e1 (t2 :: * -> *) e2.
Lens (GenericList n t1 e1) (GenericList n t2 e2) (t1 e1) (t2 e2)
L.listElementsL)
          EditMode
mode <- Getting EditMode ChatState EditMode -> MH EditMode
forall s (m :: * -> *) a. MonadState s m => Getting a s a -> m a
use ((EditState Name -> Const EditMode (EditState Name))
-> ChatState -> Const EditMode ChatState
Lens' ChatState (EditState Name)
editWhich((EditState Name -> Const EditMode (EditState Name))
 -> ChatState -> Const EditMode ChatState)
-> ((EditMode -> Const EditMode EditMode)
    -> EditState Name -> Const EditMode (EditState Name))
-> Getting EditMode ChatState EditMode
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(EditMode -> Const EditMode EditMode)
-> EditState Name -> Const EditMode (EditState Name)
forall n. Lens' (EditState n) EditMode
esEditMode)
          ChannelId -> EditMode -> Text -> [AttachmentData] -> MH ()
sendMessage ChannelId
cId EditMode
mode Text
content ([AttachmentData] -> MH ()) -> [AttachmentData] -> MH ()
forall a b. (a -> b) -> a -> b
$ Vector AttachmentData -> [AttachmentData]
forall (t :: * -> *) a. Foldable t => t a -> [a]
F.toList Vector AttachmentData
attachments

          -- Empty the attachment list only if a mesage is
          -- actually sent, since it's possible to /attach a
          -- file before actually sending the message
          Lens' ChatState (EditState Name) -> MH ()
resetAttachmentList Lens' ChatState (EditState Name)
editWhich

    -- Reset the autocomplete UI
    Traversal' ChatState (EditState Name) -> MH ()
forall n. Traversal' ChatState (EditState n) -> MH ()
resetAutocomplete Lens' ChatState (EditState Name)
Traversal' ChatState (EditState Name)
editWhich

    -- Reset the edit mode *after* handling the input so that the input
    -- handler can tell whether we're editing, replying, etc.
    EditMode
resetEditMode <- Getting EditMode ChatState EditMode -> MH EditMode
forall s (m :: * -> *) a. MonadState s m => Getting a s a -> m a
use ((EditState Name -> Const EditMode (EditState Name))
-> ChatState -> Const EditMode ChatState
Lens' ChatState (EditState Name)
editWhich((EditState Name -> Const EditMode (EditState Name))
 -> ChatState -> Const EditMode ChatState)
-> ((EditMode -> Const EditMode EditMode)
    -> EditState Name -> Const EditMode (EditState Name))
-> Getting EditMode ChatState EditMode
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(EditMode -> Const EditMode EditMode)
-> EditState Name -> Const EditMode (EditState Name)
forall n. Lens' (EditState n) EditMode
esResetEditMode)
    (EditState Name -> Identity (EditState Name))
-> ChatState -> Identity ChatState
Lens' ChatState (EditState Name)
editWhich((EditState Name -> Identity (EditState Name))
 -> ChatState -> Identity ChatState)
-> ((EditMode -> Identity EditMode)
    -> EditState Name -> Identity (EditState Name))
-> (EditMode -> Identity EditMode)
-> ChatState
-> Identity ChatState
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(EditMode -> Identity EditMode)
-> EditState Name -> Identity (EditState Name)
forall n. Lens' (EditState n) EditMode
esEditMode ((EditMode -> Identity EditMode)
 -> ChatState -> Identity ChatState)
-> EditMode -> MH ()
forall s (m :: * -> *) a b.
MonadState s m =>
ASetter s s a b -> b -> m ()
.= EditMode
resetEditMode

closingPunctuationMarks :: String
closingPunctuationMarks :: String
closingPunctuationMarks = String
".,'\";:)]!?"

isSmartClosingPunctuation :: Event -> Bool
isSmartClosingPunctuation :: Event -> Bool
isSmartClosingPunctuation (EvKey (KChar Char
c) []) = Char
c Char -> String -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` String
closingPunctuationMarks
isSmartClosingPunctuation Event
_ = Bool
False

handleEditingInput :: Lens' ChatState (EditState Name)
                   -> Event
                   -> MH ()
handleEditingInput :: Lens' ChatState (EditState Name) -> Event -> MH ()
handleEditingInput Lens' ChatState (EditState Name)
which Event
e = do
    ChannelId
cId <- Getting ChannelId ChatState ChannelId -> MH ChannelId
forall s (m :: * -> *) a. MonadState s m => Getting a s a -> m a
use ((EditState Name -> Const ChannelId (EditState Name))
-> ChatState -> Const ChannelId ChatState
Lens' ChatState (EditState Name)
which((EditState Name -> Const ChannelId (EditState Name))
 -> ChatState -> Const ChannelId ChatState)
-> ((ChannelId -> Const ChannelId ChannelId)
    -> EditState Name -> Const ChannelId (EditState Name))
-> Getting ChannelId ChatState ChannelId
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(ChannelId -> Const ChannelId ChannelId)
-> EditState Name -> Const ChannelId (EditState Name)
forall n. Lens' (EditState n) ChannelId
esChannelId)

    -- Only handle input events to the editor if we permit editing:
    -- if multiline mode is off, or if there is only one line of text
    -- in the editor. This means we skip input this catch-all handler
    -- if we're *not* in multiline mode *and* there are multiple lines,
    -- i.e., we are showing the user the status message about the
    -- current editor state and editing is not permitted.

    -- Record the input line count before handling the editing event
    -- so we can tell whether the editing event changes the line count
    -- later.
    Int
beforeLineCount <- Getting Int ChatState Int -> MH Int
forall s (m :: * -> *) a. MonadState s m => Getting a s a -> m a
use ((EditState Name -> Const Int (EditState Name))
-> ChatState -> Const Int ChatState
Lens' ChatState (EditState Name)
which((EditState Name -> Const Int (EditState Name))
 -> ChatState -> Const Int ChatState)
-> ((Int -> Const Int Int)
    -> EditState Name -> Const Int (EditState Name))
-> Getting Int ChatState Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(Editor Text Name -> Const Int (Editor Text Name))
-> EditState Name -> Const Int (EditState Name)
forall n. Lens' (EditState n) (Editor Text n)
esEditor((Editor Text Name -> Const Int (Editor Text Name))
 -> EditState Name -> Const Int (EditState Name))
-> ((Int -> Const Int Int)
    -> Editor Text Name -> Const Int (Editor Text Name))
-> (Int -> Const Int Int)
-> EditState Name
-> Const Int (EditState Name)
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(Editor Text Name -> [Text])
-> SimpleGetter (Editor Text Name) [Text]
forall s a. (s -> a) -> SimpleGetter s a
to Editor Text Name -> [Text]
forall t n. Monoid t => Editor t n -> [t]
getEditContentsGetting Int (Editor Text Name) [Text]
-> ((Int -> Const Int Int) -> [Text] -> Const Int [Text])
-> (Int -> Const Int Int)
-> Editor Text Name
-> Const Int (Editor Text Name)
forall b c a. (b -> c) -> (a -> b) -> a -> c
.([Text] -> Int) -> SimpleGetter [Text] Int
forall s a. (s -> a) -> SimpleGetter s a
to [Text] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length)

    Bool
smartBacktick <- Getting Bool ChatState Bool -> MH Bool
forall s (m :: * -> *) a. MonadState s m => Getting a s a -> m a
use ((ChatResources -> Const Bool ChatResources)
-> ChatState -> Const Bool ChatState
Lens' ChatState ChatResources
csResources((ChatResources -> Const Bool ChatResources)
 -> ChatState -> Const Bool ChatState)
-> ((Bool -> Const Bool Bool)
    -> ChatResources -> Const Bool ChatResources)
-> Getting Bool ChatState Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(Config -> Const Bool Config)
-> ChatResources -> Const Bool ChatResources
Lens' ChatResources Config
crConfiguration((Config -> Const Bool Config)
 -> ChatResources -> Const Bool ChatResources)
-> ((Bool -> Const Bool Bool) -> Config -> Const Bool Config)
-> (Bool -> Const Bool Bool)
-> ChatResources
-> Const Bool ChatResources
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(Bool -> Const Bool Bool) -> Config -> Const Bool Config
Lens' Config Bool
configSmartBacktickL)
    let smartChars :: String
smartChars = String
"*`_"
    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
    (EditState Name -> Identity (EditState Name))
-> ChatState -> Identity ChatState
Lens' ChatState (EditState Name)
which((EditState Name -> Identity (EditState Name))
 -> ChatState -> Identity ChatState)
-> ((Maybe Int -> Identity (Maybe Int))
    -> EditState Name -> Identity (EditState Name))
-> (Maybe Int -> Identity (Maybe Int))
-> ChatState
-> Identity ChatState
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(EphemeralEditState -> Identity EphemeralEditState)
-> EditState Name -> Identity (EditState Name)
forall n. Lens' (EditState n) EphemeralEditState
esEphemeral((EphemeralEditState -> Identity EphemeralEditState)
 -> EditState Name -> Identity (EditState Name))
-> ((Maybe Int -> Identity (Maybe Int))
    -> EphemeralEditState -> Identity EphemeralEditState)
-> (Maybe Int -> Identity (Maybe Int))
-> EditState Name
-> Identity (EditState Name)
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(Maybe Int -> Identity (Maybe Int))
-> EphemeralEditState -> Identity EphemeralEditState
Lens' EphemeralEditState (Maybe Int)
eesInputHistoryPosition ((Maybe Int -> Identity (Maybe Int))
 -> ChatState -> Identity ChatState)
-> Maybe Int -> MH ()
forall s (m :: * -> *) a b.
MonadState s m =>
ASetter s s a b -> b -> m ()
.= Maybe Int
forall a. Maybe a
Nothing

    Bool
smartEditing <- Getting Bool ChatState Bool -> MH Bool
forall s (m :: * -> *) a. MonadState s m => Getting a s a -> m a
use ((ChatResources -> Const Bool ChatResources)
-> ChatState -> Const Bool ChatState
Lens' ChatState ChatResources
csResources((ChatResources -> Const Bool ChatResources)
 -> ChatState -> Const Bool ChatState)
-> ((Bool -> Const Bool Bool)
    -> ChatResources -> Const Bool ChatResources)
-> Getting Bool ChatState Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(Config -> Const Bool Config)
-> ChatResources -> Const Bool ChatResources
Lens' ChatResources Config
crConfiguration((Config -> Const Bool Config)
 -> ChatResources -> Const Bool ChatResources)
-> ((Bool -> Const Bool Bool) -> Config -> Const Bool Config)
-> (Bool -> Const Bool Bool)
-> ChatResources
-> Const Bool ChatResources
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(Bool -> Const Bool Bool) -> Config -> Const Bool Config
Lens' Config Bool
configSmartEditingL)
    Bool
justCompleted <- Getting Bool ChatState Bool -> MH Bool
forall s (m :: * -> *) a. MonadState s m => Getting a s a -> m a
use ((EditState Name -> Const Bool (EditState Name))
-> ChatState -> Const Bool ChatState
Lens' ChatState (EditState Name)
which((EditState Name -> Const Bool (EditState Name))
 -> ChatState -> Const Bool ChatState)
-> ((Bool -> Const Bool Bool)
    -> EditState Name -> Const Bool (EditState Name))
-> Getting Bool ChatState Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(Bool -> Const Bool Bool)
-> EditState Name -> Const Bool (EditState Name)
forall n. Lens' (EditState n) Bool
esJustCompleted)

    Config
conf <- Getting Config ChatState Config -> MH Config
forall s (m :: * -> *) a. MonadState s m => Getting a s a -> m a
use ((ChatResources -> Const Config ChatResources)
-> ChatState -> Const Config ChatState
Lens' ChatState ChatResources
csResources((ChatResources -> Const Config ChatResources)
 -> ChatState -> Const Config ChatState)
-> ((Config -> Const Config Config)
    -> ChatResources -> Const Config ChatResources)
-> Getting Config ChatState Config
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(Config -> Const Config Config)
-> ChatResources -> Const Config ChatResources
Lens' ChatResources Config
crConfiguration)
    let keyMap :: KeyHandlerMap
keyMap = Lens' ChatState (Editor Text Name) -> KeyConfig -> KeyHandlerMap
editingKeybindings ((EditState Name -> f (EditState Name)) -> ChatState -> f ChatState
Lens' ChatState (EditState Name)
which((EditState Name -> f (EditState Name))
 -> ChatState -> f ChatState)
-> ((Editor Text Name -> f (Editor Text Name))
    -> EditState Name -> f (EditState Name))
-> (Editor Text Name -> f (Editor Text Name))
-> ChatState
-> f ChatState
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(Editor Text Name -> f (Editor Text Name))
-> EditState Name -> f (EditState Name)
forall n. Lens' (EditState n) (Editor Text n)
esEditor) (Config -> KeyConfig
configUserKeys Config
conf)
    case Event -> KeyHandlerMap -> Maybe KeyHandler
lookupKeybinding Event
e KeyHandlerMap
keyMap of
      Just KeyHandler
kb | ChatState -> Lens' ChatState (EditState Name) -> Bool
editingPermitted ChatState
st Lens' ChatState (EditState Name)
which -> (EventHandler -> MH ()
ehAction (EventHandler -> MH ()) -> EventHandler -> MH ()
forall a b. (a -> b) -> a -> b
$ KeyEventHandler -> EventHandler
kehHandler (KeyEventHandler -> EventHandler)
-> KeyEventHandler -> EventHandler
forall a b. (a -> b) -> a -> b
$ KeyHandler -> KeyEventHandler
khHandler KeyHandler
kb)
      Maybe KeyHandler
_ -> do
        case Event
e of
          -- Not editing; backspace here means cancel multi-line message
          -- composition
          EvKey Key
KBS [] | (Bool -> Bool
not (Bool -> Bool) -> Bool -> Bool
forall a b. (a -> b) -> a -> b
$ ChatState -> Lens' ChatState (EditState Name) -> Bool
editingPermitted ChatState
st Lens' ChatState (EditState Name)
which) -> do
            (EditState Name -> Identity (EditState Name))
-> ChatState -> Identity ChatState
Lens' ChatState (EditState Name)
which((EditState Name -> Identity (EditState Name))
 -> ChatState -> Identity ChatState)
-> ((Editor Text Name -> Identity (Editor Text Name))
    -> EditState Name -> Identity (EditState Name))
-> (Editor Text Name -> Identity (Editor Text Name))
-> ChatState
-> Identity ChatState
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(Editor Text Name -> Identity (Editor Text Name))
-> EditState Name -> Identity (EditState Name)
forall n. Lens' (EditState n) (Editor Text n)
esEditor ((Editor Text Name -> Identity (Editor Text Name))
 -> ChatState -> Identity ChatState)
-> (Editor Text Name -> Editor Text Name) -> MH ()
forall s (m :: * -> *) a b.
MonadState s m =>
ASetter s s a b -> (a -> b) -> m ()
%= (TextZipper Text -> TextZipper Text)
-> Editor Text Name -> Editor Text Name
forall t n.
(TextZipper t -> TextZipper t) -> Editor t n -> Editor t n
applyEdit TextZipper Text -> TextZipper Text
forall a. Monoid a => TextZipper a -> TextZipper a
Z.clearZipper
            EventM Name () -> MH ()
forall a. EventM Name a -> MH a
mh EventM Name ()
forall n. Ord n => EventM n ()
invalidateCache

          -- Backspace in editing mode with smart pair insertion means
          -- smart pair removal when possible
          EvKey Key
KBS [] | ChatState -> Lens' ChatState (EditState Name) -> Bool
editingPermitted ChatState
st Lens' ChatState (EditState Name)
which Bool -> Bool -> Bool
&& Bool
smartBacktick ->
              let backspace :: MH ()
backspace = (EditState Name -> Identity (EditState Name))
-> ChatState -> Identity ChatState
Lens' ChatState (EditState Name)
which((EditState Name -> Identity (EditState Name))
 -> ChatState -> Identity ChatState)
-> ((Editor Text Name -> Identity (Editor Text Name))
    -> EditState Name -> Identity (EditState Name))
-> (Editor Text Name -> Identity (Editor Text Name))
-> ChatState
-> Identity ChatState
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(Editor Text Name -> Identity (Editor Text Name))
-> EditState Name -> Identity (EditState Name)
forall n. Lens' (EditState n) (Editor Text n)
esEditor ((Editor Text Name -> Identity (Editor Text Name))
 -> ChatState -> Identity ChatState)
-> (Editor Text Name -> Editor Text Name) -> MH ()
forall s (m :: * -> *) a b.
MonadState s m =>
ASetter s s a b -> (a -> b) -> m ()
%= (TextZipper Text -> TextZipper Text)
-> Editor Text Name -> Editor Text Name
forall t n.
(TextZipper t -> TextZipper t) -> Editor t n -> Editor t n
applyEdit TextZipper Text -> TextZipper Text
forall a. (Eq a, Monoid a) => TextZipper a -> TextZipper a
Z.deletePrevChar
              in case String -> Editor Text Name -> Maybe Char
forall a. String -> Editor Text a -> Maybe Char
cursorAtOneOf String
smartChars (ChatState
stChatState
-> Getting (Editor Text Name) ChatState (Editor Text Name)
-> Editor Text Name
forall s a. s -> Getting a s a -> a
^.(EditState Name -> Const (Editor Text Name) (EditState Name))
-> ChatState -> Const (Editor Text Name) ChatState
Lens' ChatState (EditState Name)
which((EditState Name -> Const (Editor Text Name) (EditState Name))
 -> ChatState -> Const (Editor Text Name) ChatState)
-> ((Editor Text Name
     -> Const (Editor Text Name) (Editor Text Name))
    -> EditState Name -> Const (Editor Text Name) (EditState Name))
-> Getting (Editor Text Name) ChatState (Editor Text Name)
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(Editor Text Name -> Const (Editor Text Name) (Editor Text Name))
-> EditState Name -> Const (Editor Text Name) (EditState Name)
forall n. Lens' (EditState n) (Editor Text n)
esEditor) of
                  Maybe Char
Nothing -> MH ()
backspace
                  Just Char
ch ->
                      -- Smart char removal:
                      if | (Char -> Editor Text Name -> Bool
forall a. Char -> Editor Text a -> Bool
cursorAtChar Char
ch (Editor Text Name -> Bool) -> Editor Text Name -> Bool
forall a b. (a -> b) -> a -> b
$ (TextZipper Text -> TextZipper Text)
-> Editor Text Name -> Editor Text Name
forall t n.
(TextZipper t -> TextZipper t) -> Editor t n -> Editor t n
applyEdit TextZipper Text -> TextZipper Text
forall a. Monoid a => TextZipper a -> TextZipper a
Z.moveLeft (Editor Text Name -> Editor Text Name)
-> Editor Text Name -> Editor Text Name
forall a b. (a -> b) -> a -> b
$ ChatState
stChatState
-> Getting (Editor Text Name) ChatState (Editor Text Name)
-> Editor Text Name
forall s a. s -> Getting a s a -> a
^.(EditState Name -> Const (Editor Text Name) (EditState Name))
-> ChatState -> Const (Editor Text Name) ChatState
Lens' ChatState (EditState Name)
which((EditState Name -> Const (Editor Text Name) (EditState Name))
 -> ChatState -> Const (Editor Text Name) ChatState)
-> ((Editor Text Name
     -> Const (Editor Text Name) (Editor Text Name))
    -> EditState Name -> Const (Editor Text Name) (EditState Name))
-> Getting (Editor Text Name) ChatState (Editor Text Name)
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(Editor Text Name -> Const (Editor Text Name) (Editor Text Name))
-> EditState Name -> Const (Editor Text Name) (EditState Name)
forall n. Lens' (EditState n) (Editor Text n)
esEditor) Bool -> Bool -> Bool
&&
                           (Editor Text Name -> Bool
forall a. Editor Text a -> Bool
cursorIsAtEnd (Editor Text Name -> Bool) -> Editor Text Name -> Bool
forall a b. (a -> b) -> a -> b
$ (TextZipper Text -> TextZipper Text)
-> Editor Text Name -> Editor Text Name
forall t n.
(TextZipper t -> TextZipper t) -> Editor t n -> Editor t n
applyEdit TextZipper Text -> TextZipper Text
forall a. Monoid a => TextZipper a -> TextZipper a
Z.moveRight (Editor Text Name -> Editor Text Name)
-> Editor Text Name -> Editor Text Name
forall a b. (a -> b) -> a -> b
$ ChatState
stChatState
-> Getting (Editor Text Name) ChatState (Editor Text Name)
-> Editor Text Name
forall s a. s -> Getting a s a -> a
^.(EditState Name -> Const (Editor Text Name) (EditState Name))
-> ChatState -> Const (Editor Text Name) ChatState
Lens' ChatState (EditState Name)
which((EditState Name -> Const (Editor Text Name) (EditState Name))
 -> ChatState -> Const (Editor Text Name) ChatState)
-> ((Editor Text Name
     -> Const (Editor Text Name) (Editor Text Name))
    -> EditState Name -> Const (Editor Text Name) (EditState Name))
-> Getting (Editor Text Name) ChatState (Editor Text Name)
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(Editor Text Name -> Const (Editor Text Name) (Editor Text Name))
-> EditState Name -> Const (Editor Text Name) (EditState Name)
forall n. Lens' (EditState n) (Editor Text n)
esEditor) ->
                             (EditState Name -> Identity (EditState Name))
-> ChatState -> Identity ChatState
Lens' ChatState (EditState Name)
which((EditState Name -> Identity (EditState Name))
 -> ChatState -> Identity ChatState)
-> ((Editor Text Name -> Identity (Editor Text Name))
    -> EditState Name -> Identity (EditState Name))
-> (Editor Text Name -> Identity (Editor Text Name))
-> ChatState
-> Identity ChatState
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(Editor Text Name -> Identity (Editor Text Name))
-> EditState Name -> Identity (EditState Name)
forall n. Lens' (EditState n) (Editor Text n)
esEditor ((Editor Text Name -> Identity (Editor Text Name))
 -> ChatState -> Identity ChatState)
-> (Editor Text Name -> Editor Text Name) -> MH ()
forall s (m :: * -> *) a b.
MonadState s m =>
ASetter s s a b -> (a -> b) -> m ()
%= (TextZipper Text -> TextZipper Text)
-> Editor Text Name -> Editor Text Name
forall t n.
(TextZipper t -> TextZipper t) -> Editor t n -> Editor t n
applyEdit (TextZipper Text -> TextZipper Text
forall a. Monoid a => TextZipper a -> TextZipper a
Z.deleteChar (TextZipper Text -> TextZipper Text)
-> (TextZipper Text -> TextZipper Text)
-> TextZipper Text
-> TextZipper Text
forall k (cat :: k -> k -> *) (a :: k) (b :: k) (c :: k).
Category cat =>
cat a b -> cat b c -> cat a c
>>> TextZipper Text -> TextZipper Text
forall a. (Eq a, Monoid a) => TextZipper a -> TextZipper a
Z.deletePrevChar)
                         | Bool
otherwise -> MH ()
backspace

          EvKey (KChar Char
ch) []
            | ChatState -> Lens' ChatState (EditState Name) -> Bool
editingPermitted ChatState
st Lens' ChatState (EditState Name)
which Bool -> Bool -> Bool
&& Bool
smartBacktick Bool -> Bool -> Bool
&& Char
ch Char -> String -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` String
smartChars ->
              -- Smart char insertion:
              let doInsertChar :: MH ()
doInsertChar = do
                    (EditState Name -> Identity (EditState Name))
-> ChatState -> Identity ChatState
Lens' ChatState (EditState Name)
which((EditState Name -> Identity (EditState Name))
 -> ChatState -> Identity ChatState)
-> ((Editor Text Name -> Identity (Editor Text Name))
    -> EditState Name -> Identity (EditState Name))
-> (Editor Text Name -> Identity (Editor Text Name))
-> ChatState
-> Identity ChatState
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(Editor Text Name -> Identity (Editor Text Name))
-> EditState Name -> Identity (EditState Name)
forall n. Lens' (EditState n) (Editor Text n)
esEditor ((Editor Text Name -> Identity (Editor Text Name))
 -> ChatState -> Identity ChatState)
-> (Editor Text Name -> Editor Text Name) -> MH ()
forall s (m :: * -> *) a b.
MonadState s m =>
ASetter s s a b -> (a -> b) -> m ()
%= (TextZipper Text -> TextZipper Text)
-> Editor Text Name -> Editor Text Name
forall t n.
(TextZipper t -> TextZipper t) -> Editor t n -> Editor t n
applyEdit (Char -> TextZipper Text -> TextZipper Text
forall a. Monoid a => Char -> TextZipper a -> TextZipper a
Z.insertChar Char
ch)
                    Lens' ChatState (EditState Name) -> MH ()
sendUserTypingAction Lens' ChatState (EditState Name)
which
                  curLine :: Text
curLine = TextZipper Text -> Text
forall a. Monoid a => TextZipper a -> a
Z.currentLine (TextZipper Text -> Text) -> TextZipper Text -> Text
forall a b. (a -> b) -> a -> b
$ ChatState
stChatState
-> Getting (TextZipper Text) ChatState (TextZipper Text)
-> TextZipper Text
forall s a. s -> Getting a s a -> a
^.(EditState Name -> Const (TextZipper Text) (EditState Name))
-> ChatState -> Const (TextZipper Text) ChatState
Lens' ChatState (EditState Name)
which((EditState Name -> Const (TextZipper Text) (EditState Name))
 -> ChatState -> Const (TextZipper Text) ChatState)
-> ((TextZipper Text -> Const (TextZipper Text) (TextZipper Text))
    -> EditState Name -> Const (TextZipper Text) (EditState Name))
-> Getting (TextZipper Text) ChatState (TextZipper Text)
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(Editor Text Name -> Const (TextZipper Text) (Editor Text Name))
-> EditState Name -> Const (TextZipper Text) (EditState Name)
forall n. Lens' (EditState n) (Editor Text n)
esEditor((Editor Text Name -> Const (TextZipper Text) (Editor Text Name))
 -> EditState Name -> Const (TextZipper Text) (EditState Name))
-> ((TextZipper Text -> Const (TextZipper Text) (TextZipper Text))
    -> Editor Text Name -> Const (TextZipper Text) (Editor Text Name))
-> (TextZipper Text -> Const (TextZipper Text) (TextZipper Text))
-> EditState Name
-> Const (TextZipper Text) (EditState Name)
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(TextZipper Text -> Const (TextZipper Text) (TextZipper Text))
-> Editor Text Name -> Const (TextZipper Text) (Editor Text Name)
forall t1 n t2.
Lens (Editor t1 n) (Editor t2 n) (TextZipper t1) (TextZipper t2)
editContentsL
              -- First case: if the cursor is at the end of the current
              -- line and it contains "``" and the user entered a third
              -- "`", enable multi-line mode since they're likely typing
              -- a code block.
              in if | (Editor Text Name -> Bool
forall a. Editor Text a -> Bool
cursorIsAtEnd (Editor Text Name -> Bool) -> Editor Text Name -> Bool
forall a b. (a -> b) -> a -> b
$ ChatState
stChatState
-> Getting (Editor Text Name) ChatState (Editor Text Name)
-> Editor Text Name
forall s a. s -> Getting a s a -> a
^.(EditState Name -> Const (Editor Text Name) (EditState Name))
-> ChatState -> Const (Editor Text Name) ChatState
Lens' ChatState (EditState Name)
which((EditState Name -> Const (Editor Text Name) (EditState Name))
 -> ChatState -> Const (Editor Text Name) ChatState)
-> ((Editor Text Name
     -> Const (Editor Text Name) (Editor Text Name))
    -> EditState Name -> Const (Editor Text Name) (EditState Name))
-> Getting (Editor Text Name) ChatState (Editor Text Name)
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(Editor Text Name -> Const (Editor Text Name) (Editor Text Name))
-> EditState Name -> Const (Editor Text Name) (EditState Name)
forall n. Lens' (EditState n) (Editor Text n)
esEditor) Bool -> Bool -> Bool
&&
                         Text
curLine Text -> Text -> Bool
forall a. Eq a => a -> a -> Bool
== Text
"``" Bool -> Bool -> Bool
&&
                         Char
ch Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
'`' -> do
                        (EditState Name -> Identity (EditState Name))
-> ChatState -> Identity ChatState
Lens' ChatState (EditState Name)
which((EditState Name -> Identity (EditState Name))
 -> ChatState -> Identity ChatState)
-> ((Editor Text Name -> Identity (Editor Text Name))
    -> EditState Name -> Identity (EditState Name))
-> (Editor Text Name -> Identity (Editor Text Name))
-> ChatState
-> Identity ChatState
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(Editor Text Name -> Identity (Editor Text Name))
-> EditState Name -> Identity (EditState Name)
forall n. Lens' (EditState n) (Editor Text n)
esEditor ((Editor Text Name -> Identity (Editor Text Name))
 -> ChatState -> Identity ChatState)
-> (Editor Text Name -> Editor Text Name) -> MH ()
forall s (m :: * -> *) a b.
MonadState s m =>
ASetter s s a b -> (a -> b) -> m ()
%= (TextZipper Text -> TextZipper Text)
-> Editor Text Name -> Editor Text Name
forall t n.
(TextZipper t -> TextZipper t) -> Editor t n -> Editor t n
applyEdit (Text -> TextZipper Text -> TextZipper Text
forall a. Monoid a => a -> TextZipper a -> TextZipper a
Z.insertMany (Char -> Text
T.singleton Char
ch))
                        (EditState Name -> Identity (EditState Name))
-> ChatState -> Identity ChatState
Lens' ChatState (EditState Name)
which((EditState Name -> Identity (EditState Name))
 -> ChatState -> Identity ChatState)
-> ((Bool -> Identity Bool)
    -> EditState Name -> Identity (EditState Name))
-> (Bool -> Identity Bool)
-> ChatState
-> Identity ChatState
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(EphemeralEditState -> Identity EphemeralEditState)
-> EditState Name -> Identity (EditState Name)
forall n. Lens' (EditState n) EphemeralEditState
esEphemeral((EphemeralEditState -> Identity EphemeralEditState)
 -> EditState Name -> Identity (EditState Name))
-> ((Bool -> Identity Bool)
    -> EphemeralEditState -> Identity EphemeralEditState)
-> (Bool -> Identity Bool)
-> EditState Name
-> Identity (EditState Name)
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(Bool -> Identity Bool)
-> EphemeralEditState -> Identity EphemeralEditState
Lens' EphemeralEditState Bool
eesMultiline ((Bool -> Identity Bool) -> ChatState -> Identity ChatState)
-> Bool -> MH ()
forall s (m :: * -> *) a b.
MonadState s m =>
ASetter s s a b -> b -> m ()
.= Bool
True
                    -- Second case: user entered some smart character
                    -- (don't care which) on an empty line or at the end
                    -- of the line after whitespace, so enter a pair of
                    -- the smart chars and put the cursor between them.
                    | (Editor Text Name -> Bool
forall a. Editor Text a -> Bool
editorEmpty (Editor Text Name -> Bool) -> Editor Text Name -> Bool
forall a b. (a -> b) -> a -> b
$ ChatState
stChatState
-> Getting (Editor Text Name) ChatState (Editor Text Name)
-> Editor Text Name
forall s a. s -> Getting a s a -> a
^.(EditState Name -> Const (Editor Text Name) (EditState Name))
-> ChatState -> Const (Editor Text Name) ChatState
Lens' ChatState (EditState Name)
which((EditState Name -> Const (Editor Text Name) (EditState Name))
 -> ChatState -> Const (Editor Text Name) ChatState)
-> ((Editor Text Name
     -> Const (Editor Text Name) (Editor Text Name))
    -> EditState Name -> Const (Editor Text Name) (EditState Name))
-> Getting (Editor Text Name) ChatState (Editor Text Name)
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(Editor Text Name -> Const (Editor Text Name) (Editor Text Name))
-> EditState Name -> Const (Editor Text Name) (EditState Name)
forall n. Lens' (EditState n) (Editor Text n)
esEditor) Bool -> Bool -> Bool
||
                         ((Char -> Editor Text Name -> Bool
forall a. Char -> Editor Text a -> Bool
cursorAtChar Char
' ' ((TextZipper Text -> TextZipper Text)
-> Editor Text Name -> Editor Text Name
forall t n.
(TextZipper t -> TextZipper t) -> Editor t n -> Editor t n
applyEdit TextZipper Text -> TextZipper Text
forall a. Monoid a => TextZipper a -> TextZipper a
Z.moveLeft (Editor Text Name -> Editor Text Name)
-> Editor Text Name -> Editor Text Name
forall a b. (a -> b) -> a -> b
$ ChatState
stChatState
-> Getting (Editor Text Name) ChatState (Editor Text Name)
-> Editor Text Name
forall s a. s -> Getting a s a -> a
^.(EditState Name -> Const (Editor Text Name) (EditState Name))
-> ChatState -> Const (Editor Text Name) ChatState
Lens' ChatState (EditState Name)
which((EditState Name -> Const (Editor Text Name) (EditState Name))
 -> ChatState -> Const (Editor Text Name) ChatState)
-> ((Editor Text Name
     -> Const (Editor Text Name) (Editor Text Name))
    -> EditState Name -> Const (Editor Text Name) (EditState Name))
-> Getting (Editor Text Name) ChatState (Editor Text Name)
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(Editor Text Name -> Const (Editor Text Name) (Editor Text Name))
-> EditState Name -> Const (Editor Text Name) (EditState Name)
forall n. Lens' (EditState n) (Editor Text n)
esEditor)) Bool -> Bool -> Bool
&&
                          (Editor Text Name -> Bool
forall a. Editor Text a -> Bool
cursorIsAtEnd (Editor Text Name -> Bool) -> Editor Text Name -> Bool
forall a b. (a -> b) -> a -> b
$ ChatState
stChatState
-> Getting (Editor Text Name) ChatState (Editor Text Name)
-> Editor Text Name
forall s a. s -> Getting a s a -> a
^.(EditState Name -> Const (Editor Text Name) (EditState Name))
-> ChatState -> Const (Editor Text Name) ChatState
Lens' ChatState (EditState Name)
which((EditState Name -> Const (Editor Text Name) (EditState Name))
 -> ChatState -> Const (Editor Text Name) ChatState)
-> ((Editor Text Name
     -> Const (Editor Text Name) (Editor Text Name))
    -> EditState Name -> Const (Editor Text Name) (EditState Name))
-> Getting (Editor Text Name) ChatState (Editor Text Name)
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(Editor Text Name -> Const (Editor Text Name) (Editor Text Name))
-> EditState Name -> Const (Editor Text Name) (EditState Name)
forall n. Lens' (EditState n) (Editor Text n)
esEditor)) ->
                        (EditState Name -> Identity (EditState Name))
-> ChatState -> Identity ChatState
Lens' ChatState (EditState Name)
which((EditState Name -> Identity (EditState Name))
 -> ChatState -> Identity ChatState)
-> ((Editor Text Name -> Identity (Editor Text Name))
    -> EditState Name -> Identity (EditState Name))
-> (Editor Text Name -> Identity (Editor Text Name))
-> ChatState
-> Identity ChatState
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(Editor Text Name -> Identity (Editor Text Name))
-> EditState Name -> Identity (EditState Name)
forall n. Lens' (EditState n) (Editor Text n)
esEditor ((Editor Text Name -> Identity (Editor Text Name))
 -> ChatState -> Identity ChatState)
-> (Editor Text Name -> Editor Text Name) -> MH ()
forall s (m :: * -> *) a b.
MonadState s m =>
ASetter s s a b -> (a -> b) -> m ()
%= (TextZipper Text -> TextZipper Text)
-> Editor Text Name -> Editor Text Name
forall t n.
(TextZipper t -> TextZipper t) -> Editor t n -> Editor t n
applyEdit (Text -> TextZipper Text -> TextZipper Text
forall a. Monoid a => a -> TextZipper a -> TextZipper a
Z.insertMany (String -> Text
T.pack (String -> Text) -> String -> Text
forall a b. (a -> b) -> a -> b
$ Char
chChar -> String -> String
forall a. a -> [a] -> [a]
:Char
chChar -> String -> String
forall a. a -> [a] -> [a]
:[]) (TextZipper Text -> TextZipper Text)
-> (TextZipper Text -> TextZipper Text)
-> TextZipper Text
-> TextZipper Text
forall k (cat :: k -> k -> *) (a :: k) (b :: k) (c :: k).
Category cat =>
cat a b -> cat b c -> cat a c
>>> TextZipper Text -> TextZipper Text
forall a. Monoid a => TextZipper a -> TextZipper a
Z.moveLeft)
                    -- Third case: the cursor is already on a smart
                    -- character and that character is the last one
                    -- on the line, so instead of inserting a new
                    -- character, just move past it.
                    | (Char -> Editor Text Name -> Bool
forall a. Char -> Editor Text a -> Bool
cursorAtChar Char
ch (Editor Text Name -> Bool) -> Editor Text Name -> Bool
forall a b. (a -> b) -> a -> b
$ ChatState
stChatState
-> Getting (Editor Text Name) ChatState (Editor Text Name)
-> Editor Text Name
forall s a. s -> Getting a s a -> a
^.(EditState Name -> Const (Editor Text Name) (EditState Name))
-> ChatState -> Const (Editor Text Name) ChatState
Lens' ChatState (EditState Name)
which((EditState Name -> Const (Editor Text Name) (EditState Name))
 -> ChatState -> Const (Editor Text Name) ChatState)
-> ((Editor Text Name
     -> Const (Editor Text Name) (Editor Text Name))
    -> EditState Name -> Const (Editor Text Name) (EditState Name))
-> Getting (Editor Text Name) ChatState (Editor Text Name)
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(Editor Text Name -> Const (Editor Text Name) (Editor Text Name))
-> EditState Name -> Const (Editor Text Name) (EditState Name)
forall n. Lens' (EditState n) (Editor Text n)
esEditor) Bool -> Bool -> Bool
&&
                      (Editor Text Name -> Bool
forall a. Editor Text a -> Bool
cursorIsAtEnd (Editor Text Name -> Bool) -> Editor Text Name -> Bool
forall a b. (a -> b) -> a -> b
$ (TextZipper Text -> TextZipper Text)
-> Editor Text Name -> Editor Text Name
forall t n.
(TextZipper t -> TextZipper t) -> Editor t n -> Editor t n
applyEdit TextZipper Text -> TextZipper Text
forall a. Monoid a => TextZipper a -> TextZipper a
Z.moveRight (Editor Text Name -> Editor Text Name)
-> Editor Text Name -> Editor Text Name
forall a b. (a -> b) -> a -> b
$ ChatState
stChatState
-> Getting (Editor Text Name) ChatState (Editor Text Name)
-> Editor Text Name
forall s a. s -> Getting a s a -> a
^.(EditState Name -> Const (Editor Text Name) (EditState Name))
-> ChatState -> Const (Editor Text Name) ChatState
Lens' ChatState (EditState Name)
which((EditState Name -> Const (Editor Text Name) (EditState Name))
 -> ChatState -> Const (Editor Text Name) ChatState)
-> ((Editor Text Name
     -> Const (Editor Text Name) (Editor Text Name))
    -> EditState Name -> Const (Editor Text Name) (EditState Name))
-> Getting (Editor Text Name) ChatState (Editor Text Name)
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(Editor Text Name -> Const (Editor Text Name) (Editor Text Name))
-> EditState Name -> Const (Editor Text Name) (EditState Name)
forall n. Lens' (EditState n) (Editor Text n)
esEditor) ->
                        (EditState Name -> Identity (EditState Name))
-> ChatState -> Identity ChatState
Lens' ChatState (EditState Name)
which((EditState Name -> Identity (EditState Name))
 -> ChatState -> Identity ChatState)
-> ((Editor Text Name -> Identity (Editor Text Name))
    -> EditState Name -> Identity (EditState Name))
-> (Editor Text Name -> Identity (Editor Text Name))
-> ChatState
-> Identity ChatState
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(Editor Text Name -> Identity (Editor Text Name))
-> EditState Name -> Identity (EditState Name)
forall n. Lens' (EditState n) (Editor Text n)
esEditor ((Editor Text Name -> Identity (Editor Text Name))
 -> ChatState -> Identity ChatState)
-> (Editor Text Name -> Editor Text Name) -> MH ()
forall s (m :: * -> *) a b.
MonadState s m =>
ASetter s s a b -> (a -> b) -> m ()
%= (TextZipper Text -> TextZipper Text)
-> Editor Text Name -> Editor Text Name
forall t n.
(TextZipper t -> TextZipper t) -> Editor t n -> Editor t n
applyEdit TextZipper Text -> TextZipper Text
forall a. Monoid a => TextZipper a -> TextZipper a
Z.moveRight
                    -- Fall-through case: just insert one of the chars
                    -- without doing anything smart.
                    | Bool
otherwise -> MH ()
doInsertChar
            | ChatState -> Lens' ChatState (EditState Name) -> Bool
editingPermitted ChatState
st Lens' ChatState (EditState Name)
which -> do

              -- If the most recent editing event was a tab completion,
              -- there is a trailing space that we want to remove if the
              -- next input character is punctuation.
              Bool -> MH () -> MH ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Bool
smartEditing Bool -> Bool -> Bool
&& Bool
justCompleted Bool -> Bool -> Bool
&& Event -> Bool
isSmartClosingPunctuation Event
e) (MH () -> MH ()) -> MH () -> MH ()
forall a b. (a -> b) -> a -> b
$
                  (EditState Name -> Identity (EditState Name))
-> ChatState -> Identity ChatState
Lens' ChatState (EditState Name)
which((EditState Name -> Identity (EditState Name))
 -> ChatState -> Identity ChatState)
-> ((Editor Text Name -> Identity (Editor Text Name))
    -> EditState Name -> Identity (EditState Name))
-> (Editor Text Name -> Identity (Editor Text Name))
-> ChatState
-> Identity ChatState
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(Editor Text Name -> Identity (Editor Text Name))
-> EditState Name -> Identity (EditState Name)
forall n. Lens' (EditState n) (Editor Text n)
esEditor ((Editor Text Name -> Identity (Editor Text Name))
 -> ChatState -> Identity ChatState)
-> (Editor Text Name -> Editor Text Name) -> MH ()
forall s (m :: * -> *) a b.
MonadState s m =>
ASetter s s a b -> (a -> b) -> m ()
%= (TextZipper Text -> TextZipper Text)
-> Editor Text Name -> Editor Text Name
forall t n.
(TextZipper t -> TextZipper t) -> Editor t n -> Editor t n
applyEdit TextZipper Text -> TextZipper Text
forall a. (Eq a, Monoid a) => TextZipper a -> TextZipper a
Z.deletePrevChar

              (EditState Name -> Identity (EditState Name))
-> ChatState -> Identity ChatState
Lens' ChatState (EditState Name)
which((EditState Name -> Identity (EditState Name))
 -> ChatState -> Identity ChatState)
-> ((Editor Text Name -> Identity (Editor Text Name))
    -> EditState Name -> Identity (EditState Name))
-> (Editor Text Name -> Identity (Editor Text Name))
-> ChatState
-> Identity ChatState
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(Editor Text Name -> Identity (Editor Text Name))
-> EditState Name -> Identity (EditState Name)
forall n. Lens' (EditState n) (Editor Text n)
esEditor ((Editor Text Name -> Identity (Editor Text Name))
 -> ChatState -> Identity ChatState)
-> (Editor Text Name -> Editor Text Name) -> MH ()
forall s (m :: * -> *) a b.
MonadState s m =>
ASetter s s a b -> (a -> b) -> m ()
%= (TextZipper Text -> TextZipper Text)
-> Editor Text Name -> Editor Text Name
forall t n.
(TextZipper t -> TextZipper t) -> Editor t n -> Editor t n
applyEdit (Text -> TextZipper Text -> TextZipper Text
forall a. Monoid a => a -> TextZipper a -> TextZipper a
Z.insertMany (Text -> Text
sanitizeUserText' (Text -> Text) -> Text -> Text
forall a b. (a -> b) -> a -> b
$ Char -> Text
T.singleton Char
ch))
              Lens' ChatState (EditState Name) -> MH ()
sendUserTypingAction Lens' ChatState (EditState Name)
which
          Event
_ | ChatState -> Lens' ChatState (EditState Name) -> Bool
editingPermitted ChatState
st Lens' ChatState (EditState Name)
which -> do
              Lens' ChatState (Editor Text Name)
-> (Event -> Editor Text Name -> EventM Name (Editor Text Name))
-> Event
-> MH ()
forall b e.
Lens' ChatState b -> (e -> b -> EventM Name b) -> e -> MH ()
mhHandleEventLensed ((EditState Name -> f (EditState Name)) -> ChatState -> f ChatState
Lens' ChatState (EditState Name)
which((EditState Name -> f (EditState Name))
 -> ChatState -> f ChatState)
-> ((Editor Text Name -> f (Editor Text Name))
    -> EditState Name -> f (EditState Name))
-> (Editor Text Name -> f (Editor Text Name))
-> ChatState
-> f ChatState
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(Editor Text Name -> f (Editor Text Name))
-> EditState Name -> f (EditState Name)
forall n. Lens' (EditState n) (Editor Text n)
esEditor) Event -> Editor Text Name -> EventM Name (Editor Text Name)
forall t n.
(DecodeUtf8 t, Eq t, GenericTextZipper t) =>
Event -> Editor t n -> EventM n (Editor t n)
handleEditorEvent Event
e
              Lens' ChatState (EditState Name) -> MH ()
sendUserTypingAction Lens' ChatState (EditState Name)
which
            | Bool
otherwise -> () -> MH ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()

    let ctx :: AutocompleteContext
ctx = AutocompleteContext :: Bool -> Bool -> AutocompleteContext
AutocompleteContext { autocompleteManual :: Bool
autocompleteManual = Bool
False
                                  , autocompleteFirstMatch :: Bool
autocompleteFirstMatch = Bool
False
                                  }
    Traversal' ChatState (EditState Name)
-> AutocompleteContext -> MH ()
checkForAutocompletion Lens' ChatState (EditState Name)
Traversal' ChatState (EditState Name)
which AutocompleteContext
ctx

    -- Reset the spell check timer for this editor
    Maybe (IO ())
mReset <- Getting (Maybe (IO ())) ChatState (Maybe (IO ()))
-> MH (Maybe (IO ()))
forall s (m :: * -> *) a. MonadState s m => Getting a s a -> m a
use ((EditState Name -> Const (Maybe (IO ())) (EditState Name))
-> ChatState -> Const (Maybe (IO ())) ChatState
Lens' ChatState (EditState Name)
which((EditState Name -> Const (Maybe (IO ())) (EditState Name))
 -> ChatState -> Const (Maybe (IO ())) ChatState)
-> ((Maybe (IO ()) -> Const (Maybe (IO ())) (Maybe (IO ())))
    -> EditState Name -> Const (Maybe (IO ())) (EditState Name))
-> Getting (Maybe (IO ())) ChatState (Maybe (IO ()))
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(Maybe (IO ()) -> Const (Maybe (IO ())) (Maybe (IO ())))
-> EditState Name -> Const (Maybe (IO ())) (EditState Name)
forall n. Lens' (EditState n) (Maybe (IO ()))
esSpellCheckTimerReset)
    case Maybe (IO ())
mReset of
        Maybe (IO ())
Nothing -> () -> MH ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
        Just IO ()
reset -> IO () -> MH ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO IO ()
reset

    -- If the preview is enabled and multi-line editing is enabled and
    -- the line count changed, we need to invalidate the rendering cache
    -- entry for the channel messages because we want to redraw them to
    -- fit in the space just changed by the size of the preview area.
    Int
afterLineCount <- Getting Int ChatState Int -> MH Int
forall s (m :: * -> *) a. MonadState s m => Getting a s a -> m a
use ((EditState Name -> Const Int (EditState Name))
-> ChatState -> Const Int ChatState
Lens' ChatState (EditState Name)
which((EditState Name -> Const Int (EditState Name))
 -> ChatState -> Const Int ChatState)
-> ((Int -> Const Int Int)
    -> EditState Name -> Const Int (EditState Name))
-> Getting Int ChatState Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(Editor Text Name -> Const Int (Editor Text Name))
-> EditState Name -> Const Int (EditState Name)
forall n. Lens' (EditState n) (Editor Text n)
esEditor((Editor Text Name -> Const Int (Editor Text Name))
 -> EditState Name -> Const Int (EditState Name))
-> ((Int -> Const Int Int)
    -> Editor Text Name -> Const Int (Editor Text Name))
-> (Int -> Const Int Int)
-> EditState Name
-> Const Int (EditState Name)
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(Editor Text Name -> [Text])
-> SimpleGetter (Editor Text Name) [Text]
forall s a. (s -> a) -> SimpleGetter s a
to Editor Text Name -> [Text]
forall t n. Monoid t => Editor t n -> [t]
getEditContentsGetting Int (Editor Text Name) [Text]
-> ((Int -> Const Int Int) -> [Text] -> Const Int [Text])
-> (Int -> Const Int Int)
-> Editor Text Name
-> Const Int (Editor Text Name)
forall b c a. (b -> c) -> (a -> b) -> a -> c
.([Text] -> Int) -> SimpleGetter [Text] Int
forall s a. (s -> a) -> SimpleGetter s a
to [Text] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length)
    Bool
isMultiline <- Getting Bool ChatState Bool -> MH Bool
forall s (m :: * -> *) a. MonadState s m => Getting a s a -> m a
use ((EditState Name -> Const Bool (EditState Name))
-> ChatState -> Const Bool ChatState
Lens' ChatState (EditState Name)
which((EditState Name -> Const Bool (EditState Name))
 -> ChatState -> Const Bool ChatState)
-> ((Bool -> Const Bool Bool)
    -> EditState Name -> Const Bool (EditState Name))
-> Getting Bool ChatState Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(EphemeralEditState -> Const Bool EphemeralEditState)
-> EditState Name -> Const Bool (EditState Name)
forall n. Lens' (EditState n) EphemeralEditState
esEphemeral((EphemeralEditState -> Const Bool EphemeralEditState)
 -> EditState Name -> Const Bool (EditState Name))
-> ((Bool -> Const Bool Bool)
    -> EphemeralEditState -> Const Bool EphemeralEditState)
-> (Bool -> Const Bool Bool)
-> EditState Name
-> Const Bool (EditState Name)
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(Bool -> Const Bool Bool)
-> EphemeralEditState -> Const Bool EphemeralEditState
Lens' EphemeralEditState Bool
eesMultiline)
    Bool
isPreviewing <- Getting Bool ChatState Bool -> MH Bool
forall s (m :: * -> *) a. MonadState s m => Getting a s a -> m a
use ((ChatResources -> Const Bool ChatResources)
-> ChatState -> Const Bool ChatState
Lens' ChatState ChatResources
csResources((ChatResources -> Const Bool ChatResources)
 -> ChatState -> Const Bool ChatState)
-> ((Bool -> Const Bool Bool)
    -> ChatResources -> Const Bool ChatResources)
-> Getting Bool ChatState Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(Config -> Const Bool Config)
-> ChatResources -> Const Bool ChatResources
Lens' ChatResources Config
crConfiguration((Config -> Const Bool Config)
 -> ChatResources -> Const Bool ChatResources)
-> ((Bool -> Const Bool Bool) -> Config -> Const Bool Config)
-> (Bool -> Const Bool Bool)
-> ChatResources
-> Const Bool ChatResources
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(Bool -> Const Bool Bool) -> Config -> Const Bool Config
Lens' Config Bool
configShowMessagePreviewL)
    Bool -> MH () -> MH ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Int
beforeLineCount Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
/= Int
afterLineCount Bool -> Bool -> Bool
&& Bool
isMultiline Bool -> Bool -> Bool
&& Bool
isPreviewing) (MH () -> MH ()) -> MH () -> MH ()
forall a b. (a -> b) -> a -> b
$ do
        ChannelId -> MH ()
invalidateChannelRenderingCache ChannelId
cId

    -- Reset the recent autocompletion flag to stop smart punctuation
    -- handling.
    Bool -> MH () -> MH ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when Bool
justCompleted (MH () -> MH ()) -> MH () -> MH ()
forall a b. (a -> b) -> a -> b
$
        (EditState Name -> Identity (EditState Name))
-> ChatState -> Identity ChatState
Lens' ChatState (EditState Name)
which((EditState Name -> Identity (EditState Name))
 -> ChatState -> Identity ChatState)
-> ((Bool -> Identity Bool)
    -> EditState Name -> Identity (EditState Name))
-> (Bool -> Identity Bool)
-> ChatState
-> Identity ChatState
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(Bool -> Identity Bool)
-> EditState Name -> Identity (EditState Name)
forall n. Lens' (EditState n) Bool
esJustCompleted ((Bool -> Identity Bool) -> ChatState -> Identity ChatState)
-> Bool -> MH ()
forall s (m :: * -> *) a b.
MonadState s m =>
ASetter s s a b -> b -> m ()
.= Bool
False

-- | Send the user_typing action to the server asynchronously, over the
-- connected websocket. If the websocket is not connected, drop the
-- action silently.
sendUserTypingAction :: Lens' ChatState (EditState Name)
                     -> MH ()
sendUserTypingAction :: Lens' ChatState (EditState Name) -> MH ()
sendUserTypingAction Lens' ChatState (EditState Name)
which = 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
    Bool -> MH () -> MH ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Config -> Bool
configSendTypingNotifications (ChatState
stChatState -> Getting Config ChatState Config -> Config
forall s a. s -> Getting a s a -> a
^.(ChatResources -> Const Config ChatResources)
-> ChatState -> Const Config ChatState
Lens' ChatState ChatResources
csResources((ChatResources -> Const Config ChatResources)
 -> ChatState -> Const Config ChatState)
-> ((Config -> Const Config Config)
    -> ChatResources -> Const Config ChatResources)
-> Getting Config ChatState Config
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(Config -> Const Config Config)
-> ChatResources -> Const Config ChatResources
Lens' ChatResources Config
crConfiguration)) (MH () -> MH ()) -> MH () -> MH ()
forall a b. (a -> b) -> a -> b
$
      case ChatState
stChatState
-> Getting ConnectionStatus ChatState ConnectionStatus
-> ConnectionStatus
forall s a. s -> Getting a s a -> a
^.Getting ConnectionStatus ChatState ConnectionStatus
Lens' ChatState ConnectionStatus
csConnectionStatus of
        ConnectionStatus
Connected -> do
          let pId :: Maybe PostId
pId = case ChatState
stChatState -> Getting EditMode ChatState EditMode -> EditMode
forall s a. s -> Getting a s a -> a
^.(EditState Name -> Const EditMode (EditState Name))
-> ChatState -> Const EditMode ChatState
Lens' ChatState (EditState Name)
which((EditState Name -> Const EditMode (EditState Name))
 -> ChatState -> Const EditMode ChatState)
-> ((EditMode -> Const EditMode EditMode)
    -> EditState Name -> Const EditMode (EditState Name))
-> Getting EditMode ChatState EditMode
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(EditMode -> Const EditMode EditMode)
-> EditState Name -> Const EditMode (EditState Name)
forall n. Lens' (EditState n) EditMode
esEditMode of
                      Replying Message
_ Post
post -> PostId -> Maybe PostId
forall a. a -> Maybe a
Just (PostId -> Maybe PostId) -> PostId -> Maybe PostId
forall a b. (a -> b) -> a -> b
$ Post -> PostId
postId Post
post
                      EditMode
_               -> Maybe PostId
forall a. Maybe a
Nothing
          ChannelId
cId <- Getting ChannelId ChatState ChannelId -> MH ChannelId
forall s (m :: * -> *) a. MonadState s m => Getting a s a -> m a
use ((EditState Name -> Const ChannelId (EditState Name))
-> ChatState -> Const ChannelId ChatState
Lens' ChatState (EditState Name)
which((EditState Name -> Const ChannelId (EditState Name))
 -> ChatState -> Const ChannelId ChatState)
-> ((ChannelId -> Const ChannelId ChannelId)
    -> EditState Name -> Const ChannelId (EditState Name))
-> Getting ChannelId ChatState ChannelId
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(ChannelId -> Const ChannelId ChannelId)
-> EditState Name -> Const ChannelId (EditState Name)
forall n. Lens' (EditState n) ChannelId
esChannelId)
          IO () -> MH ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> MH ()) -> IO () -> MH ()
forall a b. (a -> b) -> a -> b
$ do
            UTCTime
now <- IO UTCTime
getCurrentTime
            let action :: WebsocketAction
action = UTCTime -> ChannelId -> Maybe PostId -> WebsocketAction
UserTyping UTCTime
now ChannelId
cId Maybe PostId
pId
            STM () -> IO ()
forall a. STM a -> IO a
STM.atomically (STM () -> IO ()) -> STM () -> IO ()
forall a b. (a -> b) -> a -> b
$ TChan WebsocketAction -> WebsocketAction -> STM ()
forall a. TChan a -> a -> STM ()
STM.writeTChan (ChatState
stChatState
-> Getting
     (TChan WebsocketAction) ChatState (TChan WebsocketAction)
-> TChan WebsocketAction
forall s a. s -> Getting a s a -> a
^.(ChatResources -> Const (TChan WebsocketAction) ChatResources)
-> ChatState -> Const (TChan WebsocketAction) ChatState
Lens' ChatState ChatResources
csResources((ChatResources -> Const (TChan WebsocketAction) ChatResources)
 -> ChatState -> Const (TChan WebsocketAction) ChatState)
-> ((TChan WebsocketAction
     -> Const (TChan WebsocketAction) (TChan WebsocketAction))
    -> ChatResources -> Const (TChan WebsocketAction) ChatResources)
-> Getting
     (TChan WebsocketAction) ChatState (TChan WebsocketAction)
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(TChan WebsocketAction
 -> Const (TChan WebsocketAction) (TChan WebsocketAction))
-> ChatResources -> Const (TChan WebsocketAction) ChatResources
Lens' ChatResources (TChan WebsocketAction)
crWebsocketActionChan) WebsocketAction
action
        ConnectionStatus
Disconnected -> () -> MH ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()

-- Kick off an async request to the spell checker for the current editor
-- contents.
requestSpellCheck :: Aspell -> MessageInterfaceTarget -> MH ()
requestSpellCheck :: Aspell -> MessageInterfaceTarget -> MH ()
requestSpellCheck Aspell
checker MessageInterfaceTarget
target = do
    -- Get the editor contents.
    Maybe [Text]
mContents <- case MessageInterfaceTarget
target of
        MITeamThread TeamId
tId -> do
            Maybe ThreadInterface
mTi <- Getting (Maybe ThreadInterface) ChatState (Maybe ThreadInterface)
-> MH (Maybe ThreadInterface)
forall s (m :: * -> *) a. MonadState s m => Getting a s a -> m a
use (TeamId -> Lens' ChatState (Maybe ThreadInterface)
maybeThreadInterface(TeamId
tId))
            case Maybe ThreadInterface
mTi of
                Maybe ThreadInterface
Nothing -> Maybe [Text] -> MH (Maybe [Text])
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe [Text]
forall a. Maybe a
Nothing
                Just ThreadInterface
ti -> Maybe [Text] -> MH (Maybe [Text])
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe [Text] -> MH (Maybe [Text]))
-> Maybe [Text] -> MH (Maybe [Text])
forall a b. (a -> b) -> a -> b
$ [Text] -> Maybe [Text]
forall a. a -> Maybe a
Just ([Text] -> Maybe [Text]) -> [Text] -> Maybe [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 -> [Text]) -> Editor Text Name -> [Text]
forall a b. (a -> b) -> a -> b
$ ThreadInterface
tiThreadInterface
-> Getting (Editor Text Name) ThreadInterface (Editor Text Name)
-> Editor Text Name
forall s a. s -> Getting a s a -> a
^.(EditState Name -> Const (Editor Text Name) (EditState Name))
-> ThreadInterface -> Const (Editor Text Name) ThreadInterface
forall n i. Lens' (MessageInterface n i) (EditState n)
miEditor((EditState Name -> Const (Editor Text Name) (EditState Name))
 -> ThreadInterface -> Const (Editor Text Name) ThreadInterface)
-> ((Editor Text Name
     -> Const (Editor Text Name) (Editor Text Name))
    -> EditState Name -> Const (Editor Text Name) (EditState Name))
-> Getting (Editor Text Name) ThreadInterface (Editor Text Name)
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(Editor Text Name -> Const (Editor Text Name) (Editor Text Name))
-> EditState Name -> Const (Editor Text Name) (EditState Name)
forall n. Lens' (EditState n) (Editor Text n)
esEditor
        MIChannel ChannelId
cId -> do
            Maybe ChannelMessageInterface
mMi <- Getting
  (First ChannelMessageInterface) ChatState ChannelMessageInterface
-> MH (Maybe ChannelMessageInterface)
forall s (m :: * -> *) a.
MonadState s m =>
Getting (First a) s a -> m (Maybe a)
preuse (ChannelId -> Traversal' ChatState ChannelMessageInterface
maybeChannelMessageInterface(ChannelId
cId))
            case Maybe ChannelMessageInterface
mMi of
                Maybe ChannelMessageInterface
Nothing -> Maybe [Text] -> MH (Maybe [Text])
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe [Text]
forall a. Maybe a
Nothing
                Just ChannelMessageInterface
mi -> Maybe [Text] -> MH (Maybe [Text])
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe [Text] -> MH (Maybe [Text]))
-> Maybe [Text] -> MH (Maybe [Text])
forall a b. (a -> b) -> a -> b
$ [Text] -> Maybe [Text]
forall a. a -> Maybe a
Just ([Text] -> Maybe [Text]) -> [Text] -> Maybe [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 -> [Text]) -> Editor Text Name -> [Text]
forall a b. (a -> b) -> a -> b
$ ChannelMessageInterface
miChannelMessageInterface
-> Getting
     (Editor Text Name) ChannelMessageInterface (Editor Text Name)
-> Editor Text Name
forall s a. s -> Getting a s a -> a
^.(EditState Name -> Const (Editor Text Name) (EditState Name))
-> ChannelMessageInterface
-> Const (Editor Text Name) ChannelMessageInterface
forall n i. Lens' (MessageInterface n i) (EditState n)
miEditor((EditState Name -> Const (Editor Text Name) (EditState Name))
 -> ChannelMessageInterface
 -> Const (Editor Text Name) ChannelMessageInterface)
-> ((Editor Text Name
     -> Const (Editor Text Name) (Editor Text Name))
    -> EditState Name -> Const (Editor Text Name) (EditState Name))
-> Getting
     (Editor Text Name) ChannelMessageInterface (Editor Text Name)
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(Editor Text Name -> Const (Editor Text Name) (Editor Text Name))
-> EditState Name -> Const (Editor Text Name) (EditState Name)
forall n. Lens' (EditState n) (Editor Text n)
esEditor

    case Maybe [Text]
mContents of
        Maybe [Text]
Nothing -> () -> MH ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
        Just [Text]
contents ->
            AsyncPriority -> IO (Maybe (MH ())) -> MH ()
doAsyncWith AsyncPriority
Preempt (IO (Maybe (MH ())) -> MH ()) -> IO (Maybe (MH ())) -> MH ()
forall a b. (a -> b) -> a -> b
$ do
                -- For each line in the editor, submit an aspell request.
                let query :: IO [AspellResponse]
query = [[AspellResponse]] -> [AspellResponse]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat ([[AspellResponse]] -> [AspellResponse])
-> IO [[AspellResponse]] -> IO [AspellResponse]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (Text -> IO [AspellResponse]) -> [Text] -> IO [[AspellResponse]]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM (Aspell -> Text -> IO [AspellResponse]
askAspell Aspell
checker) [Text]
contents
                    postMistakes :: [AspellResponse] -> MH ()
                    postMistakes :: [AspellResponse] -> MH ()
postMistakes [AspellResponse]
responses = do
                        let getMistakes :: AspellResponse -> [Text]
getMistakes AspellResponse
AllCorrect = []
                            getMistakes (Mistakes [Mistake]
ms) = Mistake -> Text
mistakeWord (Mistake -> Text) -> [Mistake] -> [Text]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Mistake]
ms
                            allMistakes :: Set Text
allMistakes = [Text] -> Set Text
forall a. Ord a => [a] -> Set a
S.fromList ([Text] -> Set Text) -> [Text] -> Set Text
forall a b. (a -> b) -> a -> b
$ [[Text]] -> [Text]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat ([[Text]] -> [Text]) -> [[Text]] -> [Text]
forall a b. (a -> b) -> a -> b
$ AspellResponse -> [Text]
getMistakes (AspellResponse -> [Text]) -> [AspellResponse] -> [[Text]]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [AspellResponse]
responses

                        case MessageInterfaceTarget
target of
                            MITeamThread TeamId
tId ->
                                TeamId -> Lens' ChatState (Maybe ThreadInterface)
maybeThreadInterface(TeamId
tId)((Maybe ThreadInterface -> Identity (Maybe ThreadInterface))
 -> ChatState -> Identity ChatState)
-> ((Set Text -> Identity (Set Text))
    -> Maybe ThreadInterface -> Identity (Maybe ThreadInterface))
-> (Set Text -> Identity (Set Text))
-> ChatState
-> Identity ChatState
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(ThreadInterface -> Identity ThreadInterface)
-> Maybe ThreadInterface -> Identity (Maybe ThreadInterface)
forall a a'. Traversal (Maybe a) (Maybe a') a a'
_Just((ThreadInterface -> Identity ThreadInterface)
 -> Maybe ThreadInterface -> Identity (Maybe ThreadInterface))
-> ((Set Text -> Identity (Set Text))
    -> ThreadInterface -> Identity ThreadInterface)
-> (Set Text -> Identity (Set Text))
-> Maybe ThreadInterface
-> Identity (Maybe ThreadInterface)
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(EditState Name -> Identity (EditState Name))
-> ThreadInterface -> Identity ThreadInterface
forall n i. Lens' (MessageInterface n i) (EditState n)
miEditor((EditState Name -> Identity (EditState Name))
 -> ThreadInterface -> Identity ThreadInterface)
-> ((Set Text -> Identity (Set Text))
    -> EditState Name -> Identity (EditState Name))
-> (Set Text -> Identity (Set Text))
-> ThreadInterface
-> Identity ThreadInterface
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(Set Text -> Identity (Set Text))
-> EditState Name -> Identity (EditState Name)
forall n. Lens' (EditState n) (Set Text)
esMisspellings ((Set Text -> Identity (Set Text))
 -> ChatState -> Identity ChatState)
-> Set Text -> MH ()
forall s (m :: * -> *) a b.
MonadState s m =>
ASetter s s a b -> b -> m ()
.= Set Text
allMistakes
                            MIChannel ChannelId
cId ->
                                ChannelId -> Traversal' ChatState ChannelMessageInterface
maybeChannelMessageInterface(ChannelId
cId)((ChannelMessageInterface -> Identity ChannelMessageInterface)
 -> ChatState -> Identity ChatState)
-> ((Set Text -> Identity (Set Text))
    -> ChannelMessageInterface -> Identity ChannelMessageInterface)
-> (Set Text -> Identity (Set Text))
-> ChatState
-> Identity ChatState
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(EditState Name -> Identity (EditState Name))
-> ChannelMessageInterface -> Identity ChannelMessageInterface
forall n i. Lens' (MessageInterface n i) (EditState n)
miEditor((EditState Name -> Identity (EditState Name))
 -> ChannelMessageInterface -> Identity ChannelMessageInterface)
-> ((Set Text -> Identity (Set Text))
    -> EditState Name -> Identity (EditState Name))
-> (Set Text -> Identity (Set Text))
-> ChannelMessageInterface
-> Identity ChannelMessageInterface
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(Set Text -> Identity (Set Text))
-> EditState Name -> Identity (EditState Name)
forall n. Lens' (EditState n) (Set Text)
esMisspellings ((Set Text -> Identity (Set Text))
 -> ChatState -> Identity ChatState)
-> Set Text -> MH ()
forall s (m :: * -> *) a b.
MonadState s m =>
ASetter s s a b -> b -> m ()
.= Set Text
allMistakes

                IO [AspellResponse]
-> ([AspellResponse] -> IO (Maybe (MH ()))) -> IO (Maybe (MH ()))
forall a. IO a -> (a -> IO (Maybe (MH ()))) -> IO (Maybe (MH ()))
tryMM IO [AspellResponse]
query (Maybe (MH ()) -> IO (Maybe (MH ()))
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe (MH ()) -> IO (Maybe (MH ())))
-> ([AspellResponse] -> Maybe (MH ()))
-> [AspellResponse]
-> IO (Maybe (MH ()))
forall b c a. (b -> c) -> (a -> b) -> a -> c
. MH () -> Maybe (MH ())
forall a. a -> Maybe a
Just (MH () -> Maybe (MH ()))
-> ([AspellResponse] -> MH ()) -> [AspellResponse] -> Maybe (MH ())
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [AspellResponse] -> MH ()
postMistakes)

editorEmpty :: Editor Text a -> Bool
editorEmpty :: Editor Text a -> Bool
editorEmpty Editor Text a
e = Editor Text a -> Bool
forall a. Editor Text a -> Bool
cursorIsAtEnd Editor Text a
e Bool -> Bool -> Bool
&&
                Editor Text a -> Bool
forall a. Editor Text a -> Bool
cursorIsAtBeginning Editor Text a
e

cursorIsAtEnd :: Editor Text a -> Bool
cursorIsAtEnd :: Editor Text a -> Bool
cursorIsAtEnd Editor Text a
e =
    let col :: Int
col = (Int, Int) -> Int
forall a b. (a, b) -> b
snd ((Int, Int) -> Int) -> (Int, Int) -> Int
forall a b. (a -> b) -> a -> b
$ TextZipper Text -> (Int, Int)
forall a. TextZipper a -> (Int, Int)
Z.cursorPosition TextZipper Text
z
        curLine :: Text
curLine = TextZipper Text -> Text
forall a. Monoid a => TextZipper a -> a
Z.currentLine TextZipper Text
z
        z :: TextZipper Text
z = Editor Text a
eEditor Text a
-> Getting (TextZipper Text) (Editor Text a) (TextZipper Text)
-> TextZipper Text
forall s a. s -> Getting a s a -> a
^.Getting (TextZipper Text) (Editor Text a) (TextZipper Text)
forall t1 n t2.
Lens (Editor t1 n) (Editor t2 n) (TextZipper t1) (TextZipper t2)
editContentsL
    in Int
col Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Text -> Int
T.length Text
curLine

cursorIsAtBeginning :: Editor Text a -> Bool
cursorIsAtBeginning :: Editor Text a -> Bool
cursorIsAtBeginning Editor Text a
e =
    let col :: Int
col = (Int, Int) -> Int
forall a b. (a, b) -> b
snd ((Int, Int) -> Int) -> (Int, Int) -> Int
forall a b. (a -> b) -> a -> b
$ TextZipper Text -> (Int, Int)
forall a. TextZipper a -> (Int, Int)
Z.cursorPosition TextZipper Text
z
        z :: TextZipper Text
z = Editor Text a
eEditor Text a
-> Getting (TextZipper Text) (Editor Text a) (TextZipper Text)
-> TextZipper Text
forall s a. s -> Getting a s a -> a
^.Getting (TextZipper Text) (Editor Text a) (TextZipper Text)
forall t1 n t2.
Lens (Editor t1 n) (Editor t2 n) (TextZipper t1) (TextZipper t2)
editContentsL
    in Int
col Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0

cursorAtOneOf :: [Char] -> Editor Text a -> Maybe Char
cursorAtOneOf :: String -> Editor Text a -> Maybe Char
cursorAtOneOf [] Editor Text a
_ = Maybe Char
forall a. Maybe a
Nothing
cursorAtOneOf (Char
c:String
cs) Editor Text a
e =
    if Char -> Editor Text a -> Bool
forall a. Char -> Editor Text a -> Bool
cursorAtChar Char
c Editor Text a
e
    then Char -> Maybe Char
forall a. a -> Maybe a
Just Char
c
    else String -> Editor Text a -> Maybe Char
forall a. String -> Editor Text a -> Maybe Char
cursorAtOneOf String
cs Editor Text a
e

cursorAtChar :: Char -> Editor Text a -> Bool
cursorAtChar :: Char -> Editor Text a -> Bool
cursorAtChar Char
ch Editor Text a
e =
    let col :: Int
col = (Int, Int) -> Int
forall a b. (a, b) -> b
snd ((Int, Int) -> Int) -> (Int, Int) -> Int
forall a b. (a -> b) -> a -> b
$ TextZipper Text -> (Int, Int)
forall a. TextZipper a -> (Int, Int)
Z.cursorPosition TextZipper Text
z
        curLine :: Text
curLine = TextZipper Text -> Text
forall a. Monoid a => TextZipper a -> a
Z.currentLine TextZipper Text
z
        z :: TextZipper Text
z = Editor Text a
eEditor Text a
-> Getting (TextZipper Text) (Editor Text a) (TextZipper Text)
-> TextZipper Text
forall s a. s -> Getting a s a -> a
^.Getting (TextZipper Text) (Editor Text a) (TextZipper Text)
forall t1 n t2.
Lens (Editor t1 n) (Editor t2 n) (TextZipper t1) (TextZipper t2)
editContentsL
    in (Char -> Text
T.singleton Char
ch) Text -> Text -> Bool
`T.isPrefixOf` Int -> Text -> Text
T.drop Int
col Text
curLine

gotoHome :: Z.TextZipper Text -> Z.TextZipper Text
gotoHome :: TextZipper Text -> TextZipper Text
gotoHome = (Int, Int) -> TextZipper Text -> TextZipper Text
forall a. Monoid a => (Int, Int) -> TextZipper a -> TextZipper a
Z.moveCursor (Int
0, Int
0)

gotoEnd :: Z.TextZipper Text -> Z.TextZipper Text
gotoEnd :: TextZipper Text -> TextZipper Text
gotoEnd TextZipper Text
z =
    let zLines :: [Text]
zLines = TextZipper Text -> [Text]
forall a. Monoid a => TextZipper a -> [a]
Z.getText TextZipper Text
z
        numLines :: Int
numLines = [Text] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Text]
zLines
        lastLineLength :: Int
lastLineLength = Text -> Int
T.length (Text -> Int) -> Text -> Int
forall a b. (a -> b) -> a -> b
$ [Text] -> Text
forall a. [a] -> a
last [Text]
zLines
    in if Int
numLines Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
0
       then (Int, Int) -> TextZipper Text -> TextZipper Text
forall a. Monoid a => (Int, Int) -> TextZipper a -> TextZipper a
Z.moveCursor (Int
numLines Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1, Int
lastLineLength) TextZipper Text
z
       else TextZipper Text
z

-- Cancels the following states in this order, as appropriate based on
-- context:
-- * Autocomplete UI display
-- * Reply
-- * Edit
-- * Close current team's thread window if open
cancelAutocompleteOrReplyOrEdit :: Lens' ChatState (EditState Name) -> MH ()
cancelAutocompleteOrReplyOrEdit :: Lens' ChatState (EditState Name) -> MH ()
cancelAutocompleteOrReplyOrEdit Lens' ChatState (EditState Name)
which = do
    ChannelId
cId <- Getting ChannelId ChatState ChannelId -> MH ChannelId
forall s (m :: * -> *) a. MonadState s m => Getting a s a -> m a
use ((EditState Name -> Const ChannelId (EditState Name))
-> ChatState -> Const ChannelId ChatState
Lens' ChatState (EditState Name)
which((EditState Name -> Const ChannelId (EditState Name))
 -> ChatState -> Const ChannelId ChatState)
-> ((ChannelId -> Const ChannelId ChannelId)
    -> EditState Name -> Const ChannelId (EditState Name))
-> Getting ChannelId ChatState ChannelId
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(ChannelId -> Const ChannelId ChannelId)
-> EditState Name -> Const ChannelId (EditState Name)
forall n. Lens' (EditState n) ChannelId
esChannelId)
    ChannelId -> MH ()
invalidateChannelRenderingCache ChannelId
cId
    Maybe (AutocompleteState Name)
ac <- Getting
  (Maybe (AutocompleteState Name))
  ChatState
  (Maybe (AutocompleteState Name))
-> MH (Maybe (AutocompleteState Name))
forall s (m :: * -> *) a. MonadState s m => Getting a s a -> m a
use ((EditState Name
 -> Const (Maybe (AutocompleteState Name)) (EditState Name))
-> ChatState -> Const (Maybe (AutocompleteState Name)) ChatState
Lens' ChatState (EditState Name)
which((EditState Name
  -> Const (Maybe (AutocompleteState Name)) (EditState Name))
 -> ChatState -> Const (Maybe (AutocompleteState Name)) ChatState)
-> ((Maybe (AutocompleteState Name)
     -> Const
          (Maybe (AutocompleteState Name)) (Maybe (AutocompleteState Name)))
    -> EditState Name
    -> Const (Maybe (AutocompleteState Name)) (EditState Name))
-> Getting
     (Maybe (AutocompleteState Name))
     ChatState
     (Maybe (AutocompleteState Name))
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(Maybe (AutocompleteState Name)
 -> Const
      (Maybe (AutocompleteState Name)) (Maybe (AutocompleteState Name)))
-> EditState Name
-> Const (Maybe (AutocompleteState Name)) (EditState Name)
forall n. Lens' (EditState n) (Maybe (AutocompleteState n))
esAutocomplete)
    case Maybe (AutocompleteState Name)
ac of
        Just AutocompleteState Name
_ -> do
            Traversal' ChatState (EditState Name) -> MH ()
forall n. Traversal' ChatState (EditState n) -> MH ()
resetAutocomplete Lens' ChatState (EditState Name)
Traversal' ChatState (EditState Name)
which
        Maybe (AutocompleteState Name)
Nothing -> do
            EditMode
resetEditMode <- Getting EditMode ChatState EditMode -> MH EditMode
forall s (m :: * -> *) a. MonadState s m => Getting a s a -> m a
use ((EditState Name -> Const EditMode (EditState Name))
-> ChatState -> Const EditMode ChatState
Lens' ChatState (EditState Name)
which((EditState Name -> Const EditMode (EditState Name))
 -> ChatState -> Const EditMode ChatState)
-> ((EditMode -> Const EditMode EditMode)
    -> EditState Name -> Const EditMode (EditState Name))
-> Getting EditMode ChatState EditMode
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(EditMode -> Const EditMode EditMode)
-> EditState Name -> Const EditMode (EditState Name)
forall n. Lens' (EditState n) EditMode
esResetEditMode)

            let resetEditor :: MH ()
resetEditor = do
                    (EditState Name -> Identity (EditState Name))
-> ChatState -> Identity ChatState
Lens' ChatState (EditState Name)
which((EditState Name -> Identity (EditState Name))
 -> ChatState -> Identity ChatState)
-> ((EditMode -> Identity EditMode)
    -> EditState Name -> Identity (EditState Name))
-> (EditMode -> Identity EditMode)
-> ChatState
-> Identity ChatState
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(EditMode -> Identity EditMode)
-> EditState Name -> Identity (EditState Name)
forall n. Lens' (EditState n) EditMode
esEditMode ((EditMode -> Identity EditMode)
 -> ChatState -> Identity ChatState)
-> EditMode -> MH ()
forall s (m :: * -> *) a b.
MonadState s m =>
ASetter s s a b -> b -> m ()
.= EditMode
resetEditMode
                    (EditState Name -> Identity (EditState Name))
-> ChatState -> Identity ChatState
Lens' ChatState (EditState Name)
which((EditState Name -> Identity (EditState Name))
 -> ChatState -> Identity ChatState)
-> ((Editor Text Name -> Identity (Editor Text Name))
    -> EditState Name -> Identity (EditState Name))
-> (Editor Text Name -> Identity (Editor Text Name))
-> ChatState
-> Identity ChatState
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(Editor Text Name -> Identity (Editor Text Name))
-> EditState Name -> Identity (EditState Name)
forall n. Lens' (EditState n) (Editor Text n)
esEditor ((Editor Text Name -> Identity (Editor Text Name))
 -> ChatState -> Identity ChatState)
-> (Editor Text Name -> Editor Text Name) -> MH ()
forall s (m :: * -> *) a b.
MonadState s m =>
ASetter s s a b -> (a -> b) -> m ()
%= (TextZipper Text -> TextZipper Text)
-> Editor Text Name -> Editor Text Name
forall t n.
(TextZipper t -> TextZipper t) -> Editor t n -> Editor t n
applyEdit TextZipper Text -> TextZipper Text
forall a. Monoid a => TextZipper a -> TextZipper a
Z.clearZipper
                    Lens' ChatState (EditState Name) -> MH ()
resetAttachmentList Lens' ChatState (EditState Name)
which

            EditMode
curEditMode <- Getting EditMode ChatState EditMode -> MH EditMode
forall s (m :: * -> *) a. MonadState s m => Getting a s a -> m a
use ((EditState Name -> Const EditMode (EditState Name))
-> ChatState -> Const EditMode ChatState
Lens' ChatState (EditState Name)
which((EditState Name -> Const EditMode (EditState Name))
 -> ChatState -> Const EditMode ChatState)
-> ((EditMode -> Const EditMode EditMode)
    -> EditState Name -> Const EditMode (EditState Name))
-> Getting EditMode ChatState EditMode
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(EditMode -> Const EditMode EditMode)
-> EditState Name -> Const EditMode (EditState Name)
forall n. Lens' (EditState n) EditMode
esEditMode)
            case EditMode
curEditMode of
                EditMode
NewPost -> () -> MH ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
                Editing {} -> MH ()
resetEditor
                Replying {} -> do
                    EditMode
prevMode <- Getting EditMode ChatState EditMode -> MH EditMode
forall s (m :: * -> *) a. MonadState s m => Getting a s a -> m a
use ((EditState Name -> Const EditMode (EditState Name))
-> ChatState -> Const EditMode ChatState
Lens' ChatState (EditState Name)
which((EditState Name -> Const EditMode (EditState Name))
 -> ChatState -> Const EditMode ChatState)
-> ((EditMode -> Const EditMode EditMode)
    -> EditState Name -> Const EditMode (EditState Name))
-> Getting EditMode ChatState EditMode
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(EditMode -> Const EditMode EditMode)
-> EditState Name -> Const EditMode (EditState Name)
forall n. Lens' (EditState n) EditMode
esEditMode)
                    MH ()
resetEditor
                    EditMode
newMode <- Getting EditMode ChatState EditMode -> MH EditMode
forall s (m :: * -> *) a. MonadState s m => Getting a s a -> m a
use ((EditState Name -> Const EditMode (EditState Name))
-> ChatState -> Const EditMode ChatState
Lens' ChatState (EditState Name)
which((EditState Name -> Const EditMode (EditState Name))
 -> ChatState -> Const EditMode ChatState)
-> ((EditMode -> Const EditMode EditMode)
    -> EditState Name -> Const EditMode (EditState Name))
-> Getting EditMode ChatState EditMode
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(EditMode -> Const EditMode EditMode)
-> EditState Name -> Const EditMode (EditState Name)
forall n. Lens' (EditState n) EditMode
esEditMode)
                    Bool -> MH () -> MH ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (EditMode
newMode EditMode -> EditMode -> Bool
forall a. Eq a => a -> a -> Bool
== EditMode
prevMode) (MH () -> MH ()) -> MH () -> MH ()
forall a b. (a -> b) -> a -> b
$
                        (TeamId -> MH ()) -> MH ()
withCurrentTeam ((TeamId -> MH ()) -> MH ()) -> (TeamId -> MH ()) -> MH ()
forall a b. (a -> b) -> a -> b
$ \TeamId
tId -> do
                            Maybe ThreadInterface
ti <- Getting (Maybe ThreadInterface) ChatState (Maybe ThreadInterface)
-> MH (Maybe ThreadInterface)
forall s (m :: * -> *) a. MonadState s m => Getting a s a -> m a
use (TeamId -> Lens' ChatState TeamState
csTeam(TeamId
tId)((TeamState -> Const (Maybe ThreadInterface) TeamState)
 -> ChatState -> Const (Maybe ThreadInterface) ChatState)
-> ((Maybe ThreadInterface
     -> Const (Maybe ThreadInterface) (Maybe ThreadInterface))
    -> TeamState -> Const (Maybe ThreadInterface) TeamState)
-> Getting
     (Maybe ThreadInterface) ChatState (Maybe ThreadInterface)
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(Maybe ThreadInterface
 -> Const (Maybe ThreadInterface) (Maybe ThreadInterface))
-> TeamState -> Const (Maybe ThreadInterface) TeamState
Lens' TeamState (Maybe ThreadInterface)
tsThreadInterface)
                            MessageInterfaceFocus
foc <- Getting MessageInterfaceFocus ChatState MessageInterfaceFocus
-> MH MessageInterfaceFocus
forall s (m :: * -> *) a. MonadState s m => Getting a s a -> m a
use (TeamId -> Lens' ChatState TeamState
csTeam(TeamId
tId)((TeamState -> Const MessageInterfaceFocus TeamState)
 -> ChatState -> Const MessageInterfaceFocus ChatState)
-> ((MessageInterfaceFocus
     -> Const MessageInterfaceFocus MessageInterfaceFocus)
    -> TeamState -> Const MessageInterfaceFocus TeamState)
-> Getting MessageInterfaceFocus ChatState MessageInterfaceFocus
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(MessageInterfaceFocus
 -> Const MessageInterfaceFocus MessageInterfaceFocus)
-> TeamState -> Const MessageInterfaceFocus TeamState
Lens' TeamState MessageInterfaceFocus
tsMessageInterfaceFocus)
                            Bool -> MH () -> MH ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Maybe ThreadInterface -> Bool
forall a. Maybe a -> Bool
isJust Maybe ThreadInterface
ti Bool -> Bool -> Bool
&& MessageInterfaceFocus
foc MessageInterfaceFocus -> MessageInterfaceFocus -> Bool
forall a. Eq a => a -> a -> Bool
== MessageInterfaceFocus
FocusThread) (MH () -> MH ()) -> MH () -> MH ()
forall a b. (a -> b) -> a -> b
$
                                TeamId -> MH ()
closeThreadWindow TeamId
tId

replyToLatestMessage :: Lens' ChatState (EditState Name) -> MH ()
replyToLatestMessage :: Lens' ChatState (EditState Name) -> MH ()
replyToLatestMessage Lens' ChatState (EditState Name)
which = do
    ChannelId
cId <- Getting ChannelId ChatState ChannelId -> MH ChannelId
forall s (m :: * -> *) a. MonadState s m => Getting a s a -> m a
use ((EditState Name -> Const ChannelId (EditState Name))
-> ChatState -> Const ChannelId ChatState
Lens' ChatState (EditState Name)
which((EditState Name -> Const ChannelId (EditState Name))
 -> ChatState -> Const ChannelId ChatState)
-> ((ChannelId -> Const ChannelId ChannelId)
    -> EditState Name -> Const ChannelId (EditState Name))
-> Getting ChannelId ChatState ChannelId
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(ChannelId -> Const ChannelId ChannelId)
-> EditState Name -> Const ChannelId (EditState Name)
forall n. Lens' (EditState n) ChannelId
esChannelId)
    ChannelId -> (ClientChannel -> MH ()) -> MH ()
withChannel ChannelId
cId ((ClientChannel -> MH ()) -> MH ())
-> (ClientChannel -> MH ()) -> MH ()
forall a b. (a -> b) -> a -> b
$ \ClientChannel
chan -> do
        let msgs :: Messages
msgs = ClientChannel
chanClientChannel
-> Getting Messages ClientChannel Messages -> Messages
forall s a. s -> Getting a s a -> a
^.(ChannelMessageInterface -> Const Messages ChannelMessageInterface)
-> ClientChannel -> Const Messages ClientChannel
Lens' ClientChannel ChannelMessageInterface
ccMessageInterface((ChannelMessageInterface
  -> Const Messages ChannelMessageInterface)
 -> ClientChannel -> Const Messages ClientChannel)
-> ((Messages -> Const Messages Messages)
    -> ChannelMessageInterface
    -> Const Messages ChannelMessageInterface)
-> Getting Messages ClientChannel Messages
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(Messages -> Const Messages Messages)
-> ChannelMessageInterface
-> Const Messages ChannelMessageInterface
forall n i. Lens' (MessageInterface n i) Messages
miMessages
        case (Message -> Bool) -> Messages -> Maybe Message
findLatestUserMessage Message -> Bool
isReplyable Messages
msgs of
          Just Message
msg | Message -> Bool
isReplyable Message
msg ->
              do Message
rootMsg <- Message -> MH Message
getReplyRootMessage Message
msg
                 ChannelId -> MH ()
invalidateChannelRenderingCache ChannelId
cId
                 (EditState Name -> Identity (EditState Name))
-> ChatState -> Identity ChatState
Lens' ChatState (EditState Name)
which((EditState Name -> Identity (EditState Name))
 -> ChatState -> Identity ChatState)
-> ((EditMode -> Identity EditMode)
    -> EditState Name -> Identity (EditState Name))
-> (EditMode -> Identity EditMode)
-> ChatState
-> Identity ChatState
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(EditMode -> Identity EditMode)
-> EditState Name -> Identity (EditState Name)
forall n. Lens' (EditState n) EditMode
esEditMode ((EditMode -> Identity EditMode)
 -> ChatState -> Identity ChatState)
-> EditMode -> MH ()
forall s (m :: * -> *) a b.
MonadState s m =>
ASetter s s a b -> b -> m ()
.= Message -> Post -> EditMode
Replying Message
rootMsg (Maybe Post -> Post
forall a. HasCallStack => Maybe a -> a
fromJust (Maybe Post -> Post) -> Maybe Post -> Post
forall a b. (a -> b) -> a -> b
$ Message
rootMsgMessage -> 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)
          Maybe Message
_ -> () -> MH ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()

data Direction = Forwards | Backwards

tabComplete :: Traversal' ChatState (EditState Name) -> Direction -> MH ()
tabComplete :: Traversal' ChatState (EditState Name) -> Direction -> MH ()
tabComplete Traversal' ChatState (EditState Name)
which Direction
dir = do
    let transform :: GenericList n t2 e2 -> GenericList n t2 e2
transform GenericList n t2 e2
list =
            let len :: Int
len = GenericList n t2 e2
listGenericList n t2 e2 -> Getting Int (GenericList n t2 e2) Int -> Int
forall s a. s -> Getting a s a -> a
^.(t2 e2 -> Const Int (t2 e2))
-> GenericList n t2 e2 -> Const Int (GenericList n t2 e2)
forall n (t1 :: * -> *) e1 (t2 :: * -> *) e2.
Lens (GenericList n t1 e1) (GenericList n t2 e2) (t1 e1) (t2 e2)
L.listElementsL((t2 e2 -> Const Int (t2 e2))
 -> GenericList n t2 e2 -> Const Int (GenericList n t2 e2))
-> ((Int -> Const Int Int) -> t2 e2 -> Const Int (t2 e2))
-> Getting Int (GenericList n t2 e2) Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(t2 e2 -> Int) -> SimpleGetter (t2 e2) Int
forall s a. (s -> a) -> SimpleGetter s a
to t2 e2 -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length
            in case Direction
dir of
                Direction
Forwards ->
                    if (GenericList n t2 e2 -> Maybe Int
forall n (t :: * -> *) e. GenericList n t e -> Maybe Int
L.listSelected GenericList n t2 e2
list Maybe Int -> Maybe Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int -> Maybe Int
forall a. a -> Maybe a
Just (Int
len Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1)) Bool -> Bool -> Bool
||
                       (GenericList n t2 e2 -> Maybe Int
forall n (t :: * -> *) e. GenericList n t e -> Maybe Int
L.listSelected GenericList n t2 e2
list Maybe Int -> Maybe Int -> Bool
forall a. Eq a => a -> a -> Bool
== Maybe Int
forall a. Maybe a
Nothing Bool -> Bool -> Bool
&& Int
len Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
0)
                    then Int -> GenericList n t2 e2 -> GenericList n t2 e2
forall (t :: * -> *) n e.
(Foldable t, Splittable t) =>
Int -> GenericList n t e -> GenericList n t e
L.listMoveTo Int
0 GenericList n t2 e2
list
                    else Int -> GenericList n t2 e2 -> GenericList n t2 e2
forall (t :: * -> *) n e.
(Foldable t, Splittable t) =>
Int -> GenericList n t e -> GenericList n t e
L.listMoveBy Int
1 GenericList n t2 e2
list
                Direction
Backwards ->
                    if (GenericList n t2 e2 -> Maybe Int
forall n (t :: * -> *) e. GenericList n t e -> Maybe Int
L.listSelected GenericList n t2 e2
list Maybe Int -> Maybe Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int -> Maybe Int
forall a. a -> Maybe a
Just Int
0) Bool -> Bool -> Bool
||
                       (GenericList n t2 e2 -> Maybe Int
forall n (t :: * -> *) e. GenericList n t e -> Maybe Int
L.listSelected GenericList n t2 e2
list Maybe Int -> Maybe Int -> Bool
forall a. Eq a => a -> a -> Bool
== Maybe Int
forall a. Maybe a
Nothing Bool -> Bool -> Bool
&& Int
len Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
0)
                    then Int -> GenericList n t2 e2 -> GenericList n t2 e2
forall (t :: * -> *) n e.
(Foldable t, Splittable t) =>
Int -> GenericList n t e -> GenericList n t e
L.listMoveTo (Int
len Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1) GenericList n t2 e2
list
                    else Int -> GenericList n t2 e2 -> GenericList n t2 e2
forall (t :: * -> *) n e.
(Foldable t, Splittable t) =>
Int -> GenericList n t e -> GenericList n t e
L.listMoveBy (-Int
1) GenericList n t2 e2
list

    (EditState Name -> Identity (EditState Name))
-> ChatState -> Identity ChatState
Traversal' ChatState (EditState Name)
which((EditState Name -> Identity (EditState Name))
 -> ChatState -> Identity ChatState)
-> ((List Name AutocompleteAlternative
     -> Identity (List Name AutocompleteAlternative))
    -> EditState Name -> Identity (EditState Name))
-> (List Name AutocompleteAlternative
    -> Identity (List Name AutocompleteAlternative))
-> ChatState
-> Identity ChatState
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(Maybe (AutocompleteState Name)
 -> Identity (Maybe (AutocompleteState Name)))
-> EditState Name -> Identity (EditState Name)
forall n. Lens' (EditState n) (Maybe (AutocompleteState n))
esAutocomplete((Maybe (AutocompleteState Name)
  -> Identity (Maybe (AutocompleteState Name)))
 -> EditState Name -> Identity (EditState Name))
-> ((List Name AutocompleteAlternative
     -> Identity (List Name AutocompleteAlternative))
    -> Maybe (AutocompleteState Name)
    -> Identity (Maybe (AutocompleteState Name)))
-> (List Name AutocompleteAlternative
    -> Identity (List Name AutocompleteAlternative))
-> EditState Name
-> Identity (EditState Name)
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(AutocompleteState Name -> Identity (AutocompleteState Name))
-> Maybe (AutocompleteState Name)
-> Identity (Maybe (AutocompleteState Name))
forall a a'. Traversal (Maybe a) (Maybe a') a a'
_Just((AutocompleteState Name -> Identity (AutocompleteState Name))
 -> Maybe (AutocompleteState Name)
 -> Identity (Maybe (AutocompleteState Name)))
-> ((List Name AutocompleteAlternative
     -> Identity (List Name AutocompleteAlternative))
    -> AutocompleteState Name -> Identity (AutocompleteState Name))
-> (List Name AutocompleteAlternative
    -> Identity (List Name AutocompleteAlternative))
-> Maybe (AutocompleteState Name)
-> Identity (Maybe (AutocompleteState Name))
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(List Name AutocompleteAlternative
 -> Identity (List Name AutocompleteAlternative))
-> AutocompleteState Name -> Identity (AutocompleteState Name)
forall n1 n2.
Lens
  (AutocompleteState n1)
  (AutocompleteState n2)
  (List n1 AutocompleteAlternative)
  (List n2 AutocompleteAlternative)
acCompletionList ((List Name AutocompleteAlternative
  -> Identity (List Name AutocompleteAlternative))
 -> ChatState -> Identity ChatState)
-> (List Name AutocompleteAlternative
    -> List Name AutocompleteAlternative)
-> MH ()
forall s (m :: * -> *) a b.
MonadState s m =>
ASetter s s a b -> (a -> b) -> m ()
%= List Name AutocompleteAlternative
-> List Name AutocompleteAlternative
forall (t2 :: * -> *) n e2.
(Splittable t2, Foldable t2) =>
GenericList n t2 e2 -> GenericList n t2 e2
transform

    Maybe (AutocompleteState Name)
mac <- Maybe (Maybe (AutocompleteState Name))
-> Maybe (AutocompleteState Name)
forall (m :: * -> *) a. Monad m => m (m a) -> m a
join (Maybe (Maybe (AutocompleteState Name))
 -> Maybe (AutocompleteState Name))
-> MH (Maybe (Maybe (AutocompleteState Name)))
-> MH (Maybe (AutocompleteState Name))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Getting
  (First (Maybe (AutocompleteState Name)))
  ChatState
  (Maybe (AutocompleteState Name))
-> MH (Maybe (Maybe (AutocompleteState Name)))
forall s (m :: * -> *) a.
MonadState s m =>
Getting (First a) s a -> m (Maybe a)
preuse ((EditState Name
 -> Const (First (Maybe (AutocompleteState Name))) (EditState Name))
-> ChatState
-> Const (First (Maybe (AutocompleteState Name))) ChatState
Traversal' ChatState (EditState Name)
which((EditState Name
  -> Const (First (Maybe (AutocompleteState Name))) (EditState Name))
 -> ChatState
 -> Const (First (Maybe (AutocompleteState Name))) ChatState)
-> ((Maybe (AutocompleteState Name)
     -> Const
          (First (Maybe (AutocompleteState Name)))
          (Maybe (AutocompleteState Name)))
    -> EditState Name
    -> Const (First (Maybe (AutocompleteState Name))) (EditState Name))
-> Getting
     (First (Maybe (AutocompleteState Name)))
     ChatState
     (Maybe (AutocompleteState Name))
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(Maybe (AutocompleteState Name)
 -> Const
      (First (Maybe (AutocompleteState Name)))
      (Maybe (AutocompleteState Name)))
-> EditState Name
-> Const (First (Maybe (AutocompleteState Name))) (EditState Name)
forall n. Lens' (EditState n) (Maybe (AutocompleteState n))
esAutocomplete)
    case Maybe (AutocompleteState Name)
mac of
        Maybe (AutocompleteState Name)
Nothing -> do
            let ctx :: AutocompleteContext
ctx = AutocompleteContext :: Bool -> Bool -> AutocompleteContext
AutocompleteContext { autocompleteManual :: Bool
autocompleteManual = Bool
True
                                          , autocompleteFirstMatch :: Bool
autocompleteFirstMatch = Bool
True
                                          }
            Traversal' ChatState (EditState Name)
-> AutocompleteContext -> MH ()
checkForAutocompletion Traversal' ChatState (EditState Name)
which AutocompleteContext
ctx
        Just AutocompleteState Name
ac -> do
            case AutocompleteState Name
acAutocompleteState Name
-> Getting
     (Maybe (Int, AutocompleteAlternative))
     (AutocompleteState Name)
     (Maybe (Int, AutocompleteAlternative))
-> Maybe (Int, AutocompleteAlternative)
forall s a. s -> Getting a s a -> a
^.(List Name AutocompleteAlternative
 -> Const
      (Maybe (Int, AutocompleteAlternative))
      (List Name AutocompleteAlternative))
-> AutocompleteState Name
-> Const
     (Maybe (Int, AutocompleteAlternative)) (AutocompleteState Name)
forall n1 n2.
Lens
  (AutocompleteState n1)
  (AutocompleteState n2)
  (List n1 AutocompleteAlternative)
  (List n2 AutocompleteAlternative)
acCompletionList((List Name AutocompleteAlternative
  -> Const
       (Maybe (Int, AutocompleteAlternative))
       (List Name AutocompleteAlternative))
 -> AutocompleteState Name
 -> Const
      (Maybe (Int, AutocompleteAlternative)) (AutocompleteState Name))
-> ((Maybe (Int, AutocompleteAlternative)
     -> Const
          (Maybe (Int, AutocompleteAlternative))
          (Maybe (Int, AutocompleteAlternative)))
    -> List Name AutocompleteAlternative
    -> Const
         (Maybe (Int, AutocompleteAlternative))
         (List Name AutocompleteAlternative))
-> Getting
     (Maybe (Int, AutocompleteAlternative))
     (AutocompleteState Name)
     (Maybe (Int, AutocompleteAlternative))
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(List Name AutocompleteAlternative
 -> Maybe (Int, AutocompleteAlternative))
-> SimpleGetter
     (List Name AutocompleteAlternative)
     (Maybe (Int, AutocompleteAlternative))
forall s a. (s -> a) -> SimpleGetter s a
to List Name AutocompleteAlternative
-> Maybe (Int, AutocompleteAlternative)
forall (t :: * -> *) n e.
(Splittable t, Foldable t) =>
GenericList n t e -> Maybe (Int, e)
L.listSelectedElement of
                Maybe (Int, AutocompleteAlternative)
Nothing -> () -> MH ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
                Just (Int
_, AutocompleteAlternative
alternative) -> do
                    let replacement :: Text
replacement = AutocompleteAlternative -> Text
autocompleteAlternativeReplacement AutocompleteAlternative
alternative
                        maybeEndOfWord :: TextZipper a -> TextZipper a
maybeEndOfWord TextZipper a
z =
                            if Bool -> (Char -> Bool) -> Maybe Char -> Bool
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Bool
True Char -> Bool
isSpace (TextZipper a -> Maybe Char
forall a. TextZipper a -> Maybe Char
Z.currentChar TextZipper a
z)
                            then TextZipper a
z
                            else TextZipper a -> TextZipper a
forall a. GenericTextZipper a => TextZipper a -> TextZipper a
Z.moveWordRight TextZipper a
z
                    (EditState Name -> Identity (EditState Name))
-> ChatState -> Identity ChatState
Traversal' ChatState (EditState Name)
which((EditState Name -> Identity (EditState Name))
 -> ChatState -> Identity ChatState)
-> ((Editor Text Name -> Identity (Editor Text Name))
    -> EditState Name -> Identity (EditState Name))
-> (Editor Text Name -> Identity (Editor Text Name))
-> ChatState
-> Identity ChatState
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(Editor Text Name -> Identity (Editor Text Name))
-> EditState Name -> Identity (EditState Name)
forall n. Lens' (EditState n) (Editor Text n)
esEditor ((Editor Text Name -> Identity (Editor Text Name))
 -> ChatState -> Identity ChatState)
-> (Editor Text Name -> Editor Text Name) -> MH ()
forall s (m :: * -> *) a b.
MonadState s m =>
ASetter s s a b -> (a -> b) -> m ()
%=
                        (TextZipper Text -> TextZipper Text)
-> Editor Text Name -> Editor Text Name
forall t n.
(TextZipper t -> TextZipper t) -> Editor t n -> Editor t n
applyEdit (Char -> TextZipper Text -> TextZipper Text
forall a. Monoid a => Char -> TextZipper a -> TextZipper a
Z.insertChar Char
' ' (TextZipper Text -> TextZipper Text)
-> (TextZipper Text -> TextZipper Text)
-> TextZipper Text
-> TextZipper Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> TextZipper Text -> TextZipper Text
forall a. Monoid a => a -> TextZipper a -> TextZipper a
Z.insertMany Text
replacement (TextZipper Text -> TextZipper Text)
-> (TextZipper Text -> TextZipper Text)
-> TextZipper Text
-> TextZipper Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. TextZipper Text -> TextZipper Text
forall a.
(Eq a, GenericTextZipper a) =>
TextZipper a -> TextZipper a
Z.deletePrevWord (TextZipper Text -> TextZipper Text)
-> (TextZipper Text -> TextZipper Text)
-> TextZipper Text
-> TextZipper Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
                                   TextZipper Text -> TextZipper Text
forall a. GenericTextZipper a => TextZipper a -> TextZipper a
maybeEndOfWord)
                    (EditState Name -> Identity (EditState Name))
-> ChatState -> Identity ChatState
Traversal' ChatState (EditState Name)
which((EditState Name -> Identity (EditState Name))
 -> ChatState -> Identity ChatState)
-> ((Bool -> Identity Bool)
    -> EditState Name -> Identity (EditState Name))
-> (Bool -> Identity Bool)
-> ChatState
-> Identity ChatState
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(Bool -> Identity Bool)
-> EditState Name -> Identity (EditState Name)
forall n. Lens' (EditState n) Bool
esJustCompleted ((Bool -> Identity Bool) -> ChatState -> Identity ChatState)
-> Bool -> MH ()
forall s (m :: * -> *) a b.
MonadState s m =>
ASetter s s a b -> b -> m ()
.= Bool
True

                    -- If there was only one completion alternative,
                    -- hide the autocomplete listing now that we've
                    -- completed the only completion.
                    Bool -> MH () -> MH ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (AutocompleteState Name
acAutocompleteState Name
-> Getting Int (AutocompleteState Name) Int -> Int
forall s a. s -> Getting a s a -> a
^.(List Name AutocompleteAlternative
 -> Const Int (List Name AutocompleteAlternative))
-> AutocompleteState Name -> Const Int (AutocompleteState Name)
forall n1 n2.
Lens
  (AutocompleteState n1)
  (AutocompleteState n2)
  (List n1 AutocompleteAlternative)
  (List n2 AutocompleteAlternative)
acCompletionList((List Name AutocompleteAlternative
  -> Const Int (List Name AutocompleteAlternative))
 -> AutocompleteState Name -> Const Int (AutocompleteState Name))
-> ((Int -> Const Int Int)
    -> List Name AutocompleteAlternative
    -> Const Int (List Name AutocompleteAlternative))
-> Getting Int (AutocompleteState Name) Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(List Name AutocompleteAlternative
 -> Vector AutocompleteAlternative)
-> SimpleGetter
     (List Name AutocompleteAlternative)
     (Vector AutocompleteAlternative)
forall s a. (s -> a) -> SimpleGetter s a
to List Name AutocompleteAlternative -> Vector AutocompleteAlternative
forall n (t :: * -> *) e. GenericList n t e -> t e
L.listElementsGetting
  Int
  (List Name AutocompleteAlternative)
  (Vector AutocompleteAlternative)
-> ((Int -> Const Int Int)
    -> Vector AutocompleteAlternative
    -> Const Int (Vector AutocompleteAlternative))
-> (Int -> Const Int Int)
-> List Name AutocompleteAlternative
-> Const Int (List Name AutocompleteAlternative)
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(Vector AutocompleteAlternative -> Int)
-> SimpleGetter (Vector AutocompleteAlternative) Int
forall s a. (s -> a) -> SimpleGetter s a
to Vector AutocompleteAlternative -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
1) (Traversal' ChatState (EditState Name) -> MH ()
forall n. Traversal' ChatState (EditState n) -> MH ()
resetAutocomplete Traversal' ChatState (EditState Name)
which)

resetAttachmentList :: Lens' ChatState (EditState Name) -> MH ()
resetAttachmentList :: Lens' ChatState (EditState Name) -> MH ()
resetAttachmentList Lens' ChatState (EditState Name)
which = do
    (EditState Name -> Identity (EditState Name))
-> ChatState -> Identity ChatState
Lens' ChatState (EditState Name)
which((EditState Name -> Identity (EditState Name))
 -> ChatState -> Identity ChatState)
-> ((List Name AttachmentData
     -> Identity (List Name AttachmentData))
    -> EditState Name -> Identity (EditState Name))
-> (List Name AttachmentData
    -> Identity (List Name AttachmentData))
-> ChatState
-> Identity ChatState
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(List Name AttachmentData -> Identity (List Name AttachmentData))
-> EditState Name -> Identity (EditState Name)
forall n. Lens' (EditState n) (List n AttachmentData)
esAttachmentList ((List Name AttachmentData -> Identity (List Name AttachmentData))
 -> ChatState -> Identity ChatState)
-> (List Name AttachmentData -> List Name AttachmentData) -> MH ()
forall s (m :: * -> *) a b.
MonadState s m =>
ASetter s s a b -> (a -> b) -> m ()
%= List Name AttachmentData -> List Name AttachmentData
forall (t :: * -> *) e n.
Monoid (t e) =>
GenericList n t e -> GenericList n t e
L.listClear