packages feed

haskell-debugger-view (empty) → 0.1.0.0

raw patch · 6 files changed

+238/−0 lines, 6 filesdep +basedep +bytestringdep +containers

Dependencies added: base, bytestring, containers, text

Files

+ CHANGELOG.md view
@@ -0,0 +1,5 @@+# Revision history for haskell-debugger-view++## 0.1.0.0 -- 2025-11-18++* First version. Released on an unsuspecting world.
+ haskell-debugger-view.cabal view
@@ -0,0 +1,40 @@+cabal-version:   3.12+name:            haskell-debugger-view+version:         0.1.0.0+license:         BSD-3-Clause+author:          Matthew Pickering, Rodrigo Mesquita+maintainer:      matthewtpickering@gmail.com, rodrigo@well-typed.com+build-type:      Simple+extra-doc-files: CHANGELOG.md+category:        Development+synopsis:+    Custom debug visualization instances for @haskell-debugger@+description:+    This package provides a class to implement custom debug visualization+    instances for user-defined datatypes, which will be discovered and used by+    @haskell-debugger@ when debugging a program. Additionally, it provides a+    handful of built-in custom visualizations, such as for @String@ and @IntMap@.+    The custom debug visualizations are displayed in the editor when inspecting+    a variable or evaluation result. The @'DebugView'@ class is the class for+    which an instance must be provided, and allows one to customize what is+    displayed inline and what fields are available when expanding it.+    See the haddocks of @'GHC.Debugger.View.Class'@ for further information.++common warnings+    ghc-options: -Wall++library+    import:           warnings+    -- If you add a module here make sure to also add this module to the list+    -- of modules that we attempt to load when haskell-debug-view is not+    -- dependend upon transitively, in GHC.Debugger.Session.Builtin+    exposed-modules:  GHC.Debugger.View.Class+                      GHC.Debugger.View.Containers+                      GHC.Debugger.View.Text+                      GHC.Debugger.View.ByteString+    build-depends:    base >= 4.22 && < 5,+                      containers >= 0.7 && < 0.9,+                      text >= 2.1 && < 2.3,+                      bytestring >= 0.12.1 && < 0.13,+    hs-source-dirs:   src+    default-language: GHC2021
+ src/GHC/Debugger/View/ByteString.hs view
@@ -0,0 +1,11 @@+{-# OPTIONS_GHC -Wno-orphans #-}+module GHC.Debugger.View.ByteString where++import GHC.Debugger.View.Class++import qualified Data.ByteString    as BS++instance DebugView BS.ByteString where+  debugValue  t = VarValue (show t) False+  debugFields _ = VarFields []+
+ src/GHC/Debugger/View/Class.hs view
@@ -0,0 +1,150 @@+{-# LANGUAGE DerivingVia, StandaloneDeriving, ViewPatterns, ImpredicativeTypes #-}+-- | The home of customizability for visualizing variables and values with @haskell-debugger@+module GHC.Debugger.View.Class+  (+    -- * Writing custom debug visualizations+    --+    -- | The entry point for custom visualizations is 'DebugView'.+    -- There are two axis of configuration:+    --+    -- 1. What to display inline in front of the variable name and whether it+    -- is expandable+    --+    -- 2. What fields are displayed when the value is expanded and what are+    -- their corresponding values+    --+    -- The former is answered by 'debugValue' / 'VarValue' and the latter by+    -- 'debugFields' / 'VarFields'.+    DebugView(..)++  , VarValue(..)+  , VarFields(..)+  , VarFieldValue(..)++  -- * Utilities+  --+  -- | These can make it easier to write your own custom instances.+  -- We also use them for the built-in custom instances.+  , BoringTy(..)++  -- * The internals+  --+  -- | These are used by @haskell-debugger@ when invoking these instances at+  -- runtime and reconstructing the result from the heap.+  --+  -- They should never be used by a user looking to write custom visualizations.+  , VarValueIO(..)+  , debugValueIOWrapper+  , VarFieldsIO(..)+  , debugFieldsIOWrapper+  )+  where++-- | Custom handling of debug terms (e.g. in the variables pane, or when+-- inspecting a lazy variable)+class DebugView a where++  -- | Compute the representation of a variable with the given value.+  --+  -- INVARIANT: this method should only called on values which are already in+  -- WHNF, never thunks.+  --+  -- That said, this method is responsible for determining how much it is+  -- forced when displaying it inline as a variable.+  --+  -- For instance, for @String@, @a@ will be fully forced to display the entire+  -- string in one go rather than as a linked list of @'Char'@.+  debugValue :: a -> VarValue++  -- | Compute the fields to display when expanding a value of type @a@.+  --+  -- This method should only be called to get the fields if the corresponding+  -- @'VarValue'@ has @'varExpandable' = True@.+  debugFields :: a -> VarFields++-- | The representation of the value for some variable on the debugger+data VarValue = VarValue+  { -- | The value to display inline for this variable+    varValue      :: 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+  { varFields :: [(String, VarFieldValue)]+  }++-- | A box for subfields of a value.+--+-- Used to construct the debug-view list of fields one gets from expanding a datatype.+-- See, for instance, the @DebugView (a, b)@ instance for an example of how it is used.+--+-- The boxed value is returned as is and can be further forced or expanded by+-- the debugger, using either the existing @'DebugView'@ instance for the+-- existential @a@ (the instance is found at runtime), or the generic runtime+-- term inspection mechanisms otherwise.+data VarFieldValue = forall a. VarFieldValue a++--------------------------------------------------------------------------------++-- | Boring types scaffolding.+--+-- Meant to be used like:+--+-- @+-- deriving via (BoringTy Int) instance (DebugView Int)+-- @+--+-- to derive a 'DebugView' for a type whose terms should always be fully forced+-- and displayed whole rather than as parts.+--+-- A boring type is one for which we don't care about the structure and would+-- rather see "whole" when being inspected. Strings and literals are a good+-- example, because it's more useful to see the string value than it is to see+-- a linked list of characters where each has to be forced individually.+newtype BoringTy a = BoringTy a++instance Show a => DebugView (BoringTy a) where+  debugValue (BoringTy x) = VarValue (show x) False+  debugFields _           = VarFields []++deriving via BoringTy Int     instance DebugView Int+deriving via BoringTy Word    instance DebugView Word+deriving via BoringTy Double  instance DebugView Double+deriving via BoringTy Float   instance DebugView Float+deriving via BoringTy Integer instance DebugView Integer+deriving via BoringTy Char    instance DebugView Char+deriving via BoringTy String  instance DebugView String++instance DebugView (a, b) where+  debugValue _ = VarValue "( , )" True+  debugFields (x, y) = VarFields+    [ ("fst", VarFieldValue x)+    , ("snd", VarFieldValue y) ]++--------------------------------------------------------------------------------+-- * (Internal) Wrappers required to call `evalStmt` on methods more easily+--------------------------------------------------------------------------------++-- | Wrapper to make evaluating from debugger easier+data VarValueIO = VarValueIO+  { varValueIO :: IO String+  , varExpandableIO :: Bool+  }++debugValueIOWrapper :: DebugView a => a -> IO [VarValueIO]+debugValueIOWrapper x = case debugValue x of+  VarValue str b ->+    pure [VarValueIO (pure str) b]++newtype VarFieldsIO = VarFieldsIO+  { varFieldsIO :: [(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]]
+ src/GHC/Debugger/View/Containers.hs view
@@ -0,0 +1,21 @@+{-# OPTIONS_GHC -Wno-orphans #-}+module GHC.Debugger.View.Containers where++import GHC.Debugger.View.Class++import qualified Data.IntMap        as IM+import qualified Data.Map           as M++instance DebugView (IM.IntMap a) where+  debugValue _ = VarValue "IntMap" True+  debugFields im = 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+    [ (show k, VarFieldValue v)+    | (k, v) <- M.toList m+    ]
+ src/GHC/Debugger/View/Text.hs view
@@ -0,0 +1,11 @@+{-# OPTIONS_GHC -Wno-orphans #-}+module GHC.Debugger.View.Text where++import GHC.Debugger.View.Class++import qualified Data.Text          as T++instance DebugView T.Text where+  debugValue  t = VarValue (show (T.unpack t)) False+  debugFields _ = VarFields []+