Skip to content

Commit efe6d35

Browse files
committed
feat: Return structured variables for evaluate var
Leverages DAP feature of returning structured variable reference rather than the evaluation string when the evaluate request is for a single variable. This is useful in the Watch context and for interactive exploration in the REPL, besides the variables pane. `show <var>` or `print <var>` can be used to reproduce the old behavior of printing the variable value whole. Fixes #116 Fixes #108
1 parent 5cf7824 commit efe6d35

File tree

7 files changed

+60
-43
lines changed

7 files changed

+60
-43
lines changed

haskell-debugger/GHC/Debugger/Breakpoint.hs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ import GHC.Driver.Env
1717
import GHC.Driver.Ppr as GHC
1818
import GHC.Runtime.Debugger.Breakpoints as GHC
1919
import GHC.Utils.Outputable as GHC
20-
import GHC.Utils.Trace
2120

2221
import GHC.Debugger.Monad
2322
import GHC.Debugger.Session

haskell-debugger/GHC/Debugger/Breakpoint/Map.hs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -66,14 +66,14 @@ lookupModuleIBIs m (BreakpointMap bm) =
6666

6767
keys :: BreakpointMap a -> [InternalBreakpointId]
6868
keys (BreakpointMap bm) =
69-
[ InternalBreakpointId mod bix
70-
| (mod, im) <- moduleEnvToList bm
69+
[ InternalBreakpointId m bix
70+
| (m, im) <- moduleEnvToList bm
7171
, bix <- IM.keys im
7272
]
7373

7474
toList :: BreakpointMap a -> [(InternalBreakpointId, a)]
7575
toList (BreakpointMap bm) =
76-
[ (InternalBreakpointId mod bix, a)
77-
| (mod, im) <- moduleEnvToList bm
76+
[ (InternalBreakpointId m bix, a)
77+
| (m, im) <- moduleEnvToList bm
7878
, (bix, a) <- IM.toList im
7979
]

haskell-debugger/GHC/Debugger/Evaluation.hs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ import System.Directory
2323
import qualified Prettyprinter as Pretty
2424

2525
import GHC
26-
import GHC.Utils.Trace
2726
import GHC.Builtin.Names (gHC_INTERNAL_GHCI_HELPERS)
2827
import GHC.Unit.Types
2928
import GHC.Data.FastString

haskell-debugger/GHC/Debugger/Interface/Messages.hs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
{-# LANGUAGE DeriveGeneric,
1+
{-# LANGUAGE LambdaCase,
2+
DeriveGeneric,
23
StandaloneDeriving,
34
OverloadedStrings,
45
DuplicateRecordFields,
@@ -161,6 +162,14 @@ data VariableReference
161162

162163
deriving (Show, Generic, Eq, Ord)
163164

165+
-- | From 'ScopeVariablesReference' to a 'VariableReference' that can be used in @"variable"@ requests
166+
scopeToVarRef :: ScopeVariablesReference -> VariableReference
167+
scopeToVarRef = \case
168+
LocalVariablesScope -> LocalVariables
169+
ModuleVariablesScope -> ModuleVariables
170+
GlobalVariablesScope -> GlobalVariables
171+
172+
164173
instance Bounded VariableReference where
165174
minBound = NoVariables
166175
maxBound = SpecificVariable maxBound

haskell-debugger/GHC/Debugger/Monad.hs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ import qualified GHCi.BreakArray as BA
2828
import GHC.Driver.DynFlags as GHC
2929
import GHC.Unit.Module.ModSummary as GHC
3030
import GHC.Utils.Outputable as GHC
31-
import GHC.Utils.Trace as GHC
3231
import GHC.Utils.Logger as GHC
3332
import GHC.Types.Unique.Supply as GHC
3433
import GHC.Runtime.Loader as GHC

hdb/Development/Debug/Adapter/Evaluation.hs

Lines changed: 46 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
{-# LANGUAGE RecordWildCards, OverloadedRecordDot, DuplicateRecordFields #-}
22
module Development.Debug.Adapter.Evaluation where
33

4+
import Control.Monad
45
import qualified Data.Text as T
56
import qualified Data.Map as M
67
import qualified Data.IntSet as IS
@@ -36,32 +37,53 @@ startExecution = do
3637
-- | Command for evaluation (includes evaluation-on-hover)
3738
commandEvaluate :: DebugAdaptor ()
3839
commandEvaluate = do
39-
EvaluateArguments {..} <- getArguments
40-
DidEval er <- sendSync (DoEval (T.unpack evaluateArgumentsExpression))
41-
case er of
42-
EvalStopped{} -> error "impossible, execution is resumed automatically for 'DoEval'"
43-
EvalAbortedWith e -> do
44-
-- Evaluation failed, we report it but don't terminate.
45-
sendEvaluateResponse EvaluateResponse
46-
{ evaluateResponseResult = T.pack e
47-
, evaluateResponseType = T.pack ""
48-
, evaluateResponsePresentationHint = Nothing
49-
, evaluateResponseVariablesReference = 0
50-
, evaluateResponseNamedVariables = Nothing
51-
, evaluateResponseIndexedVariables = Nothing
52-
, evaluateResponseMemoryReference = Nothing
53-
}
54-
_ -> do
55-
sendEvaluateResponse EvaluateResponse
56-
{ evaluateResponseResult = T.pack $ resultVal er
57-
, evaluateResponseType = T.pack $ resultType er
58-
, evaluateResponsePresentationHint = Nothing
59-
, evaluateResponseVariablesReference = 0
60-
, evaluateResponseNamedVariables = Nothing
61-
, evaluateResponseIndexedVariables = Nothing
62-
, evaluateResponseMemoryReference = Nothing
40+
EvaluateArguments {evaluateArgumentsFrameId=_todo, ..} <- getArguments
41+
-- TODO: Proper support for threads/stack frames/scopes id.
42+
-- Currently: ignore `evaluateArgumentsFrameId` and always use instead:
43+
44+
let notAVarResp res ty = EvaluateResponse
45+
{ evaluateResponseResult = res
46+
, evaluateResponseType = ty
47+
, evaluateResponsePresentationHint = Nothing
48+
, evaluateResponseVariablesReference = 0
49+
, evaluateResponseNamedVariables = Nothing
50+
, evaluateResponseIndexedVariables = Nothing
51+
, evaluateResponseMemoryReference = Nothing
6352
}
6453

54+
-- Only evaluate expression if it is not a variable found in the given `evaluateArgumentsFrameId`
55+
let doEvaluate = do
56+
DidEval er <- sendSync (DoEval (T.unpack evaluateArgumentsExpression))
57+
case er of
58+
EvalStopped{} -> error "impossible, execution is resumed automatically for 'DoEval'"
59+
EvalAbortedWith e -> do
60+
-- Evaluation failed, we report it but don't terminate.
61+
sendEvaluateResponse (notAVarResp (T.pack e) (T.pack ""))
62+
_ -> do
63+
sendEvaluateResponse (notAVarResp (T.pack $ resultVal er) (T.pack $ resultType er))
64+
65+
-- Shortcut. Single word expression may be variable in scope (#116)
66+
case T.words evaluateArgumentsExpression of
67+
[possiblyVar] -> do
68+
GotScopes scopes <- sendSync (GetScopes {-todo: use evaluateArgumentsFrameId-})
69+
foundVars <- forM (filter (not . expensive) scopes) $ \scope -> do
70+
GotVariables vars <- sendSync (GetVariables (scopeToVarRef scope.kind))
71+
return (either (:[]) id vars)
72+
case filter ((==possiblyVar) . T.pack . (.varName)) (concat foundVars) of
73+
foundOne:_ -> -- found it!
74+
sendEvaluateResponse EvaluateResponse
75+
{ evaluateResponseResult = T.pack foundOne.varValue
76+
, evaluateResponseType = T.pack foundOne.varType
77+
, evaluateResponsePresentationHint = Nothing
78+
, evaluateResponseVariablesReference = fromEnum foundOne.varRef
79+
, evaluateResponseNamedVariables = Nothing
80+
, evaluateResponseIndexedVariables = Nothing
81+
, evaluateResponseMemoryReference = Nothing
82+
}
83+
[] -> doEvaluate
84+
_ -> doEvaluate
85+
86+
6587
--------------------------------------------------------------------------------
6688
-- * Utils
6789
--------------------------------------------------------------------------------

hdb/Development/Debug/Adapter/Stopped.hs

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -153,14 +153,3 @@ varInfoToVariables VarInfo{..} =
153153
}
154154
}
155155

156-
--------------------------------------------------------------------------------
157-
-- * Utilities
158-
--------------------------------------------------------------------------------
159-
160-
-- | From 'ScopeVariablesReference' to a 'VariableReference' that can be used in @"variable"@ requests
161-
scopeToVarRef :: ScopeVariablesReference -> VariableReference
162-
scopeToVarRef = \case
163-
LocalVariablesScope -> LocalVariables
164-
ModuleVariablesScope -> ModuleVariables
165-
GlobalVariablesScope -> GlobalVariables
166-

0 commit comments

Comments
 (0)