diff --git a/src/Quasar/Wayland/Client.hs b/src/Quasar/Wayland/Client.hs index 1f9833d21ea8dadfb24ed22b2a6f7933a9d82381..d54ac10b12290f37d099209ec93f568c46cb8150 100644 --- a/src/Quasar/Wayland/Client.hs +++ b/src/Quasar/Wayland/Client.hs @@ -36,7 +36,7 @@ newWaylandClient socket = WaylandClient <$> newWaylandConnection @I_wl_display @ clientCallback :: IsInterfaceSide 'Client i => ClientCallback STM i clientCallback = Callback { messageCallback = \object message -> - lift $ traceM $ objectInterfaceName object <> "@" <> show (objectId object) <> "." <> showMessage message + lift $ traceM $ showObjectMessage object message } connectWaylandClient :: MonadResourceManager m => m WaylandClient diff --git a/src/Quasar/Wayland/Protocol/Core.hs b/src/Quasar/Wayland/Protocol/Core.hs index a6c40c607b39b4ac5e36884e0ff07b1f3e2faf41..1561cbeb8618b77ec0ccecffdd14d6ea587d4622 100644 --- a/src/Quasar/Wayland/Protocol/Core.hs +++ b/src/Quasar/Wayland/Protocol/Core.hs @@ -25,7 +25,9 @@ module Quasar.Wayland.Protocol.Core ( feedInput, setException, - -- Message decoder operations + showObjectMessage, + + -- * Message decoder operations WireFormat(..), dropRemaining, ) where @@ -239,13 +241,11 @@ instance IsObjectSide (SomeObject s m) where class (Eq a, Show a) => IsMessage a where opcodeName :: Opcode -> Maybe String - showMessage :: IsMessage a => a -> String getMessage :: IsInterface i => Object s m i -> Opcode -> Get a putMessage :: a -> PutM () instance IsMessage Void where opcodeName _ = Nothing - showMessage = absurd getMessage = invalidOpcode putMessage = absurd @@ -253,6 +253,10 @@ invalidOpcode :: IsInterface i => Object s m i -> Opcode -> Get a invalidOpcode object opcode = fail $ "Invalid opcode " <> show opcode <> " on " <> objectInterfaceName object <> "@" <> show (objectId object) +showObjectMessage :: (IsObject a, IsMessage b) => a -> b -> String +showObjectMessage object message = + objectInterfaceName object <> "@" <> show (objectId object) <> "." <> show message + -- TODO remove data DynamicArgument @@ -402,9 +406,7 @@ handleMessage rawMessage@(oId, opcode, body) = do case HM.lookup oId st.objects of Nothing -> throwM $ ProtocolException $ "Received message with invalid object id " <> show oId - Just (SomeObject object) -> do - traceM $ "Received message (raw) " <> describeDownMessage object opcode body - + Just (SomeObject object) -> case runGetOrFail (getMessageAction st.objects object rawMessage) body of Left (_, _, message) -> throwM $ ParserFailed (describeDownMessage object opcode body) message @@ -413,7 +415,7 @@ handleMessage rawMessage@(oId, opcode, body) = do throwM $ ParserFailed (describeDownMessage object opcode body) (show (BSL.length leftovers) <> "B not parsed") Just (UnknownObject interface oId) -> do - throwM $ ProtocolException $ "Received message for unknown object " <> interface <> "@" <> show oId + throwM $ ProtocolException $ "Received message for object without handler: " <> interface <> "@" <> show oId getMessageAction :: (IsSide s, IsInterface i, MonadCatch m) @@ -423,7 +425,7 @@ getMessageAction -> Get (ProtocolAction s m ()) getMessageAction objects object@(Object _ callback) (oId, opcode, body) = do message <- getDown object opcode - pure $ traceM $ "Received message " <> show message + pure $ traceM $ "<- " <> showObjectMessage object message type ProtocolAction s m a = StateT (ProtocolState s m) m a diff --git a/src/Quasar/Wayland/Protocol/TH.hs b/src/Quasar/Wayland/Protocol/TH.hs index 83cbfdb02aff1e45f16a4405aa610b8f16fc232e..6e51367c4fb629470579686824ecdda4ff034f32 100644 --- a/src/Quasar/Wayland/Protocol/TH.hs +++ b/src/Quasar/Wayland/Protocol/TH.hs @@ -9,6 +9,7 @@ import Language.Haskell.TH import Language.Haskell.TH.Lib import Language.Haskell.TH.Syntax (BangType, VarBangType, addDependentFile) import Language.Haskell.TH.Syntax qualified as TH +import Data.List (intersperse) import Quasar.Prelude import Quasar.Wayland.Protocol.Core import Text.XML.Light @@ -129,32 +130,50 @@ data MessageContext = MessageContext { msgArgFieldName :: ArgumentSpec -> Name } +-- | Pattern to match a message. Arguments can then be accessed by using 'msgArgE'. +msgConP :: MessageContext -> Q Pat +msgConP msg = conP msg.msgConName (varP . (msg.msgArgFieldName) <$> msg.msgSpec.arguments) + +-- | Expression for accessing a message argument which has been matched from a request/event using 'msgArgConP'. +msgArgE :: MessageContext -> ArgumentSpec -> Q Exp +msgArgE msg arg = varE (msg.msgArgFieldName arg) + messageTypeDecs :: Name -> [MessageContext] -> Q [Dec] messageTypeDecs name msgs = execWriterT do tellQ $ messageTypeD tellQ $ isMessageInstanceD t msgs + tellQ $ showInstanceD where t :: Q Type t = conT name messageTypeD :: Q Dec - messageTypeD = dataD (pure []) name [] Nothing (con <$> msgs) [derivingEq, derivingShow] + messageTypeD = dataD (pure []) name [] Nothing (con <$> msgs) [derivingEq] con :: MessageContext -> Q Con con msg = recC (msg.msgConName) (conField <$> msg.msgSpec.arguments) where conField :: ArgumentSpec -> Q VarBangType conField arg = defaultVarBangType (msg.msgArgFieldName arg) (argumentType arg) + showInstanceD :: Q Dec + showInstanceD = instanceD (pure []) [t|Show $t|] [showD] + showD :: Q Dec + showD = funD 'show (showClause <$> msgs) + showClause :: MessageContext -> Q Clause + showClause msg = + clause + [msgConP msg] + (normalB [|mconcat $(listE ([stringE (msg.msgSpec.name ++ "(")] <> mconcat (intersperse [stringE ", "] (showArgE <$> msg.msgSpec.arguments) <> [[stringE ")"]])))|]) + [] + where + showArgE :: ArgumentSpec -> [Q Exp] + showArgE arg = [stringE (arg.name ++ "="), [|showArgument @($(argumentSpecType arg)) $(msgArgE msg arg)|]] isMessageInstanceD :: Q Type -> [MessageContext] -> Q Dec -isMessageInstanceD t msgs = instanceD (pure []) [t|IsMessage $t|] [opcodeNameD, showMessageD, getMessageD, putMessageD] +isMessageInstanceD t msgs = instanceD (pure []) [t|IsMessage $t|] [opcodeNameD, getMessageD, putMessageD] where opcodeNameD :: Q Dec opcodeNameD = funD 'opcodeName (opcodeNameClauseD <$> msgs) opcodeNameClauseD :: MessageContext -> Q Clause opcodeNameClauseD msg = clause [litP (integerL (fromIntegral msg.msgSpec.opcode))] (normalB ([|Just $(stringE msg.msgSpec.name)|])) [] - showMessageD :: Q Dec - showMessageD = funD 'showMessage (showMessageClauseD <$> msgs) - showMessageClauseD :: MessageContext -> Q Clause - showMessageClauseD msg = clause [conP msg.msgConName (replicate (length msg.msgSpec.arguments) wildP)] (normalB (stringE msg.msgSpec.name)) [] getMessageD :: Q Dec getMessageD = funD 'getMessage (getMessageClauseD <$> msgs) getMessageClauseD :: MessageContext -> Q Clause