packages feed

haskell-debugger-view 0.1.0.0 → 0.2.0.0

raw patch · 6 files changed

+104/−22 lines, 6 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

- GHC.Debugger.View.Class: instance GHC.Internal.Read.Read GHC.Debugger.View.Class.VarValue
- GHC.Debugger.View.Class: instance GHC.Internal.Show.Show GHC.Debugger.View.Class.VarValue
+ GHC.Debugger.View.Class: [ProgramAp] :: forall a1 a. Program (a1 -> a) -> Program a1 -> Program a
+ GHC.Debugger.View.Class: [ProgramAskThunk] :: forall a1. a1 -> Program Bool
+ GHC.Debugger.View.Class: [ProgramBranch] :: forall a. Program Bool -> Program a -> Program a -> Program a
+ GHC.Debugger.View.Class: [PureProgram] :: forall a. a -> Program a
+ GHC.Debugger.View.Class: data Program a
+ GHC.Debugger.View.Class: ifP :: Program Bool -> Program a -> Program a -> Program a
+ GHC.Debugger.View.Class: instance GHC.Debugger.View.Class.DebugView GHC.Internal.Int.Int16
+ GHC.Debugger.View.Class: instance GHC.Debugger.View.Class.DebugView GHC.Internal.Int.Int32
+ GHC.Debugger.View.Class: instance GHC.Debugger.View.Class.DebugView GHC.Internal.Int.Int64
+ GHC.Debugger.View.Class: instance GHC.Debugger.View.Class.DebugView GHC.Internal.Int.Int8
+ GHC.Debugger.View.Class: instance GHC.Debugger.View.Class.DebugView GHC.Internal.Word.Word16
+ GHC.Debugger.View.Class: instance GHC.Debugger.View.Class.DebugView GHC.Internal.Word.Word32
+ GHC.Debugger.View.Class: instance GHC.Debugger.View.Class.DebugView GHC.Internal.Word.Word64
+ GHC.Debugger.View.Class: instance GHC.Debugger.View.Class.DebugView GHC.Internal.Word.Word8
+ GHC.Debugger.View.Class: instance GHC.Debugger.View.Class.DebugView [a]
+ GHC.Debugger.View.Class: instance GHC.Internal.Base.Applicative GHC.Debugger.View.Class.Program
+ GHC.Debugger.View.Class: instance GHC.Internal.Base.Functor GHC.Debugger.View.Class.Program
+ GHC.Debugger.View.Class: isThunk :: a -> Program Bool
+ GHC.Debugger.View.Class: simpleValue :: String -> Bool -> VarValue
- GHC.Debugger.View.Class: VarFieldsIO :: [(IO String, VarFieldValue)] -> VarFieldsIO
+ GHC.Debugger.View.Class: VarFieldsIO :: Program [(IO String, VarFieldValue)] -> VarFieldsIO
- GHC.Debugger.View.Class: VarValue :: String -> Bool -> VarValue
+ GHC.Debugger.View.Class: VarValue :: Program String -> Bool -> VarValue
- GHC.Debugger.View.Class: VarValueIO :: IO String -> Bool -> VarValueIO
+ GHC.Debugger.View.Class: VarValueIO :: Program (IO String) -> Bool -> VarValueIO
- GHC.Debugger.View.Class: [varFieldsIO] :: VarFieldsIO -> [(IO String, VarFieldValue)]
+ GHC.Debugger.View.Class: [varFieldsIO] :: VarFieldsIO -> Program [(IO String, VarFieldValue)]
- GHC.Debugger.View.Class: [varValueIO] :: VarValueIO -> IO String
+ GHC.Debugger.View.Class: [varValueIO] :: VarValueIO -> Program (IO String)
- GHC.Debugger.View.Class: [varValue] :: VarValue -> String
+ GHC.Debugger.View.Class: [varValue] :: VarValue -> Program String
- GHC.Debugger.View.Class: debugFields :: DebugView a => a -> VarFields
+ GHC.Debugger.View.Class: debugFields :: DebugView a => a -> Program VarFields

Files

CHANGELOG.md view
@@ -1,5 +1,15 @@ # Revision history for haskell-debugger-view +## 0.2.0.0 -- 2026-01-05++* Add support for more complex debug visualizations using the Program abstraction+    * API change: `debugValue` and `debugFields` now return `Program`-wrapped+      values, rather than `VarFields/VarValue` directly.+* Introduce new functions `isThunk` and `ifP` for conditional debugging behavior+* Enhance list visualization to show up to 50 forced elements+* Add improved handling for lazy values in debug views+* Update documentation and examples for custom DebugView instances+ ## 0.1.0.0 -- 2025-11-18  * First version. Released on an unsuspecting world.
haskell-debugger-view.cabal view
@@ -1,6 +1,6 @@ cabal-version:   3.12 name:            haskell-debugger-view-version:         0.1.0.0+version:         0.2.0.0 license:         BSD-3-Clause author:          Matthew Pickering, Rodrigo Mesquita maintainer:      matthewtpickering@gmail.com, rodrigo@well-typed.com
src/GHC/Debugger/View/ByteString.hs view
@@ -6,6 +6,6 @@ import qualified Data.ByteString    as BS  instance DebugView BS.ByteString where-  debugValue  t = VarValue (show t) False-  debugFields _ = VarFields []+  debugValue  t = simpleValue (show t) False+  debugFields _ = pure (VarFields []) 
src/GHC/Debugger/View/Class.hs view
@@ -20,7 +20,16 @@   , VarValue(..)   , VarFields(..)   , VarFieldValue(..)+  , simpleValue ++    -- * A 'Program' can describe a more complicated visualisation method which+    -- can query some information from the debugger.+  , Program(..)+  , isThunk+  , ifP++   -- * Utilities   --   -- | These can make it easier to write your own custom instances.@@ -40,6 +49,9 @@   )   where +import Data.Int+import Data.Word+ -- | Custom handling of debug terms (e.g. in the variables pane, or when -- inspecting a lazy variable) class DebugView a where@@ -60,17 +72,52 @@   --   -- This method should only be called to get the fields if the corresponding   -- @'VarValue'@ has @'varExpandable' = True@.-  debugFields :: a -> VarFields+  debugFields :: a -> Program VarFields +-- | The 'Program' abstraction allows more complicated 'DebugView' instances+-- to be constructed. The debugger will interpreter a 'Program' lazily when+-- determining how to display a variable.+--+-- At the moment the only interesting query when constructing a program is determining+-- if a value is already evaluated or not. This can be used to only display the evaluated+-- prefix of a list for example.+data Program a where+    -- | Lift a value to a program+    PureProgram :: a -> Program a+    -- | Program application+    ProgramAp :: Program (a -> b) -> Program a -> Program b+    -- | Evaluate the conditional, and branch on the result+    ProgramBranch :: Program Bool -> Program a -> Program a -> Program a+    -- | Is the value a thunk or evaluated?+    ProgramAskThunk :: a -> Program Bool++instance Functor Program where+   fmap f x = ProgramAp (PureProgram f) x++instance Applicative Program where+   pure = PureProgram+   fx <*> fy = ProgramAp fx fy++-- | Construct a 'VarValue' which doesn't require a 'Program'.+simpleValue :: String -> Bool -> VarValue+simpleValue s b = VarValue (pure s) b++-- | Construct a 'Program' which determines if 'a' is a thunk or not.+isThunk :: a -> Program Bool+isThunk = ProgramAskThunk++-- | Construct a program which branches+ifP :: Program Bool -> Program a -> Program a -> Program a+ifP = ProgramBranch+ -- | The representation of the value for some variable on the debugger data VarValue = VarValue   { -- | The value to display inline for this variable-    varValue      :: String+    varValue      :: Program String      -- | Can this variable further be expanded (s.t. @'debugFields'@ is not null?)   , varExpandable :: Bool   }-  deriving (Show, Read)  -- | The representation for fields of a value which is expandable in the debugger newtype VarFields = VarFields@@ -108,11 +155,19 @@ newtype BoringTy a = BoringTy a  instance Show a => DebugView (BoringTy a) where-  debugValue (BoringTy x) = VarValue (show x) False-  debugFields _           = VarFields []+  debugValue (BoringTy x) = simpleValue (show x) False+  debugFields _           = pure $ VarFields []  deriving via BoringTy Int     instance DebugView Int+deriving via BoringTy Int8    instance DebugView Int8+deriving via BoringTy Int16   instance DebugView Int16+deriving via BoringTy Int32   instance DebugView Int32+deriving via BoringTy Int64   instance DebugView Int64 deriving via BoringTy Word    instance DebugView Word+deriving via BoringTy Word8   instance DebugView Word8+deriving via BoringTy Word16  instance DebugView Word16+deriving via BoringTy Word32  instance DebugView Word32+deriving via BoringTy Word64  instance DebugView Word64 deriving via BoringTy Double  instance DebugView Double deriving via BoringTy Float   instance DebugView Float deriving via BoringTy Integer instance DebugView Integer@@ -120,31 +175,48 @@ deriving via BoringTy String  instance DebugView String  instance DebugView (a, b) where-  debugValue _ = VarValue "( , )" True-  debugFields (x, y) = VarFields+  debugValue _ = simpleValue "( , )" True+  debugFields (x, y) = pure $ VarFields     [ ("fst", VarFieldValue x)     , ("snd", VarFieldValue y) ] +-- | This instance will display up to the first 50 forced elements of a list.+instance {-# OVERLAPPABLE #-} DebugView [a] where+  debugValue [] = simpleValue "[]" False+  debugValue (_:_) = simpleValue "[...]" True+  debugFields v = VarFields <$> go 0 v+    where+      go :: Int -> [a] -> Program [(String, VarFieldValue)]+      go 50 xs = pure [("tail", VarFieldValue xs)]+      go _ [] = pure []+      go n (x:xs) = ((show n, VarFieldValue x) :) <$>+                      (ifP (isThunk xs) (pure $ [("tail", VarFieldValue xs)])+                                        (go (n + 1) xs))+ -------------------------------------------------------------------------------- -- * (Internal) Wrappers required to call `evalStmt` on methods more easily --------------------------------------------------------------------------------  -- | Wrapper to make evaluating from debugger easier data VarValueIO = VarValueIO-  { varValueIO :: IO String+  { varValueIO :: Program (IO String)   , varExpandableIO :: Bool   }  debugValueIOWrapper :: DebugView a => a -> IO [VarValueIO] debugValueIOWrapper x = case debugValue x of   VarValue str b ->-    pure [VarValueIO (pure str) b]+    pure [VarValueIO (pure <$> str) b]  newtype VarFieldsIO = VarFieldsIO-  { varFieldsIO :: [(IO String, VarFieldValue)]+  { varFieldsIO :: Program [(IO String, VarFieldValue)]   }  debugFieldsIOWrapper :: DebugView a => a -> IO [VarFieldsIO]-debugFieldsIOWrapper x = case debugFields x of-  VarFields fls ->-    pure [VarFieldsIO [ (pure fl_s, b) | (fl_s, b) <- fls]]+debugFieldsIOWrapper x = pure [VarFieldsIO (toVarFieldsIO <$> (debugFields x))]++toVarFieldsIO :: VarFields -> [(IO String, VarFieldValue)]+toVarFieldsIO x =+  case x of+    VarFields fls -> [ (pure fl_s, b) | (fl_s, b) <- fls]+
src/GHC/Debugger/View/Containers.hs view
@@ -7,15 +7,15 @@ import qualified Data.Map           as M  instance DebugView (IM.IntMap a) where-  debugValue _ = VarValue "IntMap" True-  debugFields im = VarFields+  debugValue _ = simpleValue "IntMap" True+  debugFields im = pure $ VarFields     [ (show k, VarFieldValue v)     | (k, v) <- IM.toList im     ]  instance Show k => DebugView (M.Map k a) where-  debugValue _ = VarValue "Map" True-  debugFields m = VarFields+  debugValue _ = simpleValue "Map" True+  debugFields m = pure $ VarFields     [ (show k, VarFieldValue v)     | (k, v) <- M.toList m     ]
src/GHC/Debugger/View/Text.hs view
@@ -6,6 +6,6 @@ import qualified Data.Text          as T  instance DebugView T.Text where-  debugValue  t = VarValue (show (T.unpack t)) False-  debugFields _ = VarFields []+  debugValue  t = simpleValue (show (T.unpack t)) False+  debugFields _ = pure $ VarFields []