packages feed

irc-core 1.1.4 → 1.1.5

raw patch · 5 files changed

+122/−58 lines, 5 filesdep ~data-default-classdep ~lensdep ~vtyPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependency ranges changed: data-default-class, lens, vty

API changes (from Hackage documentation)

+ Irc.Model: NoPing :: PingStatus
+ Irc.Model: PingSent :: UTCTime -> PingStatus
+ Irc.Model: PingTime :: Pico -> PingStatus
+ Irc.Model: data PingStatus
+ Irc.Model: instance GHC.Read.Read Irc.Model.PingStatus
+ Irc.Model: instance GHC.Show.Show Irc.Model.PingStatus
- Irc.Model: IrcConnection :: !Identifier -> !(Map Identifier IrcChannel) -> Maybe ByteString -> [Char] -> [Char] -> !Bool -> !Int -> Maybe Char -> Maybe Char -> !(Map Identifier IrcUser) -> !ModeTypes -> !ModeTypes -> !Int -> !Int -> Maybe (ByteString, ByteString) -> Maybe (ByteString, ByteString) -> !ByteString -> !ByteString -> !Phase -> Maybe Pico -> IrcConnection
+ Irc.Model: IrcConnection :: !Identifier -> !(Map Identifier IrcChannel) -> Maybe ByteString -> [Char] -> [Char] -> !Bool -> !Int -> Maybe Char -> Maybe Char -> !(Map Identifier IrcUser) -> !ModeTypes -> !ModeTypes -> !Int -> !Int -> Maybe (ByteString, ByteString) -> Maybe (ByteString, ByteString) -> !ByteString -> !ByteString -> !Phase -> !PingStatus -> IrcConnection
- Irc.Model: [_connPingTime] :: IrcConnection -> Maybe Pico
+ Irc.Model: [_connPingTime] :: IrcConnection -> !PingStatus
- Irc.Model: connPingTime :: Lens' IrcConnection (Maybe Pico)
+ Irc.Model: connPingTime :: Lens' IrcConnection PingStatus

Files

CHANGELOG.md view
@@ -1,3 +1,9 @@+1.1.5+-------+* Show effects of control-modifiers inline when composing chat messages+* Show time since last transmitted ping+* Automatically split long chat messages+ 1.1.4 ------- * Support host-specific server-certificate sections
driver/ImageUtils.hs view
@@ -19,7 +19,8 @@ data Formatting = Formatting   { _fmtFore :: Maybe Color   , _fmtBack :: Maybe Color-  , _fmtBold, _fmtItalic, _fmtUnderline, _fmtReverse :: !Bool+  , _fmtBold, _fmtItalic, _fmtUnderline, _fmtReverse+  , _fmtExplicit :: !Bool   }  makeLenses ''Formatting@@ -57,26 +58,43 @@   where   (a,b) = Text.break isControl t +  normalFormatting = defaultFormatting { _fmtExplicit = view fmtExplicit fmt }++  explicit img+    | view fmtExplicit fmt = img+    | otherwise = emptyImage+   rest = case Text.uncons b of     Nothing -> emptyImage-    Just ('\x02',xs) -> ircFormattedText' (over fmtBold      not fmt) xs-    Just ('\x0F',xs) -> ircFormattedText' defaultFormatting           xs-    Just ('\x16',xs) -> ircFormattedText' (over fmtReverse   not fmt) xs-    Just ('\x1D',xs) -> ircFormattedText' (over fmtItalic    not fmt) xs-    Just ('\x1F',xs) -> ircFormattedText' (over fmtUnderline not fmt) xs-    Just ('\x03',xs)-      | Just (fore,xs1) <- colorNumber xs ->-         case Text.uncons xs1 of-           Just (',',xs2)-              | Just (back,xs3) <- colorNumber xs2 -> ircFormattedText'-                                                        (set fmtFore (Just fore)-                                                        (set fmtBack (Just back) fmt)) xs3-           _ -> ircFormattedText' (set fmtFore (Just fore)-                                  (set fmtBack Nothing fmt)) xs1-      | otherwise -> ircFormattedText' (set fmtFore Nothing (set fmtBack Nothing fmt)) xs+    Just (b', xs) ->+      explicit (explicitControlImage b') <|>+      case b' of+        '\^B' -> ircFormattedText' (over fmtBold      not fmt) xs+        '\^O' -> ircFormattedText' normalFormatting            xs+        '\^V' -> ircFormattedText' (over fmtReverse   not fmt) xs+        '\^]' -> ircFormattedText' (over fmtItalic    not fmt) xs+        '\^_' -> ircFormattedText' (over fmtUnderline not fmt) xs+        '\^C'+          | Just (fore,xs1) <- colorNumber xs ->+             case Text.uncons xs1 of+               Just (',',xs2)+                  | Just (back,xs3) <- colorNumber xs2 ->+                      explicit (colorNumbers xs3) <|>+                      ircFormattedText'+                        (set fmtFore (Just fore)+                        (set fmtBack (Just back) fmt)) xs3 -    Just (_,xs) -> ircFormattedText' fmt xs+               _ -> explicit (colorNumbers xs1) <|>+                    ircFormattedText'+                      (set fmtFore (Just fore)+                      (set fmtBack Nothing fmt)) xs1 +          | otherwise -> ircFormattedText' (set fmtFore Nothing (set fmtBack Nothing fmt)) xs+          where+            colorNumbers t = text' defAttr (Text.take (Text.length xs - Text.length t) xs)++        _ -> ircFormattedText' fmt xs+ colorNumber :: Text -> Maybe (Color, Text) colorNumber t =   do (c1,c2,t1) <- splitNumber t@@ -121,8 +139,12 @@   , _fmtItalic    = False   , _fmtUnderline = False   , _fmtReverse   = False+  , _fmtExplicit  = False   } +explicitFormatting :: Formatting+explicitFormatting = defaultFormatting { _fmtExplicit = True }+ formattingAttr :: Formatting -> Attr formattingAttr fmt   = addForeColor@@ -158,12 +180,16 @@   case break isControl xs of     (a,[]) -> string attr a     (a,b:bs) -> string attr a-            <|> char (withStyle attr reverseVideo)-                     (controls ! fromEnum b)+            <|> explicitControlImage b             <|> stringWithControls attr bs -  where-  controls = listArray (0,0x1f) ('@':['A'..'Z']++"[\\]^_")+explicitControlImage :: Char -> Image+explicitControlImage x =+  char (withStyle defAttr reverseVideo)+       (controlNames ! fromEnum x)++controlNames :: Array Int Char+controlNames = listArray (0,0x1f) ('@':['A'..'Z']++"[\\]^_")  nameHighlighter ::   ByteString -> Set Identifier -> Identifier -> [Color] -> Image
driver/Main.hs view
@@ -185,7 +185,8 @@  driver :: Vty -> TChan Event -> TChan (UTCTime, MsgFromServer) -> ClientState -> IO () driver vty vtyEventChan ircMsgChan st0 =-  do let (scroll', pic) = picForState st0+  do now <- getCurrentTime+     let (scroll', pic) = picForState now st0          st1 = set clientScrollPos scroll' st0      update vty pic      e <- readEitherTChan vtyEventChan ircMsgChan@@ -207,9 +208,9 @@   processTimerEvent e st =     case e of       TransmitPing ->-        do sendTimestampPing st-           st' <- schedulePing st-           considerTimers st'+        do st1 <- sendTimestampPing st+           st2 <- schedulePing st1+           considerTimers st2        DropOperator chan ->         do clientSend (modeCmd chan ["-o",views connNick idBytes conn]) st@@ -285,7 +286,9 @@     '/':_ -> case commandEvent st of                (img, Nothing) -> (img, return (KeepGoing st))                (img, Just m ) -> (img, m)-    txt -> (stringWithControls defAttr txt, fmap KeepGoing (doSendMessageCurrent SendPriv st))+    txt -> ( ircFormattedText' explicitFormatting (Text.pack txt)+           , fmap KeepGoing (doSendMessageCurrent SendPriv st)+           )  keyEvent :: Key -> [Modifier] -> ClientState -> IO KeyEventResult keyEvent k ms st =@@ -355,6 +358,18 @@       doSendMessage sendType c (Text.pack (clientInput st)) st     _ -> return st +-- Pessimistic maximum length computation for the message part for+-- privmsg and notice. Note that the need for the limit is because+-- the server will limit the length of the message sent out to each+-- client, not just the length of the messages it will recieve.+computeMaxMessageLength :: Identifier -> String -> Identifier -> Int+computeMaxMessageLength nick user target+  = 512+  - 63 -- max hostname+  - length (":~!@ PRIVMSG :\r\n"::String)+  - B8.length (idBytes nick)+  - length user+  - B8.length (idBytes target)  doSendMessage :: SendType -> Identifier -> Text -> ClientState -> IO ClientState @@ -363,22 +378,29 @@  doSendMessage sendType target message st =   do let bs = case sendType of-                SendPriv -> privMsgCmd target (Text.encodeUtf8 message)-                SendAction -> privMsgCmd target ("\SOHACTION " <>-                                                 Text.encodeUtf8 message <> "\SOH")-                SendNotice -> noticeCmd target (Text.encodeUtf8 message)-                SendCtcp cmd -> ctcpRequestCmd target+                SendPriv -> map (privMsgCmd target . Text.encodeUtf8) messages+                                -- long actions aren't split up+                SendAction -> [privMsgCmd target ("\SOHACTION " <>+                                                 Text.encodeUtf8 message <> "\SOH")]+                SendNotice -> map (noticeCmd target . Text.encodeUtf8) messages+                SendCtcp cmd -> [ctcpRequestCmd target                                  (Text.encodeUtf8 (Text.pack (map toUpper cmd)))-                                 (Text.encodeUtf8 message)-     clientSend bs st+                                 (Text.encodeUtf8 message)]+     mapM_ (`clientSend` st) bs      now <- getCurrentTime-     let myNick = view connNick conn-         myModes = view (connChannels . ix target' . chanUsers . ix myNick) conn+     let myModes = view (connChannels . ix target' . chanUsers . ix myNick) conn      return (addMessage target' (fakeMsg now myModes) (clearInput st))    where-  conn = view (clientServer0 . ccConnection) st+  myNick = view connNick conn +  maxMessageLength =+    computeMaxMessageLength myNick (view (ccServerSettings.ssUser) ircconn) target+  messages = Text.chunksOf maxMessageLength message++  ircconn = view clientServer0 st+  conn = view ccConnection ircconn+   (statusmsg, target') = splitStatusMsg target conn    fakeMsg now modes = IrcMessage@@ -587,14 +609,14 @@   , ("reconnect", [], pure (doReconnect st'))    , ("ping", [],-    (\msg -> st' <$ doPingCmd msg st')+    (\msg -> doPingCmd msg st')     <$> pRemainingNoSp)    ] -doPingCmd :: String -> ClientState -> IO ()+doPingCmd :: String -> ClientState -> IO ClientState doPingCmd ""  st = sendTimestampPing st-doPingCmd msg st = clientSend (pingCmd (Text.encodeUtf8 (Text.pack msg))) st+doPingCmd msg st = st <$ clientSend (pingCmd (Text.encodeUtf8 (Text.pack msg))) st  doReconnect :: ClientState -> IO ClientState doReconnect st =@@ -737,8 +759,8 @@ -- Primary UI rendering ------------------------------------------------------------------------ -picForState :: ClientState -> (Int,Picture)-picForState st = (scroll', pic)+picForState :: UTCTime -> ClientState -> (Int,Picture)+picForState now st = (scroll', pic)   where   conn = view (clientServer0 . ccConnection) st @@ -760,7 +782,7 @@     , mainFocusImage     ] -  divider = dividerImage st+  divider = dividerImage now st    -- Pad the main image when it doesn't fill the screen   -- so that it starts at the bottom of the frame@@ -841,26 +863,29 @@   beginning = char (withForeColor defAttr brightBlack) '^'   ending    = char (withForeColor defAttr brightBlack) '$' -dividerImage :: ClientState -> Image-dividerImage st+dividerImage :: UTCTime -> ClientState -> Image+dividerImage now st   = extendToWidth (nickPart <|> channelPart <|> lagPart)   where   conn = view (clientServer0 . ccConnection) st    myNick = view connNick conn -  lagPart =-    case view connPingTime conn of-      Just s ->+  drawLagTime color s =        let s' = realToFrac s :: Centi -- truncate to two decimal places            sStr = showFixed True s' <> "s"        in                 string defAttr "-["-            <|> string (withForeColor defAttr yellow) sStr+            <|> string (withForeColor defAttr color) sStr             <|> string defAttr "]" -      _ -> emptyImage+  lagPart =+    case view connPingTime conn of+      NoPing        -> emptyImage+      PingSent when -> drawLagTime red (realToFrac (diffUTCTime now when))+      PingTime s    -> drawLagTime yellow s +   channelPart =     ifoldr (\i x xs -> drawOne i x <|> xs)            emptyImage@@ -1050,10 +1075,11 @@      let pingTime = addUTCTime 60 now      return (addTimerEvent pingTime TransmitPing st) -sendTimestampPing :: ClientState -> IO ()+sendTimestampPing :: ClientState -> IO ClientState sendTimestampPing st =   do now <- getCurrentTime      let ts = realToFrac (utcTimeToPOSIXSeconds now) :: Pico          chopTrailingZeros = True          tsStr = B8.pack (showFixed chopTrailingZeros ts)      clientSend (pingCmd tsStr) st+     return $! set (clientServer0.ccConnection.connPingTime) (PingSent now) st
irc-core.cabal view
@@ -1,5 +1,5 @@ name:                irc-core-version:             1.1.4+version:             1.1.5 homepage:            https://github.com/glguy/irc-core bug-reports:         https://github.com/glguy/irc-core/issues license:             BSD3@@ -97,7 +97,7 @@                        base64-bytestring>= 1.0.0.1  && < 1.1,                        containers       >= 0.5      && < 0.6,                        free             >= 4.11     && < 4.13,-                       lens             >= 4.7      && < 4.14,+                       lens             >= 4.7      && < 4.15,                        text             >= 1.2.0.4  && < 1.3,                        transformers     >= 0.2      && < 0.6,                        regex-tdfa       >= 1.2      && < 1.3@@ -134,7 +134,7 @@                   connection       >= 0.2.4    && < 0.3,                  tls              >= 1.2.16   && < 1.4,-                 data-default-class >= 0.0.1  && < 0.1,+                 data-default-class >= 0.0.1  && < 0.2,                  x509             >= 1.5.0.1  && < 1.7,                  x509-system      >= 1.5.0    && < 1.7,                  x509-store       >= 1.5.0    && < 1.7,@@ -148,12 +148,12 @@                  deepseq          >= 1.3.0.2  && < 1.5,                  directory        >= 1.2.1.0  && < 1.3,                  filepath         >= 1.3.0.2  && < 1.5,-                 lens             >= 4.7      && < 4.14,+                 lens             >= 4.7      && < 4.15,                  network          >= 2.6.0.2  && < 2.7,                  split            >= 0.2.2    && < 0.3,                  stm              >= 2.4.4    && < 2.5,                  text             >= 1.2.0.4  && < 1.3,-                 vty              >= 5.2.7    && < 5.5,+                 vty              >= 5.2.7    && < 5.6,                  haskell-lexer    >= 1.0      && < 1.1,                  transformers     >= 0.2      && < 0.6,                  regex-tdfa       >= 1.2      && < 1.3
src/Irc/Model.hs view
@@ -34,6 +34,9 @@   , connPingTime   , defaultIrcConnection +  -- * Ping information+  , PingStatus(..)+   -- * Phases   , Phase(..) @@ -141,10 +144,13 @@   , _connUmode    :: !ByteString   , _connSnoMask  :: !ByteString   , _connPhase    :: !Phase-  , _connPingTime :: Maybe Pico -- No read instance for NominalDiffTime+  , _connPingTime :: !PingStatus   }   deriving (Read, Show) +data PingStatus = PingTime Pico | PingSent UTCTime | NoPing+  deriving (Read, Show)+ -- | 'IrcConnection' value with everything unspecified defaultIrcConnection :: IrcConnection defaultIrcConnection = IrcConnection@@ -167,7 +173,7 @@   , _connUmode     = ""   , _connSnoMask   = ""   , _connPhase     = RegistrationPhase-  , _connPingTime  = Nothing+  , _connPingTime  = NoPing   }  data Phase@@ -280,7 +286,7 @@                 do now <- getStamp                    let past = posixSecondsToUTCTime (realToFrac (sec :: Pico))                        delta = realToFrac (now `diffUTCTime` past)-                   return (set connPingTime (Just delta) conn)+                   return (set connPingTime (PingTime delta) conn)         Pong mbServer msg ->          doServerMessage "Pong" (maybe "" (<>" ") mbServer <> msg) conn