mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2025-06-29 04:39:53 +00:00
terminal: support multiline messages (as JSON strings) (#1936)
* terminal: support for multiline messages * fix * fix tests
This commit is contained in:
parent
b7575ec01d
commit
7c4c627ee9
4 changed files with 56 additions and 38 deletions
|
@ -1018,7 +1018,7 @@ processChatCommand = \case
|
||||||
SendMessageBroadcast msg -> withUser $ \user -> do
|
SendMessageBroadcast msg -> withUser $ \user -> do
|
||||||
contacts <- withStore' (`getUserContacts` user)
|
contacts <- withStore' (`getUserContacts` user)
|
||||||
withChatLock "sendMessageBroadcast" . procCmd $ do
|
withChatLock "sendMessageBroadcast" . procCmd $ do
|
||||||
let mc = MCText $ safeDecodeUtf8 msg
|
let mc = MCText msg
|
||||||
cts = filter (\ct -> isReady ct && directOrUsed ct) contacts
|
cts = filter (\ct -> isReady ct && directOrUsed ct) contacts
|
||||||
forM_ cts $ \ct ->
|
forM_ cts $ \ct ->
|
||||||
void
|
void
|
||||||
|
@ -1030,8 +1030,8 @@ processChatCommand = \case
|
||||||
CRBroadcastSent user mc (length cts) <$> liftIO getZonedTime
|
CRBroadcastSent user mc (length cts) <$> liftIO getZonedTime
|
||||||
SendMessageQuote cName (AMsgDirection msgDir) quotedMsg msg -> withUser $ \user@User {userId} -> do
|
SendMessageQuote cName (AMsgDirection msgDir) quotedMsg msg -> withUser $ \user@User {userId} -> do
|
||||||
contactId <- withStore $ \db -> getContactIdByName db user cName
|
contactId <- withStore $ \db -> getContactIdByName db user cName
|
||||||
quotedItemId <- withStore $ \db -> getDirectChatItemIdByText db userId contactId msgDir (safeDecodeUtf8 quotedMsg)
|
quotedItemId <- withStore $ \db -> getDirectChatItemIdByText db userId contactId msgDir quotedMsg
|
||||||
let mc = MCText $ safeDecodeUtf8 msg
|
let mc = MCText msg
|
||||||
processChatCommand . APISendMessage (ChatRef CTDirect contactId) False $ ComposedMessage Nothing (Just quotedItemId) mc
|
processChatCommand . APISendMessage (ChatRef CTDirect contactId) False $ ComposedMessage Nothing (Just quotedItemId) mc
|
||||||
DeleteMessage chatName deletedMsg -> withUser $ \user -> do
|
DeleteMessage chatName deletedMsg -> withUser $ \user -> do
|
||||||
chatRef <- getChatRef user chatName
|
chatRef <- getChatRef user chatName
|
||||||
|
@ -1039,16 +1039,16 @@ processChatCommand = \case
|
||||||
processChatCommand $ APIDeleteChatItem chatRef deletedItemId CIDMBroadcast
|
processChatCommand $ APIDeleteChatItem chatRef deletedItemId CIDMBroadcast
|
||||||
DeleteMemberMessage gName mName deletedMsg -> withUser $ \user -> do
|
DeleteMemberMessage gName mName deletedMsg -> withUser $ \user -> do
|
||||||
(gId, mId) <- getGroupAndMemberId user gName mName
|
(gId, mId) <- getGroupAndMemberId user gName mName
|
||||||
deletedItemId <- withStore $ \db -> getGroupChatItemIdByText db user gId (Just mName) $ safeDecodeUtf8 deletedMsg
|
deletedItemId <- withStore $ \db -> getGroupChatItemIdByText db user gId (Just mName) deletedMsg
|
||||||
processChatCommand $ APIDeleteMemberChatItem gId mId deletedItemId
|
processChatCommand $ APIDeleteMemberChatItem gId mId deletedItemId
|
||||||
EditMessage chatName editedMsg msg -> withUser $ \user -> do
|
EditMessage chatName editedMsg msg -> withUser $ \user -> do
|
||||||
chatRef <- getChatRef user chatName
|
chatRef <- getChatRef user chatName
|
||||||
editedItemId <- getSentChatItemIdByText user chatRef editedMsg
|
editedItemId <- getSentChatItemIdByText user chatRef editedMsg
|
||||||
let mc = MCText $ safeDecodeUtf8 msg
|
let mc = MCText msg
|
||||||
processChatCommand $ APIUpdateChatItem chatRef editedItemId False mc
|
processChatCommand $ APIUpdateChatItem chatRef editedItemId False mc
|
||||||
UpdateLiveMessage chatName chatItemId live msg -> withUser $ \user -> do
|
UpdateLiveMessage chatName chatItemId live msg -> withUser $ \user -> do
|
||||||
chatRef <- getChatRef user chatName
|
chatRef <- getChatRef user chatName
|
||||||
let mc = MCText $ safeDecodeUtf8 msg
|
let mc = MCText msg
|
||||||
processChatCommand $ APIUpdateChatItem chatRef chatItemId live mc
|
processChatCommand $ APIUpdateChatItem chatRef chatItemId live mc
|
||||||
APINewGroup userId gProfile -> withUserId userId $ \user -> do
|
APINewGroup userId gProfile -> withUserId userId $ \user -> do
|
||||||
gVar <- asks idsDrg
|
gVar <- asks idsDrg
|
||||||
|
@ -1217,8 +1217,8 @@ processChatCommand = \case
|
||||||
processChatCommand $ APIGetGroupLink groupId
|
processChatCommand $ APIGetGroupLink groupId
|
||||||
SendGroupMessageQuote gName cName quotedMsg msg -> withUser $ \user -> do
|
SendGroupMessageQuote gName cName quotedMsg msg -> withUser $ \user -> do
|
||||||
groupId <- withStore $ \db -> getGroupIdByName db user gName
|
groupId <- withStore $ \db -> getGroupIdByName db user gName
|
||||||
quotedItemId <- withStore $ \db -> getGroupChatItemIdByText db user groupId cName (safeDecodeUtf8 quotedMsg)
|
quotedItemId <- withStore $ \db -> getGroupChatItemIdByText db user groupId cName quotedMsg
|
||||||
let mc = MCText $ safeDecodeUtf8 msg
|
let mc = MCText msg
|
||||||
processChatCommand . APISendMessage (ChatRef CTGroup groupId) False $ ComposedMessage Nothing (Just quotedItemId) mc
|
processChatCommand . APISendMessage (ChatRef CTGroup groupId) False $ ComposedMessage Nothing (Just quotedItemId) mc
|
||||||
LastChats count_ -> withUser' $ \user -> do
|
LastChats count_ -> withUser' $ \user -> do
|
||||||
chats <- withStore' $ \db -> getChatPreviews db user False
|
chats <- withStore' $ \db -> getChatPreviews db user False
|
||||||
|
@ -1386,10 +1386,10 @@ processChatCommand = \case
|
||||||
code' <- getConnectionCode $ aConnId conn
|
code' <- getConnectionCode $ aConnId conn
|
||||||
withStore' $ \db -> setConnectionVerified db user connId Nothing
|
withStore' $ \db -> setConnectionVerified db user connId Nothing
|
||||||
pure $ CRConnectionVerified user False code'
|
pure $ CRConnectionVerified user False code'
|
||||||
getSentChatItemIdByText :: User -> ChatRef -> ByteString -> m Int64
|
getSentChatItemIdByText :: User -> ChatRef -> Text -> m Int64
|
||||||
getSentChatItemIdByText user@User {userId, localDisplayName} (ChatRef cType cId) msg = case cType of
|
getSentChatItemIdByText user@User {userId, localDisplayName} (ChatRef cType cId) msg = case cType of
|
||||||
CTDirect -> withStore $ \db -> getDirectChatItemIdByText db userId cId SMDSnd (safeDecodeUtf8 msg)
|
CTDirect -> withStore $ \db -> getDirectChatItemIdByText db userId cId SMDSnd msg
|
||||||
CTGroup -> withStore $ \db -> getGroupChatItemIdByText db user cId (Just localDisplayName) (safeDecodeUtf8 msg)
|
CTGroup -> withStore $ \db -> getGroupChatItemIdByText db user cId (Just localDisplayName) msg
|
||||||
_ -> throwChatError $ CECommandError "not supported"
|
_ -> throwChatError $ CECommandError "not supported"
|
||||||
connectViaContact :: User -> ConnectionRequestUri 'CMContact -> m ChatResponse
|
connectViaContact :: User -> ConnectionRequestUri 'CMContact -> m ChatResponse
|
||||||
connectViaContact user@User {userId} cReq@(CRContactUri ConnReqUriData {crClientData}) = withChatLock "connectViaContact" $ do
|
connectViaContact user@User {userId} cReq@(CRContactUri ConnReqUriData {crClientData}) = withChatLock "connectViaContact" $ do
|
||||||
|
@ -1543,7 +1543,7 @@ processChatCommand = \case
|
||||||
setActive $ ActiveG localDisplayName
|
setActive $ ActiveG localDisplayName
|
||||||
sendTextMessage chatName msg live = withUser $ \user -> do
|
sendTextMessage chatName msg live = withUser $ \user -> do
|
||||||
chatRef <- getChatRef user chatName
|
chatRef <- getChatRef user chatName
|
||||||
let mc = MCText $ safeDecodeUtf8 msg
|
let mc = MCText msg
|
||||||
processChatCommand . APISendMessage chatRef live $ ComposedMessage Nothing Nothing mc
|
processChatCommand . APISendMessage chatRef live $ ComposedMessage Nothing Nothing mc
|
||||||
sndContactCITimed :: Bool -> Contact -> m (Maybe CITimed)
|
sndContactCITimed :: Bool -> Contact -> m (Maybe CITimed)
|
||||||
sndContactCITimed live = mapM (sndCITimed_ live) . contactTimedTTL
|
sndContactCITimed live = mapM (sndCITimed_ live) . contactTimedTTL
|
||||||
|
@ -4056,29 +4056,29 @@ chatCommandP =
|
||||||
"/_group_profile #" *> (APIUpdateGroupProfile <$> A.decimal <* A.space <*> jsonP),
|
"/_group_profile #" *> (APIUpdateGroupProfile <$> A.decimal <* A.space <*> jsonP),
|
||||||
("/group_profile " <|> "/gp ") *> char_ '#' *> (UpdateGroupNames <$> displayName <* A.space <*> groupProfile),
|
("/group_profile " <|> "/gp ") *> char_ '#' *> (UpdateGroupNames <$> displayName <* A.space <*> groupProfile),
|
||||||
("/group_profile " <|> "/gp ") *> char_ '#' *> (ShowGroupProfile <$> displayName),
|
("/group_profile " <|> "/gp ") *> char_ '#' *> (ShowGroupProfile <$> displayName),
|
||||||
"/group_descr " *> char_ '#' *> (UpdateGroupDescription <$> displayName <*> optional (A.space *> (jsonP <|> textP))),
|
"/group_descr " *> char_ '#' *> (UpdateGroupDescription <$> displayName <*> optional (A.space *> msgTextP)),
|
||||||
"/_create link #" *> (APICreateGroupLink <$> A.decimal),
|
"/_create link #" *> (APICreateGroupLink <$> A.decimal),
|
||||||
"/_delete link #" *> (APIDeleteGroupLink <$> A.decimal),
|
"/_delete link #" *> (APIDeleteGroupLink <$> A.decimal),
|
||||||
"/_get link #" *> (APIGetGroupLink <$> A.decimal),
|
"/_get link #" *> (APIGetGroupLink <$> A.decimal),
|
||||||
"/create link #" *> (CreateGroupLink <$> displayName),
|
"/create link #" *> (CreateGroupLink <$> displayName),
|
||||||
"/delete link #" *> (DeleteGroupLink <$> displayName),
|
"/delete link #" *> (DeleteGroupLink <$> displayName),
|
||||||
"/show link #" *> (ShowGroupLink <$> displayName),
|
"/show link #" *> (ShowGroupLink <$> displayName),
|
||||||
(">#" <|> "> #") *> (SendGroupMessageQuote <$> displayName <* A.space <*> pure Nothing <*> quotedMsg <*> A.takeByteString),
|
(">#" <|> "> #") *> (SendGroupMessageQuote <$> displayName <* A.space <*> pure Nothing <*> quotedMsg <*> msgTextP),
|
||||||
(">#" <|> "> #") *> (SendGroupMessageQuote <$> displayName <* A.space <* char_ '@' <*> (Just <$> displayName) <* A.space <*> quotedMsg <*> A.takeByteString),
|
(">#" <|> "> #") *> (SendGroupMessageQuote <$> displayName <* A.space <* char_ '@' <*> (Just <$> displayName) <* A.space <*> quotedMsg <*> msgTextP),
|
||||||
"/_contacts " *> (APIListContacts <$> A.decimal),
|
"/_contacts " *> (APIListContacts <$> A.decimal),
|
||||||
"/contacts" $> ListContacts,
|
"/contacts" $> ListContacts,
|
||||||
"/_connect " *> (APIConnect <$> A.decimal <* A.space <*> ((Just <$> strP) <|> A.takeByteString $> Nothing)),
|
"/_connect " *> (APIConnect <$> A.decimal <* A.space <*> ((Just <$> strP) <|> A.takeByteString $> Nothing)),
|
||||||
"/_connect " *> (APIAddContact <$> A.decimal),
|
"/_connect " *> (APIAddContact <$> A.decimal),
|
||||||
("/connect " <|> "/c ") *> (Connect <$> ((Just <$> strP) <|> A.takeByteString $> Nothing)),
|
("/connect " <|> "/c ") *> (Connect <$> ((Just <$> strP) <|> A.takeByteString $> Nothing)),
|
||||||
("/connect" <|> "/c") $> AddContact,
|
("/connect" <|> "/c") $> AddContact,
|
||||||
SendMessage <$> chatNameP <* A.space <*> A.takeByteString,
|
SendMessage <$> chatNameP <* A.space <*> msgTextP,
|
||||||
"/live " *> (SendLiveMessage <$> chatNameP <*> (A.space *> A.takeByteString <|> pure "")),
|
"/live " *> (SendLiveMessage <$> chatNameP <*> (A.space *> msgTextP <|> pure "")),
|
||||||
(">@" <|> "> @") *> sendMsgQuote (AMsgDirection SMDRcv),
|
(">@" <|> "> @") *> sendMsgQuote (AMsgDirection SMDRcv),
|
||||||
(">>@" <|> ">> @") *> sendMsgQuote (AMsgDirection SMDSnd),
|
(">>@" <|> ">> @") *> sendMsgQuote (AMsgDirection SMDSnd),
|
||||||
("\\ " <|> "\\") *> (DeleteMessage <$> chatNameP <* A.space <*> A.takeByteString),
|
("\\ " <|> "\\") *> (DeleteMessage <$> chatNameP <* A.space <*> textP),
|
||||||
("\\\\ #" <|> "\\\\#") *> (DeleteMemberMessage <$> displayName <* A.space <* char_ '@' <*> displayName <* A.space <*> A.takeByteString),
|
("\\\\ #" <|> "\\\\#") *> (DeleteMemberMessage <$> displayName <* A.space <* char_ '@' <*> displayName <* A.space <*> textP),
|
||||||
("! " <|> "!") *> (EditMessage <$> chatNameP <* A.space <*> (quotedMsg <|> pure "") <*> A.takeByteString),
|
("! " <|> "!") *> (EditMessage <$> chatNameP <* A.space <*> (quotedMsg <|> pure "") <*> msgTextP),
|
||||||
"/feed " *> (SendMessageBroadcast <$> A.takeByteString),
|
"/feed " *> (SendMessageBroadcast <$> msgTextP),
|
||||||
("/chats" <|> "/cs") *> (LastChats <$> (" all" $> Nothing <|> Just <$> (A.space *> A.decimal <|> pure 20))),
|
("/chats" <|> "/cs") *> (LastChats <$> (" all" $> Nothing <|> Just <$> (A.space *> A.decimal <|> pure 20))),
|
||||||
("/tail" <|> "/t") *> (LastMessages <$> optional (A.space *> chatNameP) <*> msgCountP <*> pure Nothing),
|
("/tail" <|> "/t") *> (LastMessages <$> optional (A.space *> chatNameP) <*> msgCountP <*> pure Nothing),
|
||||||
("/search" <|> "/?") *> (LastMessages <$> optional (A.space *> chatNameP) <*> msgCountP <*> (Just <$> (A.space *> stringP))),
|
("/search" <|> "/?") *> (LastMessages <$> optional (A.space *> chatNameP) <*> msgCountP <*> (Just <$> (A.space *> stringP))),
|
||||||
|
@ -4139,8 +4139,8 @@ chatCommandP =
|
||||||
msgContentP = "text " *> mcTextP <|> "json " *> jsonP
|
msgContentP = "text " *> mcTextP <|> "json " *> jsonP
|
||||||
ciDeleteMode = "broadcast" $> CIDMBroadcast <|> "internal" $> CIDMInternal
|
ciDeleteMode = "broadcast" $> CIDMBroadcast <|> "internal" $> CIDMInternal
|
||||||
displayName = safeDecodeUtf8 <$> (B.cons <$> A.satisfy refChar <*> A.takeTill (== ' '))
|
displayName = safeDecodeUtf8 <$> (B.cons <$> A.satisfy refChar <*> A.takeTill (== ' '))
|
||||||
sendMsgQuote msgDir = SendMessageQuote <$> displayName <* A.space <*> pure msgDir <*> quotedMsg <*> A.takeByteString
|
sendMsgQuote msgDir = SendMessageQuote <$> displayName <* A.space <*> pure msgDir <*> quotedMsg <*> msgTextP
|
||||||
quotedMsg = A.char '(' *> A.takeTill (== ')') <* A.char ')' <* optional A.space
|
quotedMsg = safeDecodeUtf8 <$> (A.char '(' *> A.takeTill (== ')') <* A.char ')') <* optional A.space
|
||||||
refChar c = c > ' ' && c /= '#' && c /= '@'
|
refChar c = c > ' ' && c /= '#' && c /= '@'
|
||||||
liveMessageP = " live=" *> onOffP <|> pure False
|
liveMessageP = " live=" *> onOffP <|> pure False
|
||||||
onOffP = ("on" $> True) <|> ("off" $> False)
|
onOffP = ("on" $> True) <|> ("off" $> False)
|
||||||
|
@ -4162,6 +4162,7 @@ chatCommandP =
|
||||||
n <- (A.space *> A.takeByteString) <|> pure ""
|
n <- (A.space *> A.takeByteString) <|> pure ""
|
||||||
pure $ if B.null n then name else safeDecodeUtf8 n
|
pure $ if B.null n then name else safeDecodeUtf8 n
|
||||||
textP = safeDecodeUtf8 <$> A.takeByteString
|
textP = safeDecodeUtf8 <$> A.takeByteString
|
||||||
|
msgTextP = jsonP <|> textP
|
||||||
stringP = T.unpack . safeDecodeUtf8 <$> A.takeByteString
|
stringP = T.unpack . safeDecodeUtf8 <$> A.takeByteString
|
||||||
filePath = stringP
|
filePath = stringP
|
||||||
memberRole =
|
memberRole =
|
||||||
|
|
|
@ -293,14 +293,14 @@ data ChatCommand
|
||||||
| AddressAutoAccept (Maybe AutoAccept)
|
| AddressAutoAccept (Maybe AutoAccept)
|
||||||
| AcceptContact ContactName
|
| AcceptContact ContactName
|
||||||
| RejectContact ContactName
|
| RejectContact ContactName
|
||||||
| SendMessage ChatName ByteString
|
| SendMessage ChatName Text
|
||||||
| SendLiveMessage ChatName ByteString
|
| SendLiveMessage ChatName Text
|
||||||
| SendMessageQuote {contactName :: ContactName, msgDir :: AMsgDirection, quotedMsg :: ByteString, message :: ByteString}
|
| SendMessageQuote {contactName :: ContactName, msgDir :: AMsgDirection, quotedMsg :: Text, message :: Text}
|
||||||
| SendMessageBroadcast ByteString -- UserId (not used in UI)
|
| SendMessageBroadcast Text -- UserId (not used in UI)
|
||||||
| DeleteMessage ChatName ByteString
|
| DeleteMessage ChatName Text
|
||||||
| DeleteMemberMessage GroupName ContactName ByteString
|
| DeleteMemberMessage GroupName ContactName Text
|
||||||
| EditMessage {chatName :: ChatName, editedMsg :: ByteString, message :: ByteString}
|
| EditMessage {chatName :: ChatName, editedMsg :: Text, message :: Text}
|
||||||
| UpdateLiveMessage {chatName :: ChatName, chatItemId :: ChatItemId, liveMessage :: Bool, message :: ByteString}
|
| UpdateLiveMessage {chatName :: ChatName, chatItemId :: ChatItemId, liveMessage :: Bool, message :: Text}
|
||||||
| APINewGroup UserId GroupProfile
|
| APINewGroup UserId GroupProfile
|
||||||
| NewGroup GroupProfile
|
| NewGroup GroupProfile
|
||||||
| AddMember GroupName ContactName GroupMemberRole
|
| AddMember GroupName ContactName GroupMemberRole
|
||||||
|
@ -318,7 +318,7 @@ data ChatCommand
|
||||||
| CreateGroupLink GroupName
|
| CreateGroupLink GroupName
|
||||||
| DeleteGroupLink GroupName
|
| DeleteGroupLink GroupName
|
||||||
| ShowGroupLink GroupName
|
| ShowGroupLink GroupName
|
||||||
| SendGroupMessageQuote {groupName :: GroupName, contactName_ :: Maybe ContactName, quotedMsg :: ByteString, message :: ByteString}
|
| SendGroupMessageQuote {groupName :: GroupName, contactName_ :: Maybe ContactName, quotedMsg :: Text, message :: Text}
|
||||||
| LastChats (Maybe Int) -- UserId (not used in UI)
|
| LastChats (Maybe Int) -- UserId (not used in UI)
|
||||||
| LastMessages (Maybe ChatName) Int (Maybe String) -- UserId (not used in UI)
|
| LastMessages (Maybe ChatName) Int (Maybe String) -- UserId (not used in UI)
|
||||||
| LastChatItemId (Maybe ChatName) Int -- UserId (not used in UI)
|
| LastChatItemId (Maybe ChatName) Int -- UserId (not used in UI)
|
||||||
|
|
|
@ -23,7 +23,7 @@ import Simplex.Chat.Controller
|
||||||
import Simplex.Chat.Messages
|
import Simplex.Chat.Messages
|
||||||
import Simplex.Chat.Styled
|
import Simplex.Chat.Styled
|
||||||
import Simplex.Chat.Terminal.Output
|
import Simplex.Chat.Terminal.Output
|
||||||
import Simplex.Messaging.Util (safeDecodeUtf8, whenM)
|
import Simplex.Messaging.Util (whenM)
|
||||||
import System.Exit (exitSuccess)
|
import System.Exit (exitSuccess)
|
||||||
import System.Terminal hiding (insertChars)
|
import System.Terminal hiding (insertChars)
|
||||||
import UnliftIO.STM
|
import UnliftIO.STM
|
||||||
|
@ -61,7 +61,7 @@ runInputLoop ct@ChatTerminal {termState, liveMessageState} cc = forever $ do
|
||||||
startLiveMessage :: Either a ChatCommand -> ChatResponse -> IO ()
|
startLiveMessage :: Either a ChatCommand -> ChatResponse -> IO ()
|
||||||
startLiveMessage (Right (SendLiveMessage chatName msg)) (CRNewChatItem _ (AChatItem cType SMDSnd _ ChatItem {meta = CIMeta {itemId}})) = do
|
startLiveMessage (Right (SendLiveMessage chatName msg)) (CRNewChatItem _ (AChatItem cType SMDSnd _ ChatItem {meta = CIMeta {itemId}})) = do
|
||||||
whenM (isNothing <$> readTVarIO liveMessageState) $ do
|
whenM (isNothing <$> readTVarIO liveMessageState) $ do
|
||||||
let s = T.unpack $ safeDecodeUtf8 msg
|
let s = T.unpack msg
|
||||||
int = case cType of SCTGroup -> 5000000; _ -> 3000000 :: Int
|
int = case cType of SCTGroup -> 5000000; _ -> 3000000 :: Int
|
||||||
liveThreadId <- mkWeakThreadId =<< runLiveMessage int `forkFinally` const (atomically $ writeTVar liveMessageState Nothing)
|
liveThreadId <- mkWeakThreadId =<< runLiveMessage int `forkFinally` const (atomically $ writeTVar liveMessageState Nothing)
|
||||||
promptThreadId <- mkWeakThreadId =<< forkIO blinkLivePrompt
|
promptThreadId <- mkWeakThreadId =<< forkIO blinkLivePrompt
|
||||||
|
@ -110,8 +110,7 @@ runInputLoop ct@ChatTerminal {termState, liveMessageState} cc = forever $ do
|
||||||
|
|
||||||
sendUpdatedLiveMessage :: ChatController -> String -> LiveMessage -> Bool -> IO ChatResponse
|
sendUpdatedLiveMessage :: ChatController -> String -> LiveMessage -> Bool -> IO ChatResponse
|
||||||
sendUpdatedLiveMessage cc sentMsg LiveMessage {chatName, chatItemId} live = do
|
sendUpdatedLiveMessage cc sentMsg LiveMessage {chatName, chatItemId} live = do
|
||||||
let bs = encodeUtf8 $ T.pack sentMsg
|
let cmd = UpdateLiveMessage chatName chatItemId live $ T.pack sentMsg
|
||||||
cmd = UpdateLiveMessage chatName chatItemId live bs
|
|
||||||
either (CRChatCmdError Nothing) id <$> runExceptT (processChatCommand cmd) `runReaderT` cc
|
either (CRChatCmdError Nothing) id <$> runExceptT (processChatCommand cmd) `runReaderT` cc
|
||||||
|
|
||||||
runTerminalInput :: ChatTerminal -> ChatController -> IO ()
|
runTerminalInput :: ChatTerminal -> ChatController -> IO ()
|
||||||
|
@ -238,8 +237,8 @@ updateTermState ac live tw (key, ms) ts@TerminalState {inputString = s, inputPos
|
||||||
Left _ -> inp
|
Left _ -> inp
|
||||||
Right cmd -> case cmd of
|
Right cmd -> case cmd of
|
||||||
SendMessage {} -> "! " <> inp
|
SendMessage {} -> "! " <> inp
|
||||||
SendMessageQuote {contactName, message} -> T.unpack $ "! @" <> contactName <> " " <> safeDecodeUtf8 message
|
SendMessageQuote {contactName, message} -> T.unpack $ "! @" <> contactName <> " " <> message
|
||||||
SendGroupMessageQuote {groupName, message} -> T.unpack $ "! #" <> groupName <> " " <> safeDecodeUtf8 message
|
SendGroupMessageQuote {groupName, message} -> T.unpack $ "! #" <> groupName <> " " <> message
|
||||||
_ -> inp
|
_ -> inp
|
||||||
setPosition p' = ts' (s, p')
|
setPosition p' = ts' (s, p')
|
||||||
prevWordPos
|
prevWordPos
|
||||||
|
|
|
@ -32,6 +32,7 @@ chatDirectTests = do
|
||||||
it "direct message delete" testDirectMessageDelete
|
it "direct message delete" testDirectMessageDelete
|
||||||
it "direct live message" testDirectLiveMessage
|
it "direct live message" testDirectLiveMessage
|
||||||
it "repeat AUTH errors disable contact" testRepeatAuthErrorsDisableContact
|
it "repeat AUTH errors disable contact" testRepeatAuthErrorsDisableContact
|
||||||
|
it "should send multiline message" testMultilineMessage
|
||||||
describe "SMP servers" $ do
|
describe "SMP servers" $ do
|
||||||
it "get and set SMP servers" testGetSetSMPServers
|
it "get and set SMP servers" testGetSetSMPServers
|
||||||
it "test SMP server connection" testTestSMPServerConnection
|
it "test SMP server connection" testTestSMPServerConnection
|
||||||
|
@ -369,6 +370,23 @@ testRepeatAuthErrorsDisableContact =
|
||||||
alice #> "@bob hey"
|
alice #> "@bob hey"
|
||||||
alice <## "[bob, contactId: 2, connId: 1] error: connection authorization failed - this could happen if connection was deleted, secured with different credentials, or due to a bug - please re-create the connection"
|
alice <## "[bob, contactId: 2, connId: 1] error: connection authorization failed - this could happen if connection was deleted, secured with different credentials, or due to a bug - please re-create the connection"
|
||||||
|
|
||||||
|
testMultilineMessage :: HasCallStack => FilePath -> IO ()
|
||||||
|
testMultilineMessage = testChat3 aliceProfile bobProfile cathProfile $ \alice bob cath -> do
|
||||||
|
connectUsers alice bob
|
||||||
|
connectUsers alice cath
|
||||||
|
alice `send` "@bob \"hello\\nthere\"" -- @bob "hello\nthere"
|
||||||
|
alice <# "@bob hello"
|
||||||
|
alice <## "there"
|
||||||
|
bob <# "alice> hello"
|
||||||
|
bob <## "there"
|
||||||
|
alice `send` "/feed \"hello\\nthere\"" -- /feed "hello\nthere"
|
||||||
|
alice <##. "/feed (2)"
|
||||||
|
alice <## "there"
|
||||||
|
bob <# "alice> hello"
|
||||||
|
bob <## "there"
|
||||||
|
cath <# "alice> hello"
|
||||||
|
cath <## "there"
|
||||||
|
|
||||||
testGetSetSMPServers :: HasCallStack => FilePath -> IO ()
|
testGetSetSMPServers :: HasCallStack => FilePath -> IO ()
|
||||||
testGetSetSMPServers =
|
testGetSetSMPServers =
|
||||||
testChat2 aliceProfile bobProfile $
|
testChat2 aliceProfile bobProfile $
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue