private JObject GetScriptSource(string scriptId)
        {
            var sourceFile = _debugInfoStore.GetSourceFileById(scriptId);

            return(DebuggerConnection.ToJObject(new
            {
                // TODO: Stop reading the file from disk. Get the document's
                // contents from the .pdb file, assuming that info exists there.
                scriptSource = File.ReadAllText(sourceFile.FileName)
            }));
        }
        private JObject GetPossibleBreakpoints(string scriptId, int lineNumber, int columnNumber)
        {
            var closestLocations = _debugInfoStore.GetBreakpointLocations(scriptId, lineNumber);

            return(DebuggerConnection.ToJObject(new
            {
                locations = closestLocations.Select(location => new
                {
                    ScriptId = scriptId,
                    LineNumber = location.SequencePointInfo.StartLine - 1,
                    ColumnNumber = location.SequencePointInfo.StartColumn - 1
                })
            }));
        }
 private async Task NotifyBrowserAboutScript(int executionContextId, JObject auxData, SourceFileInfo sourceFile)
 {
     await _ideConnection.SendMessageAsync(new MessageBase
     {
         Method = "Debugger.scriptParsed",
         Params = DebuggerConnection.ToJObject(new
         {
             ScriptId                = sourceFile.Id,
             Url                     = sourceFile.Url,
             ExecutionContextId      = executionContextId,
             ExecutionContextAuxData = auxData,
             Hash                    = "fakehash",
             //IsLiveEdit = false,
             //SourceMapURL = string.Empty,
             //HasSourceURL = false,
             //IsModule = false,
             //StartLine = 0,
             //StartColumn = 0,
             //EndLine = 3,
             //EndColumn = 0,
             //Length = 123
         })
     });
 }
        private async Task <JObject> SetBreakpoint(SourceFileInfo script, int lineNumber, int columnNumber)
        {
            var closestLocation = _debugInfoStore.GetClosestBreakpointLocation(script, lineNumber, columnNumber);

            if (closestLocation == null)
            {
                Console.WriteLine($"\n*** No location found when trying to set breakpoint at line {lineNumber}, col {columnNumber} in {script.FileName}");
                return(EmptyJObject);
            }
            else
            {
                // The breakpoint needs to be tracked:
                // [1] In the debug orchestrator, so it can recreate the list of breakpoints
                // later if it needs to
                var breakpointId = CreateBreakpointId(closestLocation.DnaMethodIdentifier, closestLocation.SequencePointInfo.Offset);
                _currentBreakpointsById[breakpointId] = closestLocation;

                // [2] In DNA, so it knows when to stop
                Console.WriteLine($"\n*** Found location at seq point {closestLocation.SequencePointIndex} in {closestLocation.DnaMethodIdentifier}");
                await SetBreakpointInDNA(closestLocation);

                // [3] In the IDE, so it can be shown to the developer
                return(DebuggerConnection.ToJObject(new
                {
                    breakpointId = breakpointId,
                    locations = new[]
                    {
                        new {
                            scriptId = closestLocation.SourceFile.Id,
                            lineNumber = closestLocation.SequencePointInfo.StartLine - 1,
                            columnNumber = closestLocation.SequencePointInfo.StartColumn - 1
                        }
                    }
                }));
            }
        }
        private async Task <JObject> EvaluateJsInBrowser(string expression, string callFrameId = null)
        {
            JObject resultWrapper;

            if (string.IsNullOrEmpty(callFrameId))
            {
                resultWrapper = await _browserConnection.CallMethodAsync("Runtime.evaluate", DebuggerConnection.ToJObject(new
                {
                    Expression = expression
                }));
            }
            else
            {
                resultWrapper = await _browserConnection.CallMethodAsync("Debugger.evaluateOnCallFrame", DebuggerConnection.ToJObject(new
                {
                    Expression  = expression,
                    CallFrameId = callFrameId
                }));
            }

            return(resultWrapper.GetValue("result").Value <JObject>());
        }
        private async Task NotifyIdeAboutDotnetBreakpointHit(MessageBase message, JObject nativeTopCallFrame)
        {
            var nativeCallFrameId = nativeTopCallFrame.GetValue("callFrameId").Value <string>();
            var debuggerMessage   = await EvaluateJsInBrowser("message", nativeCallFrameId);

            var debuggerMessageJson   = debuggerMessage.GetValue("value").Value <string>();
            var debuggerMessageParsed = JsonConvert.DeserializeObject <JObject>(debuggerMessageJson);
            var dnaLocationId         = debuggerMessageParsed.GetValue("ID").Value <string>();
            var ilOffset     = debuggerMessageParsed.GetValue("ilOffset").Value <int>();
            var breakpointId = CreateBreakpointId(dnaLocationId, ilOffset);

            // Modify the message to indicate we hit the .NET breakpoint, then pass it through to
            // the IDE. TODO: Also fix up the call stack, etc.
            var breakpoint = _debugInfoStore.FindBreakpointUsingDnaData(dnaLocationId, ilOffset, out var sourceFile);

            if (breakpoint == null)
            {
                Console.WriteLine($"Could not find .NET breakpoint corresponding to IL offset {ilOffset} in ID {dnaLocationId}");
                await _ideConnection.SendMessageAsync(message);

                return;
            }
            _currentlyPausedInDotNetBreakpoint = breakpoint;

            var lineNumber = breakpoint.SequencePointInfo.StartLine;
            var colNumber  = breakpoint.SequencePointInfo.StartColumn;

            Console.WriteLine($"Hit .NET breakpoint at {sourceFile.FileName} line {lineNumber} col {colNumber}\n");

            var nativeCallFrames = message.Params.GetValue("callFrames").Values <JObject>();
            var dotNetCallFrames = new[]
            {
                // TODO: Include all .NET call frames, not just the top one
                DebuggerConnection.ToJObject(new
                {
                    CallFrameId      = "dotnetcallframe:0",
                    FunctionName     = breakpoint.MethodName,
                    FunctionLocation = new {
                        ScriptId     = sourceFile.Id,
                        LineNumber   = lineNumber - 1, // TODO: Get actual line/col where the function starts, not the breakpoint hit
                        ColumnNumber = colNumber - 1
                    },
                    Location = new {
                        ScriptId     = sourceFile.Id,
                        LineNumber   = lineNumber - 1,
                        ColumnNumber = colNumber - 1
                    },
                    ScopeChain = EmptyJObject, // TODO: Populate, so it can show locals
                    This       = EmptyJObject
                })
            };
            await _ideConnection.SendMessageAsync(new MessageBase
            {
                Method = "Debugger.paused",
                Params = DebuggerConnection.ToJObject(new
                {
                    CallFrames     = dotNetCallFrames.Concat(nativeCallFrames),
                    Reason         = "other",
                    HitBreakpoints = new[] { breakpointId }
                })
            });
        }