From ec80503bfb38de40d859b8b7942ae5e9568b53a3 Mon Sep 17 00:00:00 2001 From: Paul van Brenk Date: Wed, 22 Feb 2017 15:55:25 -0800 Subject: [PATCH 1/9] Support WebKit debugger. This needs matching changes in the webkit debugger component. --- Common/Product/SharedProject/ProjectNode.cs | 5 +- .../Nodejs/Debugger/DebugEngine/AD7Engine.cs | 7 +- .../Product/Nodejs/Debugger/NodeConstants.cs | 2 +- .../Nodejs/Debugger/NodeDebugOptions.cs | 2 +- .../Product/Nodejs/Debugger/NodeDebugger.cs | 132 +++++---- .../Nodejs/Debugger/NodeEvaluationResult.cs | 2 +- .../Nodejs/Debugger/NodeEventEventArgs.cs | 28 -- Nodejs/Product/Nodejs/Debugger/NodeProcess.cs | 8 +- Nodejs/Product/Nodejs/Nodejs.csproj | 9 +- .../NodejsGeneralOptionsControl.Designer.cs | 78 +++--- .../Options/NodejsGeneralOptionsControl.cs | 6 + .../NodejsGeneralOptionsControl.en.resx | 253 ++++++++++-------- .../Options/NodejsGeneralOptionsPage.cs | 55 ++-- .../Nodejs/Project/NodejsProjectLauncher.cs | 158 ++++++++--- 14 files changed, 417 insertions(+), 328 deletions(-) delete mode 100644 Nodejs/Product/Nodejs/Debugger/NodeEventEventArgs.cs diff --git a/Common/Product/SharedProject/ProjectNode.cs b/Common/Product/SharedProject/ProjectNode.cs index 738d03052..bb5baa52e 100644 --- a/Common/Product/SharedProject/ProjectNode.cs +++ b/Common/Product/SharedProject/ProjectNode.cs @@ -4496,7 +4496,6 @@ public virtual int IsDocumentInProject(string mkDoc, out int found, VSDOCUMENTPR } return VSConstants.S_OK; - } protected virtual bool IncludeNonMemberItemInProject(HierarchyNode node) { @@ -5597,6 +5596,10 @@ public virtual int GetBuildSystemKind(out uint kind) { internal HierarchyNode FindNodeByFullPath(string name) { Site.GetUIThread().MustBeCalledFromUIThread(); + if (name.StartsWith("mdha:", StringComparison.OrdinalIgnoreCase)) { + return default(HierarchyNode); + } + Debug.Assert(Path.IsPathRooted(name)); HierarchyNode node; diff --git a/Nodejs/Product/Nodejs/Debugger/DebugEngine/AD7Engine.cs b/Nodejs/Product/Nodejs/Debugger/DebugEngine/AD7Engine.cs index da4304a5d..5787792eb 100644 --- a/Nodejs/Product/Nodejs/Debugger/DebugEngine/AD7Engine.cs +++ b/Nodejs/Product/Nodejs/Debugger/DebugEngine/AD7Engine.cs @@ -565,9 +565,10 @@ int IDebugEngineLaunch2.LaunchSuspended(string pszServer, IDebugPort2 port, stri AttachEvents(_process); - var adProcessId = new AD_PROCESS_ID(); - adProcessId.ProcessIdType = (uint)enum_AD_PROCESS_ID.AD_PROCESS_ID_SYSTEM; - adProcessId.dwProcessId = (uint)_process.Id; + var adProcessId = new AD_PROCESS_ID() { + ProcessIdType = (uint)enum_AD_PROCESS_ID.AD_PROCESS_ID_SYSTEM, + dwProcessId = (uint)_process.Id + }; EngineUtils.RequireOk(port.GetProcess(adProcessId, out process)); LiveLogger.WriteLine("AD7Engine LaunchSuspended returning S_OK"); diff --git a/Nodejs/Product/Nodejs/Debugger/NodeConstants.cs b/Nodejs/Product/Nodejs/Debugger/NodeConstants.cs index e1ba0984a..a67019214 100644 --- a/Nodejs/Product/Nodejs/Debugger/NodeConstants.cs +++ b/Nodejs/Product/Nodejs/Debugger/NodeConstants.cs @@ -15,7 +15,7 @@ //*********************************************************// namespace Microsoft.NodejsTools.Debugger { - sealed class NodeConstants { + internal sealed class NodeConstants { public const string ScriptWrapBegin = "(function (exports, require, module, __filename, __dirname) { "; public const string ScriptWrapEnd = "\n});"; } diff --git a/Nodejs/Product/Nodejs/Debugger/NodeDebugOptions.cs b/Nodejs/Product/Nodejs/Debugger/NodeDebugOptions.cs index 7af3abe32..b3fec9a2e 100644 --- a/Nodejs/Product/Nodejs/Debugger/NodeDebugOptions.cs +++ b/Nodejs/Product/Nodejs/Debugger/NodeDebugOptions.cs @@ -18,7 +18,7 @@ namespace Microsoft.NodejsTools.Debugger { [Flags] - enum NodeDebugOptions { + internal enum NodeDebugOptions { None, /// /// Passing this flag to the debugger will cause it to wait for input on an abnormal (non-zero) diff --git a/Nodejs/Product/Nodejs/Debugger/NodeDebugger.cs b/Nodejs/Product/Nodejs/Debugger/NodeDebugger.cs index 29cb27bd2..46917aac3 100644 --- a/Nodejs/Product/Nodejs/Debugger/NodeDebugger.cs +++ b/Nodejs/Product/Nodejs/Debugger/NodeDebugger.cs @@ -36,8 +36,8 @@ namespace Microsoft.NodejsTools.Debugger { /// /// Handles all interactions with a Node process which is being debugged. /// - sealed class NodeDebugger : IDisposable { - public readonly int MainThreadId = 1; + internal sealed class NodeDebugger : IDisposable { + public const int MainThreadId = 1; private readonly Dictionary _breakpointBindings = new Dictionary(); private readonly IDebuggerClient _client; private readonly IDebuggerConnection _connection; @@ -76,39 +76,57 @@ private NodeDebugger() { _fileNameMapper = new LocalFileNameMapper(); } - public NodeDebugger( - string exe, - string script, - string dir, - string env, - string interpreterOptions, - NodeDebugOptions debugOptions, - ushort? debuggerPort = null, - bool createNodeWindow = true) + public NodeDebugger(Uri debuggerEndpointUri, int id) + : this() { + _debuggerEndpointUri = debuggerEndpointUri; + _id = id; + _attached = true; + } + + public NodeDebugger(string exe, string script, string dir, string env, string interpreterOptions, NodeDebugOptions debugOptions, ushort? debuggerPort = null, bool createNodeWindow = true) : this() { // Select debugger port for a local connection - ushort debuggerPortOrDefault = NodejsConstants.DefaultDebuggerPort; - if (debuggerPort != null) { - debuggerPortOrDefault = debuggerPort.Value; - } else { - List activeConnections = - (from listener in IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpListeners() - select listener.Port).ToList(); - if (activeConnections.Contains(debuggerPortOrDefault)) { - debuggerPortOrDefault = (ushort)Enumerable.Range(new Random().Next(5859, 6000), 60000).Except(activeConnections).First(); - } + var debuggerPortOrDefault = debuggerPort ?? GetDebuggerPort(); + _debuggerEndpointUri = new UriBuilder { Scheme = "tcp", Host = "localhost", Port = debuggerPortOrDefault }.Uri; + + _process = StartNodeProcessWithDebug(exe, script, dir, env, interpreterOptions, debugOptions, debuggerPortOrDefault, createNodeWindow); + } + + private static ushort GetDebuggerPort() { + var debuggerPortOrDefault = NodejsConstants.DefaultDebuggerPort; + + var activeConnections = (from listener in IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpListeners() + select listener.Port).ToList(); + + if (activeConnections.Contains(debuggerPortOrDefault)) { + debuggerPortOrDefault = (ushort)Enumerable.Range(new Random().Next(5859, 6000), 60000).Except(activeConnections).First(); } - _debuggerEndpointUri = new UriBuilder { Scheme = "tcp", Host = "localhost", Port = debuggerPortOrDefault }.Uri; + return debuggerPortOrDefault; + } + + public static NodeProcess StartNodeProcessWithDebug(string exe, string script, string dir, string env, string interpreterOptions, NodeDebugOptions debugOptions, ushort? debuggerPort = null, bool createNodeWindow = true) { + // Select debugger port for a local connection + var debuggerPortOrDefault = debuggerPort ?? GetDebuggerPort(); // Node usage: node [options] [ -e script | script.js ] [arguments] - string allArgs = string.Format(CultureInfo.InvariantCulture, - "--debug-brk={0} --nolazy {1} {2}", - debuggerPortOrDefault, - interpreterOptions, - script - ); + var allArgs = $"--debug-brk={debuggerPortOrDefault} --nolazy {interpreterOptions} \"{script}\""; + + return StartNodeProcess(exe, dir, env, debugOptions, debuggerPortOrDefault, allArgs, createNodeWindow); + } + public static NodeProcess StartNodeProcessWithInspect(string exe, string script, string dir, string env, string interpreterOptions, NodeDebugOptions debugOptions, ushort? debuggerPort = null, bool createNodeWindow = true) { + // Select debugger port for a local connection + var debuggerPortOrDefault = debuggerPort ?? GetDebuggerPort(); + + // Node usage: node [options] [ -e script | script.js ] [arguments] + string allArgs = $"--debug-brk={debuggerPortOrDefault} --nolazy {interpreterOptions} {script}"; + + return StartNodeProcess(exe, dir, env, debugOptions, debuggerPortOrDefault, allArgs, createNodeWindow); + } + + // starts the nodeprocess in debug mode without hooking up our debugger, this way we can attach the WebKit debugger as a next step. + private static NodeProcess StartNodeProcess(string exe, string dir, string env, NodeDebugOptions debugOptions, ushort debuggerPortOrDefault, string allArgs, bool createNodeWindow) { var psi = new ProcessStartInfo(exe, allArgs) { CreateNoWindow = !createNodeWindow, WorkingDirectory = dir, @@ -116,42 +134,32 @@ public NodeDebugger( }; if (env != null) { - string[] envValues = env.Split('\0'); - foreach (string curValue in envValues) { - string[] nameValue = curValue.Split(new[] { '=' }, 2); + var envValues = env.Split('\0'); + foreach (var curValue in envValues) { + var nameValue = curValue.Split(new[] { '=' }, 2); if (nameValue.Length == 2 && !String.IsNullOrWhiteSpace(nameValue[0])) { psi.EnvironmentVariables[nameValue[0]] = nameValue[1]; } } } - _process = new NodeProcess( + return new NodeProcess( psi, - debugOptions.HasFlag(NodeDebugOptions.WaitOnAbnormalExit), - debugOptions.HasFlag(NodeDebugOptions.WaitOnNormalExit), - true); + waitOnAbnormal: debugOptions.HasFlag(NodeDebugOptions.WaitOnAbnormalExit), + waitOnNormal: debugOptions.HasFlag(NodeDebugOptions.WaitOnNormalExit), + enableRaisingEvents: true, + debuggerPort: debuggerPortOrDefault); } - public NodeDebugger(Uri debuggerEndpointUri, int id) - : this() { - _debuggerEndpointUri = debuggerEndpointUri; - _id = id; - _attached = true; - } + #region Public Process API - public int Id { - get { return _id != null ? _id.Value : _process.Id; } - } + public int Id => _id != null ? _id.Value : _process.Id; - private NodeThread MainThread { - get { return _threads[MainThreadId]; } - } + private NodeThread MainThread => _threads[MainThreadId]; - public bool HasExited { - get { return !_connection.Connected; } - } + public bool HasExited => !_connection.Connected; /// /// Gets or sets a value indicating whether executed remote debugging process. @@ -424,16 +432,12 @@ public void ClearExceptionTreatment() { /// /// Gets a next command identifier. /// - private int CommandId { - get { return Interlocked.Increment(ref _commandId); } - } + private int CommandId => Interlocked.Increment(ref _commandId); /// /// Gets a source mapper. /// - public SourceMapper SourceMapper { - get { return _sourceMapper; } - } + public SourceMapper SourceMapper => _sourceMapper; /// /// Gets or sets a file name mapper. @@ -650,7 +654,7 @@ private async Task ProcessBreakpointBreakAsync( } SetBreakpointCommand result = await SetBreakpointAsync(breakpoint, cancellationToken: cancellationToken).ConfigureAwait(false); - + // Treat rebound breakpoint binding as fully bound NodeBreakpointBinding reboundbreakpointBinding = CreateBreakpointBinding(breakpoint, result.BreakpointId, result.ScriptId, breakpoint.GetPosition(SourceMapper).FileName, result.Line, result.Column, true); HandleBindBreakpointSuccess(reboundbreakpointBinding, breakpoint); @@ -712,7 +716,7 @@ private void OnExceptionEvent(object sender, ExceptionEventArgs args) { var lookupCommand = new LookupCommand(CommandId, _resultFactory, new[] { exception.ErrorNumber.Value }); string errorCodeFromLookup = null; - + if (await TrySendRequestAsync(lookupCommand).ConfigureAwait(false)) { errorCodeFromLookup = lookupCommand.Results[errorNumber][0].StringValue; _errorCodes[errorNumber] = errorCodeFromLookup; @@ -848,10 +852,6 @@ private IEnumerable GetLocalFrames(IEnumerable s return backtraceCommand.Running; } - internal IList GetThreads() { - return _threads.Values.ToList(); - } - internal void SendStepOver(int identity) { DebugWriteCommand("StepOver"); DebuggerClient.RunWithRequestExceptionsHandled(async () => { @@ -1049,7 +1049,7 @@ internal async Task UpdateBreakpointBindingAsync( internal async Task GetBreakpointHitCountAsync(int breakpointId, CancellationToken cancellationToken = new CancellationToken()) { var listBreakpointsCommand = new ListBreakpointsCommand(CommandId); - + int hitCount; if (await TrySendRequestAsync(listBreakpointsCommand, cancellationToken).ConfigureAwait(false) && listBreakpointsCommand.Breakpoints.TryGetValue(breakpointId, out hitCount)) { @@ -1160,7 +1160,7 @@ internal async Task SetVariableValueAsync( return false; } } - + #endregion #region Debugging Events @@ -1211,7 +1211,7 @@ private bool GetOrAddModule(NodeModule module, out NodeModule value, NodeStackFr javaScriptFileName = FileNameMapper.GetLocalFileName(javaScriptFileName); // Try to get mapping for JS file - if(stackFrame != null) { + if (stackFrame != null) { line = stackFrame.Line; column = stackFrame.Column; } @@ -1255,8 +1255,6 @@ public NodeModule GetModuleForFilePath(string filePath) { internal void Close() { } - - #region IDisposable public void Dispose() { diff --git a/Nodejs/Product/Nodejs/Debugger/NodeEvaluationResult.cs b/Nodejs/Product/Nodejs/Debugger/NodeEvaluationResult.cs index ffb69e6d6..359d7275c 100644 --- a/Nodejs/Product/Nodejs/Debugger/NodeEvaluationResult.cs +++ b/Nodejs/Product/Nodejs/Debugger/NodeEvaluationResult.cs @@ -24,7 +24,7 @@ namespace Microsoft.NodejsTools.Debugger { /// /// Represents the result of an evaluation of an expression against a given stack frame. /// - class NodeEvaluationResult { + internal class NodeEvaluationResult { private readonly Regex _stringLengthExpression = new Regex(@"\.\.\. \(length: ([0-9]+)\)$", RegexOptions.Compiled); /// diff --git a/Nodejs/Product/Nodejs/Debugger/NodeEventEventArgs.cs b/Nodejs/Product/Nodejs/Debugger/NodeEventEventArgs.cs deleted file mode 100644 index 933cc41e9..000000000 --- a/Nodejs/Product/Nodejs/Debugger/NodeEventEventArgs.cs +++ /dev/null @@ -1,28 +0,0 @@ -//*********************************************************// -// Copyright (c) Microsoft. All rights reserved. -// -// Apache 2.0 License -// -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -// implied. See the License for the specific language governing -// permissions and limitations under the License. -// -//*********************************************************// - -using System; -using System.Collections.Generic; - -namespace Microsoft.NodejsTools.Debugger { - sealed class NodeEventEventArgs : EventArgs { - public readonly Dictionary Data; - - public NodeEventEventArgs(Dictionary data) { - Data = data; - } - } -} \ No newline at end of file diff --git a/Nodejs/Product/Nodejs/Debugger/NodeProcess.cs b/Nodejs/Product/Nodejs/Debugger/NodeProcess.cs index 935af5b88..885bbb0a4 100644 --- a/Nodejs/Product/Nodejs/Debugger/NodeProcess.cs +++ b/Nodejs/Product/Nodejs/Debugger/NodeProcess.cs @@ -29,13 +29,17 @@ namespace Microsoft.NodejsTools.Debugger { sealed class NodeProcess : IDisposable { private readonly ProcessStartInfo _psi; private readonly bool _waitOnAbnormal, _waitOnNormal, _enableRaisingEvents; - private Process _process, _pressAnyKeyProcess; + private Process _process; + private Process _pressAnyKeyProcess; - public NodeProcess(ProcessStartInfo psi, bool waitOnAbnormal, bool waitOnNormal, bool enableRaisingEvents) { + public ushort DebuggerPort { get; } + + public NodeProcess(ProcessStartInfo psi, bool waitOnAbnormal, bool waitOnNormal, bool enableRaisingEvents, ushort debuggerPort = 0) { _psi = psi; _waitOnAbnormal = waitOnAbnormal; _waitOnNormal = waitOnNormal; _enableRaisingEvents = enableRaisingEvents; + DebuggerPort = debuggerPort; } public static NodeProcess Start(ProcessStartInfo psi, bool waitOnAbnormal, bool waitOnNormal) { diff --git a/Nodejs/Product/Nodejs/Nodejs.csproj b/Nodejs/Product/Nodejs/Nodejs.csproj index d364a2828..efb0b3f83 100644 --- a/Nodejs/Product/Nodejs/Nodejs.csproj +++ b/Nodejs/Product/Nodejs/Nodejs.csproj @@ -1,4 +1,4 @@ - + @@ -404,7 +404,6 @@ - @@ -890,7 +889,6 @@ SalsaLsIntellisenseOptionsControl.cs - NewFileNameForm.cs @@ -915,7 +913,6 @@ - NodejsGeneralPropertyPageControl.cs @@ -940,7 +937,6 @@ - NodejsGeneralOptionsControl.cs @@ -950,6 +946,7 @@ PublicResXFileCodeGenerator NodejsGeneralOptionsControl.cs + Designer @@ -965,7 +962,6 @@ - NodejsNpmOptionsControl.cs @@ -990,7 +986,6 @@ - diff --git a/Nodejs/Product/Nodejs/Options/NodejsGeneralOptionsControl.Designer.cs b/Nodejs/Product/Nodejs/Options/NodejsGeneralOptionsControl.Designer.cs index 9521934a3..b329f9b78 100644 --- a/Nodejs/Product/Nodejs/Options/NodejsGeneralOptionsControl.Designer.cs +++ b/Nodejs/Product/Nodejs/Options/NodejsGeneralOptionsControl.Designer.cs @@ -24,45 +24,22 @@ protected override void Dispose(bool disposing) { /// private void InitializeComponent() { System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(NodejsGeneralOptionsControl)); - this.tableLayoutPanel3 = new System.Windows.Forms.TableLayoutPanel(); - this._surveyNewsCheckLabel = new System.Windows.Forms.Label(); - this._surveyNewsCheckCombo = new System.Windows.Forms.ComboBox(); this._topOptionsPanel = new System.Windows.Forms.Panel(); this._checkForLongPaths = new System.Windows.Forms.CheckBox(); this._editAndContinue = new System.Windows.Forms.CheckBox(); this._waitOnNormalExit = new System.Windows.Forms.CheckBox(); this._waitOnAbnormalExit = new System.Windows.Forms.CheckBox(); - this.tableLayoutPanel3.SuspendLayout(); + this._webkitDebugger = new System.Windows.Forms.CheckBox(); + this.tableLayoutPanel3 = new System.Windows.Forms.TableLayoutPanel(); + this._surveyNewsCheckCombo = new System.Windows.Forms.ComboBox(); + this._surveyNewsCheckLabel = new System.Windows.Forms.Label(); this._topOptionsPanel.SuspendLayout(); + this.tableLayoutPanel3.SuspendLayout(); this.SuspendLayout(); // - // tableLayoutPanel3 - // - resources.ApplyResources(this.tableLayoutPanel3, "tableLayoutPanel3"); - this.tableLayoutPanel3.Controls.Add(this._surveyNewsCheckLabel, 0, 7); - this.tableLayoutPanel3.Controls.Add(this._surveyNewsCheckCombo, 1, 7); - this.tableLayoutPanel3.Name = "tableLayoutPanel3"; - // - // _surveyNewsCheckLabel - // - resources.ApplyResources(this._surveyNewsCheckLabel, "_surveyNewsCheckLabel"); - this._surveyNewsCheckLabel.Name = "_surveyNewsCheckLabel"; - // - // _surveyNewsCheckCombo - // - resources.ApplyResources(this._surveyNewsCheckCombo, "_surveyNewsCheckCombo"); - this._surveyNewsCheckCombo.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; - this._surveyNewsCheckCombo.DropDownWidth = 172; - this._surveyNewsCheckCombo.FormattingEnabled = true; - this._surveyNewsCheckCombo.Items.AddRange(new object[] { - resources.GetString("_surveyNewsCheckCombo.Items"), - resources.GetString("_surveyNewsCheckCombo.Items1"), - resources.GetString("_surveyNewsCheckCombo.Items2"), - resources.GetString("_surveyNewsCheckCombo.Items3")}); - this._surveyNewsCheckCombo.Name = "_surveyNewsCheckCombo"; - // // _topOptionsPanel // + this._topOptionsPanel.Controls.Add(this._webkitDebugger); this._topOptionsPanel.Controls.Add(this._checkForLongPaths); this._topOptionsPanel.Controls.Add(this._editAndContinue); this._topOptionsPanel.Controls.Add(this._waitOnNormalExit); @@ -94,6 +71,37 @@ private void InitializeComponent() { this._waitOnAbnormalExit.Name = "_waitOnAbnormalExit"; this._waitOnAbnormalExit.UseVisualStyleBackColor = true; // + // _webkitDebugger + // + resources.ApplyResources(this._webkitDebugger, "_webkitDebugger"); + this._webkitDebugger.Name = "_webkitDebugger"; + this._webkitDebugger.UseVisualStyleBackColor = true; + // + // tableLayoutPanel3 + // + resources.ApplyResources(this.tableLayoutPanel3, "tableLayoutPanel3"); + this.tableLayoutPanel3.Controls.Add(this._surveyNewsCheckLabel, 0, 7); + this.tableLayoutPanel3.Controls.Add(this._surveyNewsCheckCombo, 1, 7); + this.tableLayoutPanel3.Name = "tableLayoutPanel3"; + // + // _surveyNewsCheckCombo + // + resources.ApplyResources(this._surveyNewsCheckCombo, "_surveyNewsCheckCombo"); + this._surveyNewsCheckCombo.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this._surveyNewsCheckCombo.DropDownWidth = 172; + this._surveyNewsCheckCombo.FormattingEnabled = true; + this._surveyNewsCheckCombo.Items.AddRange(new object[] { + resources.GetString("_surveyNewsCheckCombo.Items"), + resources.GetString("_surveyNewsCheckCombo.Items1"), + resources.GetString("_surveyNewsCheckCombo.Items2"), + resources.GetString("_surveyNewsCheckCombo.Items3")}); + this._surveyNewsCheckCombo.Name = "_surveyNewsCheckCombo"; + // + // _surveyNewsCheckLabel + // + resources.ApplyResources(this._surveyNewsCheckLabel, "_surveyNewsCheckLabel"); + this._surveyNewsCheckLabel.Name = "_surveyNewsCheckLabel"; + // // NodejsGeneralOptionsControl // resources.ApplyResources(this, "$this"); @@ -101,24 +109,24 @@ private void InitializeComponent() { this.Controls.Add(this.tableLayoutPanel3); this.Controls.Add(this._topOptionsPanel); this.Name = "NodejsGeneralOptionsControl"; - this.tableLayoutPanel3.ResumeLayout(false); - this.tableLayoutPanel3.PerformLayout(); this._topOptionsPanel.ResumeLayout(false); this._topOptionsPanel.PerformLayout(); + this.tableLayoutPanel3.ResumeLayout(false); + this.tableLayoutPanel3.PerformLayout(); this.ResumeLayout(false); this.PerformLayout(); } #endregion - - private System.Windows.Forms.TableLayoutPanel tableLayoutPanel3; - private System.Windows.Forms.Label _surveyNewsCheckLabel; - private System.Windows.Forms.ComboBox _surveyNewsCheckCombo; private System.Windows.Forms.Panel _topOptionsPanel; private System.Windows.Forms.CheckBox _waitOnNormalExit; private System.Windows.Forms.CheckBox _waitOnAbnormalExit; private System.Windows.Forms.CheckBox _editAndContinue; private System.Windows.Forms.CheckBox _checkForLongPaths; + private System.Windows.Forms.CheckBox _webkitDebugger; + private System.Windows.Forms.TableLayoutPanel tableLayoutPanel3; + private System.Windows.Forms.Label _surveyNewsCheckLabel; + private System.Windows.Forms.ComboBox _surveyNewsCheckCombo; } } diff --git a/Nodejs/Product/Nodejs/Options/NodejsGeneralOptionsControl.cs b/Nodejs/Product/Nodejs/Options/NodejsGeneralOptionsControl.cs index 2cc6ec645..646d543bc 100644 --- a/Nodejs/Product/Nodejs/Options/NodejsGeneralOptionsControl.cs +++ b/Nodejs/Product/Nodejs/Options/NodejsGeneralOptionsControl.cs @@ -66,6 +66,11 @@ internal void SyncControlWithPageSettings(NodejsGeneralOptionsPage page) { _waitOnNormalExit.Checked = page.WaitOnNormalExit; _editAndContinue.Checked = page.EditAndContinue; _checkForLongPaths.Checked = page.CheckForLongPaths; + _webkitDebugger.Checked = page.UseWebKitDebugger; + +#if !DEV15 + _webkitDebugger.Enabled = false; +#endif } internal void SyncPageWithControlSettings(NodejsGeneralOptionsPage page) { @@ -74,6 +79,7 @@ internal void SyncPageWithControlSettings(NodejsGeneralOptionsPage page) { page.WaitOnNormalExit = _waitOnNormalExit.Checked; page.EditAndContinue = _editAndContinue.Checked; page.CheckForLongPaths = _checkForLongPaths.Checked; + page.UseWebKitDebugger = _webkitDebugger.Checked; } } } \ No newline at end of file diff --git a/Nodejs/Product/Nodejs/Options/NodejsGeneralOptionsControl.en.resx b/Nodejs/Product/Nodejs/Options/NodejsGeneralOptionsControl.en.resx index 438dca5f1..97589a3ce 100644 --- a/Nodejs/Product/Nodejs/Options/NodejsGeneralOptionsControl.en.resx +++ b/Nodejs/Product/Nodejs/Options/NodejsGeneralOptionsControl.en.resx @@ -118,125 +118,38 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - + True - - GrowAndShrink - - - 2 - - - Left - - - True + + NoControl - - 6, 7 - - - 6, 0, 6, 0 - - - 117, 13 - - - 7 - - - &Check for survey/news - - - MiddleLeft + + 4, 96 - - _surveyNewsCheckLabel - - - System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + 304, 17 - - tableLayoutPanel3 + + 5 - - 0 - - - Left, Right - - - Never + + Use the new NodeJs debugger protocol (for NodeJs v7.5+) - - Once a day - - - Once a week - - - Once a month - - - 135, 3 - - - 6, 3, 6, 3 + + _webkitDebugger - - 240, 21 - - - 8 - - - _surveyNewsCheckCombo - - - System.Windows.Forms.ComboBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - tableLayoutPanel3 - - - 1 - - - Fill - - - 0, 97 - - - 3, 4, 3, 4 - - - 9 - - - 381, 193 - - - 0 - - - tableLayoutPanel3 - - - System.Windows.Forms.TableLayoutPanel, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + System.Windows.Forms.CheckBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - $this + + _topOptionsPanel - + 0 - - <?xml version="1.0" encoding="utf-16"?><TableLayoutSettings><Controls><Control Name="_surveyNewsCheckLabel" Row="7" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="_surveyNewsCheckCombo" Row="7" RowSpan="1" Column="1" ColumnSpan="1" /></Controls><Columns Styles="AutoSize,0,Percent,100" /><Rows Styles="AutoSize,0,AutoSize,0,AutoSize,0,AutoSize,0,AutoSize,0,AutoSize,0,AutoSize,0,AutoSize,0,Absolute,20" /></TableLayoutSettings> - True @@ -262,7 +175,7 @@ _topOptionsPanel - 0 + 1 True @@ -289,7 +202,7 @@ _topOptionsPanel - 1 + 2 True @@ -316,7 +229,7 @@ _topOptionsPanel - 2 + 3 True @@ -343,7 +256,7 @@ _topOptionsPanel - 3 + 4 Top @@ -352,7 +265,7 @@ 0, 0 - 381, 97 + 381, 120 1 @@ -369,6 +282,126 @@ 1 + + True + + + GrowAndShrink + + + 2 + + + Left + + + True + + + NoControl + + + 6, 7 + + + 6, 0, 6, 0 + + + 117, 13 + + + 7 + + + &Check for survey/news + + + MiddleLeft + + + _surveyNewsCheckLabel + + + System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + tableLayoutPanel3 + + + 0 + + + Left, Right + + + Never + + + Once a day + + + Once a week + + + Once a month + + + 135, 3 + + + 6, 3, 6, 3 + + + 240, 21 + + + 8 + + + _surveyNewsCheckCombo + + + System.Windows.Forms.ComboBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + tableLayoutPanel3 + + + 1 + + + Fill + + + 0, 120 + + + 3, 4, 3, 4 + + + 9 + + + 381, 170 + + + 0 + + + tableLayoutPanel3 + + + System.Windows.Forms.TableLayoutPanel, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 0 + + + <?xml version="1.0" encoding="utf-16"?><TableLayoutSettings><Controls><Control Name="_surveyNewsCheckLabel" Row="7" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="_surveyNewsCheckCombo" Row="7" RowSpan="1" Column="1" ColumnSpan="1" /></Controls><Columns Styles="AutoSize,0,Percent,100" /><Rows Styles="AutoSize,0,AutoSize,0,AutoSize,0,AutoSize,0,AutoSize,0,AutoSize,0,AutoSize,0,AutoSize,0,Absolute,20" /></TableLayoutSettings> + True diff --git a/Nodejs/Product/Nodejs/Options/NodejsGeneralOptionsPage.cs b/Nodejs/Product/Nodejs/Options/NodejsGeneralOptionsPage.cs index 7c55fb455..f37a8081f 100644 --- a/Nodejs/Product/Nodejs/Options/NodejsGeneralOptionsPage.cs +++ b/Nodejs/Product/Nodejs/Options/NodejsGeneralOptionsPage.cs @@ -21,6 +21,7 @@ namespace Microsoft.NodejsTools.Options { [ComVisible(true)] public class NodejsGeneralOptionsPage : NodejsDialogPage { + private const string DefaultSurveyNewsFeedUrl = "https://go.microsoft.com/fwlink/?LinkId=328027"; private const string DefaultSurveyNewsIndexUrl = "https://go.microsoft.com/fwlink/?LinkId=328029"; private const string SurveyNewsCheckSetting = "SurveyNewsCheck"; @@ -31,10 +32,8 @@ public class NodejsGeneralOptionsPage : NodejsDialogPage { private const string WaitOnNormalExitSetting = "WaitOnNormalExit"; private const string EditAndContinueSetting = "EditAndContinue"; private const string CheckForLongPathsSetting = "CheckForLongPaths"; - private SurveyNewsPolicy _surveyNewsCheck; - private string _surveyNewsFeedUrl; - private string _surveyNewsIndexUrl; - private DateTime _surveyNewsLastCheck; + private const string UseWebKitDebuggerSetting = "UseWebKitDebugger"; + private NodejsGeneralOptionsControl _window; public NodejsGeneralOptionsPage() @@ -74,38 +73,31 @@ protected override IWin32Window Window { /// public bool CheckForLongPaths { get; set; } + /// + /// Indicates whether we should use the WebKit debugger or the default NodeJs debugger. + /// + public bool UseWebKitDebugger { get; set; } + /// /// The frequency at which to check for updated news. Default is once /// per week. /// - public SurveyNewsPolicy SurveyNewsCheck { - get { return _surveyNewsCheck; } - set { _surveyNewsCheck = value; } - } + public SurveyNewsPolicy SurveyNewsCheck { get; set; } /// /// The date/time when the last check for news occurred. /// - public DateTime SurveyNewsLastCheck { - get { return _surveyNewsLastCheck; } - set { _surveyNewsLastCheck = value; } - } + public DateTime SurveyNewsLastCheck { get; set; } /// /// The url of the news feed. /// - public string SurveyNewsFeedUrl { - get { return _surveyNewsFeedUrl; } - set { _surveyNewsFeedUrl = value; } - } + public string SurveyNewsFeedUrl { get; set; } /// /// The url of the news index page. /// - public string SurveyNewsIndexUrl { - get { return _surveyNewsIndexUrl; } - set { _surveyNewsIndexUrl = value; } - } + public string SurveyNewsIndexUrl { get; set; } /// /// Resets settings back to their defaults. This should be followed by @@ -113,26 +105,28 @@ public string SurveyNewsIndexUrl { /// values. /// public override void ResetSettings() { - _surveyNewsCheck = SurveyNewsPolicy.CheckOnceWeek; - _surveyNewsLastCheck = DateTime.MinValue; - _surveyNewsFeedUrl = DefaultSurveyNewsFeedUrl; - _surveyNewsIndexUrl = DefaultSurveyNewsIndexUrl; + SurveyNewsCheck = SurveyNewsPolicy.CheckOnceWeek; + SurveyNewsLastCheck = DateTime.MinValue; + SurveyNewsFeedUrl = DefaultSurveyNewsFeedUrl; + SurveyNewsIndexUrl = DefaultSurveyNewsIndexUrl; WaitOnAbnormalExit = true; WaitOnNormalExit = false; EditAndContinue = true; CheckForLongPaths = true; + UseWebKitDebugger = false; } public override void LoadSettingsFromStorage() { // Load settings from storage. - _surveyNewsCheck = LoadEnum(SurveyNewsCheckSetting) ?? SurveyNewsPolicy.CheckOnceWeek; - _surveyNewsLastCheck = LoadDateTime(SurveyNewsLastCheckSetting) ?? DateTime.MinValue; - _surveyNewsFeedUrl = LoadString(SurveyNewsFeedUrlSetting) ?? DefaultSurveyNewsFeedUrl; - _surveyNewsIndexUrl = LoadString(SurveyNewsIndexUrlSetting) ?? DefaultSurveyNewsIndexUrl; + SurveyNewsCheck = LoadEnum(SurveyNewsCheckSetting) ?? SurveyNewsPolicy.CheckOnceWeek; + SurveyNewsLastCheck = LoadDateTime(SurveyNewsLastCheckSetting) ?? DateTime.MinValue; + SurveyNewsFeedUrl = LoadString(SurveyNewsFeedUrlSetting) ?? DefaultSurveyNewsFeedUrl; + SurveyNewsIndexUrl = LoadString(SurveyNewsIndexUrlSetting) ?? DefaultSurveyNewsIndexUrl; WaitOnAbnormalExit = LoadBool(WaitOnAbnormalExitSetting) ?? true; WaitOnNormalExit = LoadBool(WaitOnNormalExitSetting) ?? false; EditAndContinue = LoadBool(EditAndContinueSetting) ?? true; CheckForLongPaths = LoadBool(CheckForLongPathsSetting) ?? true; + UseWebKitDebugger = LoadBool(UseWebKitDebuggerSetting) ?? false; // Synchronize UI with backing properties. if (_window != null) { @@ -147,12 +141,13 @@ public override void SaveSettingsToStorage() { } // Save settings. - SaveEnum(SurveyNewsCheckSetting, _surveyNewsCheck); - SaveDateTime(SurveyNewsLastCheckSetting, _surveyNewsLastCheck); + SaveEnum(SurveyNewsCheckSetting, SurveyNewsCheck); + SaveDateTime(SurveyNewsLastCheckSetting, SurveyNewsLastCheck); SaveBool(WaitOnNormalExitSetting, WaitOnNormalExit); SaveBool(WaitOnAbnormalExitSetting, WaitOnAbnormalExit); SaveBool(EditAndContinueSetting, EditAndContinue); SaveBool(CheckForLongPathsSetting, CheckForLongPaths); + SaveBool(UseWebKitDebuggerSetting, UseWebKitDebugger); } } } \ No newline at end of file diff --git a/Nodejs/Product/Nodejs/Project/NodejsProjectLauncher.cs b/Nodejs/Product/Nodejs/Project/NodejsProjectLauncher.cs index 91a64802c..d1a6540ad 100644 --- a/Nodejs/Product/Nodejs/Project/NodejsProjectLauncher.cs +++ b/Nodejs/Product/Nodejs/Project/NodejsProjectLauncher.cs @@ -15,9 +15,7 @@ //*********************************************************// using System; -using System.Collections; using System.Collections.Generic; -using System.Collections.Specialized; using System.Diagnostics; using System.Globalization; using System.IO; @@ -32,14 +30,14 @@ using System.Windows.Forms; using Microsoft.NodejsTools.Debugger; using Microsoft.NodejsTools.Debugger.DebugEngine; +using Microsoft.NodejsTools.TypeScript; using Microsoft.VisualStudio; using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Shell.Interop; using Microsoft.VisualStudioTools.Project; -using Microsoft.NodejsTools.TypeScript; namespace Microsoft.NodejsTools.Project { - class NodejsProjectLauncher : IProjectLauncher { + internal class NodejsProjectLauncher : IProjectLauncher { private readonly NodejsProjectNode _project; private int? _testServerPort; @@ -66,53 +64,130 @@ public int LaunchFile(string file, bool debug) { } private int Start(string file, bool debug) { - string nodePath = GetNodePath(); + var nodePath = GetNodePath(); if (nodePath == null) { Nodejs.ShowNodejsNotInstalled(); return VSConstants.S_OK; } bool startBrowser = ShouldStartBrowser(); +#if !DEV15 + bool useWebKitDebugger = false; +#else + bool useWebKitDebugger = NodejsPackage.Instance.GeneralOptionsPage.UseWebKitDebugger; +#endif - if (debug) { + if (debug && !useWebKitDebugger) { StartWithDebugger(file); + } else if (debug && useWebKitDebugger) { + StartAndAttachDebugger(file, nodePath); } else { - var psi = new ProcessStartInfo(); - psi.UseShellExecute = false; + StartNodeProcess(file, nodePath, startBrowser); + } + + return VSConstants.S_OK; + } - psi.FileName = nodePath; - psi.Arguments = GetFullArguments(file); - psi.WorkingDirectory = _project.GetWorkingDirectory(); + private void StartAndAttachDebugger(string file, string nodePath) { - string webBrowserUrl = GetFullUrl(); - Uri uri = null; - if (!String.IsNullOrWhiteSpace(webBrowserUrl)) { - uri = new Uri(webBrowserUrl); + string workingDir = _project.GetWorkingDirectory(); + string env = ""; + var interpreterOptions = _project.GetProjectProperty(NodeProjectProperty.NodeExeArguments); - psi.EnvironmentVariables["PORT"] = uri.Port.ToString(); - } + var process = NodeDebugger.StartNodeProcessWithInspect(exe: nodePath, script: file, dir: workingDir, env: env, interpreterOptions: interpreterOptions, debugOptions: NodeDebugOptions.None); + process.Start(); - foreach (var nameValue in GetEnvironmentVariables()) { - psi.EnvironmentVariables[nameValue.Key] = nameValue.Value; - } + // setup debug info and attach + var webkitDebuggerGuid = Guid.Parse("4cc6df14-0ab5-4a91-8bb4-eb0bf233d0fe"); + var webkitPortSupplierGuid = Guid.Parse("4103f338-2255-40c0-acf5-7380e2bea13d"); + var debugUri = $"http://127.0.0.1:{process.DebuggerPort}"; - var process = NodeProcess.Start( - psi, - NodejsPackage.Instance.GeneralOptionsPage.WaitOnAbnormalExit, - NodejsPackage.Instance.GeneralOptionsPage.WaitOnNormalExit); - _project.OnDispose += process.ResponseToTerminateEvent; - - if (startBrowser && uri != null) { - OnPortOpenedHandler.CreateHandler( - uri.Port, - shortCircuitPredicate: () => process.HasExited, - action: () => { - VsShellUtilities.OpenBrowser(webBrowserUrl, (uint)__VSOSPFLAGS.OSP_LaunchNewBrowser); - } - ); - } + var dbgInfo = new VsDebugTargetInfo4(); + dbgInfo.dlo = (uint)DEBUG_LAUNCH_OPERATION.DLO_AlreadyRunning; + dbgInfo.LaunchFlags = (uint)__VSDBGLAUNCHFLAGS.DBGLAUNCH_DetachOnStop; + + dbgInfo.guidLaunchDebugEngine = webkitDebuggerGuid; + dbgInfo.dwDebugEngineCount = 1; + + var enginesPtr = MarshalDebugEngines(new[] { webkitDebuggerGuid }); + dbgInfo.pDebugEngines = enginesPtr; + dbgInfo.guidPortSupplier = webkitPortSupplierGuid; + dbgInfo.bstrPortName = debugUri; + + // we connect through a URI, so no need to set the process, + // we need to set the process id to '1' so the debugger is able to attach + dbgInfo.bstrExe = $"\01"; + + AttachDebugger(dbgInfo); + } + + private void AttachDebugger(VsDebugTargetInfo4 dbgInfo) { + var serviceProvider = _project.Site; + + var launchResults = new VsDebugTargetProcessInfo[1]; + var debugger = serviceProvider.GetService(typeof(SVsShellDebugger)) as IVsDebugger4; + + if (debugger == null) { + throw new InvalidOperationException(); + } + + debugger.LaunchDebugTargets4(1, new[] { dbgInfo }, launchResults); + } + + private static IntPtr MarshalDebugEngines(Guid[] debugEngines) { + if (debugEngines.Length == 0) { + return IntPtr.Zero; + } + + var guiSize = Marshal.SizeOf(typeof(Guid)); + var size = debugEngines.Length * guiSize; + var bytes = new byte[size]; + for (var i = 0; i < debugEngines.Length; ++i) { + debugEngines[i].ToByteArray().CopyTo(bytes, i * guiSize); + } + + var pDebugEngines = Marshal.AllocCoTaskMem(size); + Marshal.Copy(bytes, 0, pDebugEngines, size); + + return pDebugEngines; + } + + private void StartNodeProcess(string file, string nodePath, bool startBrowser) { + //TODO: looks like this duplicates a ton of code in NodeDebugger + var psi = new ProcessStartInfo() { + UseShellExecute = false, + + FileName = nodePath, + Arguments = GetFullArguments(file), + WorkingDirectory = _project.GetWorkingDirectory() + }; + + var webBrowserUrl = GetFullUrl(); + Uri uri = null; + if (!String.IsNullOrWhiteSpace(webBrowserUrl)) { + uri = new Uri(webBrowserUrl); + psi.EnvironmentVariables["PORT"] = uri.Port.ToString(); + } + + foreach (var nameValue in GetEnvironmentVariables()) { + psi.EnvironmentVariables[nameValue.Key] = nameValue.Value; + } + + var process = NodeProcess.Start( + psi, + waitOnAbnormal: NodejsPackage.Instance.GeneralOptionsPage.WaitOnAbnormalExit, + waitOnNormal: NodejsPackage.Instance.GeneralOptionsPage.WaitOnNormalExit); + _project.OnDispose += process.ResponseToTerminateEvent; + + if (startBrowser && uri != null) { + OnPortOpenedHandler.CreateHandler( + uri.Port, + shortCircuitPredicate: () => process.HasExited, + action: () => { + VsShellUtilities.OpenBrowser(webBrowserUrl, (uint)__VSOSPFLAGS.OSP_LaunchNewBrowser); + } + ); } - return VSConstants.S_OK; } private string GetFullArguments(string file, bool includeNodeArgs = true) { @@ -136,7 +211,7 @@ private string GetNodePath() { return Nodejs.GetAbsoluteNodeExePath(_project.ProjectHome, overridePath); } - #endregion +#endregion private string GetFullUrl() { var host = _project.GetProjectProperty(NodeProjectProperty.LaunchUrl); @@ -181,7 +256,7 @@ private int TestServerPort { /// Default implementation of the "Start Debugging" command. /// private void StartWithDebugger(string startupFile) { - VsDebugTargetInfo dbgInfo = new VsDebugTargetInfo(); + var dbgInfo = new VsDebugTargetInfo(); dbgInfo.cbSize = (uint)Marshal.SizeOf(dbgInfo); if (SetupDebugInfo(ref dbgInfo, startupFile)) { @@ -189,7 +264,6 @@ private void StartWithDebugger(string startupFile) { } } - private void LaunchDebugger(IServiceProvider provider, VsDebugTargetInfo dbgInfo) { if (!Directory.Exists(dbgInfo.bstrCurDir)) { MessageBox.Show(string.Format(CultureInfo.CurrentCulture, Resources.DebugWorkingDirectoryDoesNotExistErrorMessage, dbgInfo.bstrCurDir), SR.ProductName); @@ -257,7 +331,7 @@ private bool SetupDebugInfo(ref VsDebugTargetInfo dbgInfo, string startupFile) { dbgInfo.fSendStdoutToOutputWindow = 0; - StringDictionary env = new StringDictionary(); + var env = new Dictionary(StringComparer.OrdinalIgnoreCase); if (!String.IsNullOrWhiteSpace(url)) { Uri webUrl = new Uri(url); env["PORT"] = webUrl.Port.ToString(); @@ -281,7 +355,7 @@ private bool SetupDebugInfo(ref VsDebugTargetInfo dbgInfo, string startupFile) { //null-terminated block of null-terminated strings. //Each string is in the following form:name=value\0 StringBuilder buf = new StringBuilder(); - foreach (DictionaryEntry entry in env) { + foreach (var entry in env) { buf.AppendFormat("{0}={1}\0", entry.Key, entry.Value); } buf.Append("\0"); @@ -424,4 +498,4 @@ private static void OnPortOpened(object infoObj) { } } } -} +} \ No newline at end of file From 9e71319fadc6e79a7dfd712c56e00d87278699d7 Mon Sep 17 00:00:00 2001 From: Paul van Brenk Date: Thu, 23 Feb 2017 11:38:43 -0800 Subject: [PATCH 2/9] Correctly escape script when using inspect --- Nodejs/Product/Nodejs/Debugger/NodeDebugger.cs | 2 +- .../Nodejs/Project/NodejsProjectLauncher.cs | 18 ++++++++++-------- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/Nodejs/Product/Nodejs/Debugger/NodeDebugger.cs b/Nodejs/Product/Nodejs/Debugger/NodeDebugger.cs index 46917aac3..ee7ba667f 100644 --- a/Nodejs/Product/Nodejs/Debugger/NodeDebugger.cs +++ b/Nodejs/Product/Nodejs/Debugger/NodeDebugger.cs @@ -120,7 +120,7 @@ public static NodeProcess StartNodeProcessWithInspect(string exe, string script, var debuggerPortOrDefault = debuggerPort ?? GetDebuggerPort(); // Node usage: node [options] [ -e script | script.js ] [arguments] - string allArgs = $"--debug-brk={debuggerPortOrDefault} --nolazy {interpreterOptions} {script}"; + string allArgs = $"--inspect={debuggerPortOrDefault} --debug-brk --nolazy {interpreterOptions} \"{script}\""; return StartNodeProcess(exe, dir, env, debugOptions, debuggerPortOrDefault, allArgs, createNodeWindow); } diff --git a/Nodejs/Product/Nodejs/Project/NodejsProjectLauncher.cs b/Nodejs/Product/Nodejs/Project/NodejsProjectLauncher.cs index d1a6540ad..1d840488a 100644 --- a/Nodejs/Product/Nodejs/Project/NodejsProjectLauncher.cs +++ b/Nodejs/Product/Nodejs/Project/NodejsProjectLauncher.cs @@ -41,6 +41,9 @@ internal class NodejsProjectLauncher : IProjectLauncher { private readonly NodejsProjectNode _project; private int? _testServerPort; + private static readonly Guid WebkitDebuggerGuid = Guid.Parse("4cc6df14-0ab5-4a91-8bb4-eb0bf233d0fe"); + private static readonly Guid WebkitPortSupplierGuid = Guid.Parse("4103f338-2255-40c0-acf5-7380e2bea13d"); + public NodejsProjectLauncher(NodejsProjectNode project) { _project = project; @@ -90,6 +93,7 @@ private int Start(string file, bool debug) { private void StartAndAttachDebugger(string file, string nodePath) { + // start the node process string workingDir = _project.GetWorkingDirectory(); string env = ""; var interpreterOptions = _project.GetProjectProperty(NodeProjectProperty.NodeExeArguments); @@ -98,20 +102,18 @@ private void StartAndAttachDebugger(string file, string nodePath) { process.Start(); // setup debug info and attach - var webkitDebuggerGuid = Guid.Parse("4cc6df14-0ab5-4a91-8bb4-eb0bf233d0fe"); - var webkitPortSupplierGuid = Guid.Parse("4103f338-2255-40c0-acf5-7380e2bea13d"); var debugUri = $"http://127.0.0.1:{process.DebuggerPort}"; var dbgInfo = new VsDebugTargetInfo4(); dbgInfo.dlo = (uint)DEBUG_LAUNCH_OPERATION.DLO_AlreadyRunning; dbgInfo.LaunchFlags = (uint)__VSDBGLAUNCHFLAGS.DBGLAUNCH_DetachOnStop; - dbgInfo.guidLaunchDebugEngine = webkitDebuggerGuid; + dbgInfo.guidLaunchDebugEngine = WebkitDebuggerGuid; dbgInfo.dwDebugEngineCount = 1; - var enginesPtr = MarshalDebugEngines(new[] { webkitDebuggerGuid }); + var enginesPtr = MarshalDebugEngines(new[] { WebkitDebuggerGuid }); dbgInfo.pDebugEngines = enginesPtr; - dbgInfo.guidPortSupplier = webkitPortSupplierGuid; + dbgInfo.guidPortSupplier = WebkitPortSupplierGuid; dbgInfo.bstrPortName = debugUri; // we connect through a URI, so no need to set the process, @@ -124,13 +126,13 @@ private void StartAndAttachDebugger(string file, string nodePath) { private void AttachDebugger(VsDebugTargetInfo4 dbgInfo) { var serviceProvider = _project.Site; - var launchResults = new VsDebugTargetProcessInfo[1]; var debugger = serviceProvider.GetService(typeof(SVsShellDebugger)) as IVsDebugger4; if (debugger == null) { - throw new InvalidOperationException(); + throw new InvalidOperationException("Failed to get the debugger service."); } + var launchResults = new VsDebugTargetProcessInfo[1]; debugger.LaunchDebugTargets4(1, new[] { dbgInfo }, launchResults); } @@ -351,7 +353,7 @@ private bool SetupDebugInfo(ref VsDebugTargetInfo dbgInfo, string startupFile) { } } - //Environemnt variables should be passed as a + //Environment variables should be passed as a //null-terminated block of null-terminated strings. //Each string is in the following form:name=value\0 StringBuilder buf = new StringBuilder(); From 9e03b4c63544f26c3d8d77aae76f6b49cc45f9f5 Mon Sep 17 00:00:00 2001 From: Paul van Brenk Date: Thu, 23 Feb 2017 17:22:30 -0800 Subject: [PATCH 3/9] Finish up options to use when starting the Node process --- .../Nodejs/Debugger/DebugEngine/AD7Engine.cs | 10 ---- .../Nodejs/Debugger/NodeDebugOptions.cs | 10 ---- .../Product/Nodejs/Debugger/NodeDebugger.cs | 4 +- Nodejs/Product/Nodejs/Logging/LiveLogger.cs | 4 +- .../Nodejs/Project/NodejsProjectLauncher.cs | 52 ++++++++++++++----- 5 files changed, 41 insertions(+), 39 deletions(-) diff --git a/Nodejs/Product/Nodejs/Debugger/DebugEngine/AD7Engine.cs b/Nodejs/Product/Nodejs/Debugger/DebugEngine/AD7Engine.cs index 5787792eb..7d7b5c991 100644 --- a/Nodejs/Product/Nodejs/Debugger/DebugEngine/AD7Engine.cs +++ b/Nodejs/Product/Nodejs/Debugger/DebugEngine/AD7Engine.cs @@ -85,11 +85,6 @@ public sealed class AD7Engine : IDebugEngine2, IDebugEngineLaunch2, IDebugProgra /// public const string WaitOnNormalExitSetting = "WAIT_ON_NORMAL_EXIT"; - /// - /// Specifies if the output should be redirected to the visual studio output window. - /// - public const string RedirectOutputSetting = "REDIRECT_OUTPUT"; - /// /// Specifies options which should be passed to the Node runtime before the script. If /// the interpreter options should include a semicolon then it should be escaped as a double @@ -517,11 +512,6 @@ int IDebugEngineLaunch2.LaunchSuspended(string pszServer, IDebugPort2 port, stri debugOptions |= NodeDebugOptions.WaitOnNormalExit; } break; - case RedirectOutputSetting: - if (Boolean.TryParse(setting[1], out value) && value) { - debugOptions |= NodeDebugOptions.RedirectOutput; - } - break; case DirMappingSetting: string[] dirs = setting[1].Split('|'); if (dirs.Length == 2) { diff --git a/Nodejs/Product/Nodejs/Debugger/NodeDebugOptions.cs b/Nodejs/Product/Nodejs/Debugger/NodeDebugOptions.cs index b3fec9a2e..a4d475c8d 100644 --- a/Nodejs/Product/Nodejs/Debugger/NodeDebugOptions.cs +++ b/Nodejs/Product/Nodejs/Debugger/NodeDebugOptions.cs @@ -29,15 +29,5 @@ internal enum NodeDebugOptions { /// Passing this flag to the debugger will cause it to wait for input on a normal (zero) exit code. /// WaitOnNormalExit = 0x02, - /// - /// Passing this flag will cause output to standard out to be redirected via the debugger - /// so it can be outputted in the Visual Studio debug output window. - /// - RedirectOutput = 0x04, - - /// - /// Set if you do not want to create a window - /// - CreateNoWindow = 0x40 } } diff --git a/Nodejs/Product/Nodejs/Debugger/NodeDebugger.cs b/Nodejs/Product/Nodejs/Debugger/NodeDebugger.cs index ee7ba667f..47936f47c 100644 --- a/Nodejs/Product/Nodejs/Debugger/NodeDebugger.cs +++ b/Nodejs/Product/Nodejs/Debugger/NodeDebugger.cs @@ -151,8 +151,6 @@ private static NodeProcess StartNodeProcess(string exe, string dir, string env, debuggerPort: debuggerPortOrDefault); } - - #region Public Process API public int Id => _id != null ? _id.Value : _process.Id; @@ -244,7 +242,7 @@ public async Task BreakAllAsync() { // We need to get the backtrace before we break, so we request the backtrace // and follow up with firing the appropriate event for the break tokenSource = new CancellationTokenSource(_timeout); - bool running = await PerformBacktraceAsync(tokenSource.Token).ConfigureAwait(false); + var running = await PerformBacktraceAsync(tokenSource.Token).ConfigureAwait(false); Debug.Assert(!running); // Fallback to firing step complete event diff --git a/Nodejs/Product/Nodejs/Logging/LiveLogger.cs b/Nodejs/Product/Nodejs/Logging/LiveLogger.cs index 745820dc3..42fb0c4f4 100644 --- a/Nodejs/Product/Nodejs/Logging/LiveLogger.cs +++ b/Nodejs/Product/Nodejs/Logging/LiveLogger.cs @@ -14,11 +14,11 @@ // //*********************************************************// -using Microsoft.NodejsTools.Options; -using Microsoft.VisualStudioTools.Project; using System; using System.Diagnostics; using System.Globalization; +using Microsoft.NodejsTools.Options; +using Microsoft.VisualStudioTools.Project; namespace Microsoft.NodejsTools.Logging { diff --git a/Nodejs/Product/Nodejs/Project/NodejsProjectLauncher.cs b/Nodejs/Product/Nodejs/Project/NodejsProjectLauncher.cs index 1d840488a..56d5ed60c 100644 --- a/Nodejs/Product/Nodejs/Project/NodejsProjectLauncher.cs +++ b/Nodejs/Product/Nodejs/Project/NodejsProjectLauncher.cs @@ -94,11 +94,12 @@ private int Start(string file, bool debug) { private void StartAndAttachDebugger(string file, string nodePath) { // start the node process - string workingDir = _project.GetWorkingDirectory(); - string env = ""; + var workingDir = _project.GetWorkingDirectory(); + var env = ""; var interpreterOptions = _project.GetProjectProperty(NodeProjectProperty.NodeExeArguments); + var debugOptions = this.GetDebugOptions(); - var process = NodeDebugger.StartNodeProcessWithInspect(exe: nodePath, script: file, dir: workingDir, env: env, interpreterOptions: interpreterOptions, debugOptions: NodeDebugOptions.None); + var process = NodeDebugger.StartNodeProcessWithInspect(exe: nodePath, script: file, dir: workingDir, env: env, interpreterOptions: interpreterOptions, debugOptions: debugOptions); process.Start(); // setup debug info and attach @@ -106,7 +107,7 @@ private void StartAndAttachDebugger(string file, string nodePath) { var dbgInfo = new VsDebugTargetInfo4(); dbgInfo.dlo = (uint)DEBUG_LAUNCH_OPERATION.DLO_AlreadyRunning; - dbgInfo.LaunchFlags = (uint)__VSDBGLAUNCHFLAGS.DBGLAUNCH_DetachOnStop; + dbgInfo.LaunchFlags = (uint)__VSDBGLAUNCHFLAGS.DBGLAUNCH_StopDebuggingOnEnd; dbgInfo.guidLaunchDebugEngine = WebkitDebuggerGuid; dbgInfo.dwDebugEngineCount = 1; @@ -115,6 +116,7 @@ private void StartAndAttachDebugger(string file, string nodePath) { dbgInfo.pDebugEngines = enginesPtr; dbgInfo.guidPortSupplier = WebkitPortSupplierGuid; dbgInfo.bstrPortName = debugUri; + dbgInfo.fSendToOutputWindow = 0; // we connect through a URI, so no need to set the process, // we need to set the process id to '1' so the debugger is able to attach @@ -123,6 +125,22 @@ private void StartAndAttachDebugger(string file, string nodePath) { AttachDebugger(dbgInfo); } + private NodeDebugOptions GetDebugOptions() { + + var debugOptions = NodeDebugOptions.None; + + if (NodejsPackage.Instance.GeneralOptionsPage.WaitOnAbnormalExit) { + debugOptions |= NodeDebugOptions.WaitOnAbnormalExit; + } + + if (NodejsPackage.Instance.GeneralOptionsPage.WaitOnNormalExit) { + debugOptions |= NodeDebugOptions.WaitOnNormalExit; + } + + + return debugOptions; + } + private void AttachDebugger(VsDebugTargetInfo4 dbgInfo) { var serviceProvider = _project.Site; @@ -155,7 +173,7 @@ private static IntPtr MarshalDebugEngines(Guid[] debugEngines) { } private void StartNodeProcess(string file, string nodePath, bool startBrowser) { - //TODO: looks like this duplicates a ton of code in NodeDebugger + //TODO: looks like this duplicates a bunch of code in NodeDebugger var psi = new ProcessStartInfo() { UseShellExecute = false, @@ -228,7 +246,7 @@ private string GetFullUrl() { } } - internal static string GetFullUrl(string host, int port) { + private static string GetFullUrl(string host, int port) { UriBuilder builder; Uri uri; if (Uri.TryCreate(host, UriKind.Absolute, out uri)) { @@ -332,10 +350,19 @@ private bool SetupDebugInfo(ref VsDebugTargetInfo dbgInfo, string startupFile) { } dbgInfo.fSendStdoutToOutputWindow = 0; + dbgInfo.bstrEnv = GetEnvironmentVariablesString(url); + + // Set the Node debugger + dbgInfo.clsidCustom = AD7Engine.DebugEngineGuid; + dbgInfo.grfLaunch = (uint)__VSDBGLAUNCHFLAGS.DBGLAUNCH_StopDebuggingOnEnd; + return true; + } + + private string GetEnvironmentVariablesString(string url) { var env = new Dictionary(StringComparer.OrdinalIgnoreCase); if (!String.IsNullOrWhiteSpace(url)) { - Uri webUrl = new Uri(url); + var webUrl = new Uri(url); env["PORT"] = webUrl.Port.ToString(); } @@ -347,7 +374,7 @@ private bool SetupDebugInfo(ref VsDebugTargetInfo dbgInfo, string startupFile) { // add any inherited env vars var variables = Environment.GetEnvironmentVariables(); foreach (var key in variables.Keys) { - string strKey = (string)key; + var strKey = (string)key; if (!env.ContainsKey(strKey)) { env.Add(strKey, (string)variables[key]); } @@ -356,18 +383,15 @@ private bool SetupDebugInfo(ref VsDebugTargetInfo dbgInfo, string startupFile) { //Environment variables should be passed as a //null-terminated block of null-terminated strings. //Each string is in the following form:name=value\0 - StringBuilder buf = new StringBuilder(); + var buf = new StringBuilder(); foreach (var entry in env) { buf.AppendFormat("{0}={1}\0", entry.Key, entry.Value); } buf.Append("\0"); - dbgInfo.bstrEnv = buf.ToString(); + return buf.ToString(); } - // Set the Node debugger - dbgInfo.clsidCustom = AD7Engine.DebugEngineGuid; - dbgInfo.grfLaunch = (uint)__VSDBGLAUNCHFLAGS.DBGLAUNCH_StopDebuggingOnEnd; - return true; + return null; } private bool ShouldStartBrowser() { From 5007396126419b8df2f66aabedcf28f5823f0a01 Mon Sep 17 00:00:00 2001 From: Paul van Brenk Date: Fri, 24 Feb 2017 10:47:29 -0800 Subject: [PATCH 4/9] PR feedback --- .../Product/Nodejs/Debugger/NodeDebugger.cs | 40 +++++++++++++++++-- .../Nodejs/Project/NodejsProjectLauncher.cs | 9 +++-- 2 files changed, 41 insertions(+), 8 deletions(-) diff --git a/Nodejs/Product/Nodejs/Debugger/NodeDebugger.cs b/Nodejs/Product/Nodejs/Debugger/NodeDebugger.cs index 47936f47c..a82a34840 100644 --- a/Nodejs/Product/Nodejs/Debugger/NodeDebugger.cs +++ b/Nodejs/Product/Nodejs/Debugger/NodeDebugger.cs @@ -83,7 +83,15 @@ public NodeDebugger(Uri debuggerEndpointUri, int id) _attached = true; } - public NodeDebugger(string exe, string script, string dir, string env, string interpreterOptions, NodeDebugOptions debugOptions, ushort? debuggerPort = null, bool createNodeWindow = true) + public NodeDebugger( + string exe, + string script, + string dir, + string env, + string interpreterOptions, + NodeDebugOptions debugOptions, + ushort? debuggerPort = null, + bool createNodeWindow = true) : this() { // Select debugger port for a local connection var debuggerPortOrDefault = debuggerPort ?? GetDebuggerPort(); @@ -105,7 +113,15 @@ private static ushort GetDebuggerPort() { return debuggerPortOrDefault; } - public static NodeProcess StartNodeProcessWithDebug(string exe, string script, string dir, string env, string interpreterOptions, NodeDebugOptions debugOptions, ushort? debuggerPort = null, bool createNodeWindow = true) { + public static NodeProcess StartNodeProcessWithDebug( + string exe, + string script, + string dir, + string env, + string interpreterOptions, + NodeDebugOptions debugOptions, + ushort? debuggerPort = null, + bool createNodeWindow = true) { // Select debugger port for a local connection var debuggerPortOrDefault = debuggerPort ?? GetDebuggerPort(); @@ -115,7 +131,15 @@ public static NodeProcess StartNodeProcessWithDebug(string exe, string script, s return StartNodeProcess(exe, dir, env, debugOptions, debuggerPortOrDefault, allArgs, createNodeWindow); } - public static NodeProcess StartNodeProcessWithInspect(string exe, string script, string dir, string env, string interpreterOptions, NodeDebugOptions debugOptions, ushort? debuggerPort = null, bool createNodeWindow = true) { + public static NodeProcess StartNodeProcessWithInspect( + string exe, + string script, + string dir, + string env, + string interpreterOptions, + NodeDebugOptions debugOptions, + ushort? debuggerPort = null, + bool createNodeWindow = true) { // Select debugger port for a local connection var debuggerPortOrDefault = debuggerPort ?? GetDebuggerPort(); @@ -126,7 +150,15 @@ public static NodeProcess StartNodeProcessWithInspect(string exe, string script, } // starts the nodeprocess in debug mode without hooking up our debugger, this way we can attach the WebKit debugger as a next step. - private static NodeProcess StartNodeProcess(string exe, string dir, string env, NodeDebugOptions debugOptions, ushort debuggerPortOrDefault, string allArgs, bool createNodeWindow) { + private static NodeProcess StartNodeProcess( + string exe, + string dir, + string env, + NodeDebugOptions + debugOptions, + ushort debuggerPortOrDefault, + string allArgs, + bool createNodeWindow) { var psi = new ProcessStartInfo(exe, allArgs) { CreateNoWindow = !createNodeWindow, WorkingDirectory = dir, diff --git a/Nodejs/Product/Nodejs/Project/NodejsProjectLauncher.cs b/Nodejs/Product/Nodejs/Project/NodejsProjectLauncher.cs index 56d5ed60c..a33d6f7e2 100644 --- a/Nodejs/Product/Nodejs/Project/NodejsProjectLauncher.cs +++ b/Nodejs/Product/Nodejs/Project/NodejsProjectLauncher.cs @@ -95,7 +95,8 @@ private void StartAndAttachDebugger(string file, string nodePath) { // start the node process var workingDir = _project.GetWorkingDirectory(); - var env = ""; + var url = GetFullUrl(); + var env = GetEnvironmentVariablesString(url); var interpreterOptions = _project.GetProjectProperty(NodeProjectProperty.NodeExeArguments); var debugOptions = this.GetDebugOptions(); @@ -159,11 +160,11 @@ private static IntPtr MarshalDebugEngines(Guid[] debugEngines) { return IntPtr.Zero; } - var guiSize = Marshal.SizeOf(typeof(Guid)); - var size = debugEngines.Length * guiSize; + var guidSize = Marshal.SizeOf(typeof(Guid)); + var size = debugEngines.Length * guidSize; var bytes = new byte[size]; for (var i = 0; i < debugEngines.Length; ++i) { - debugEngines[i].ToByteArray().CopyTo(bytes, i * guiSize); + debugEngines[i].ToByteArray().CopyTo(bytes, i * guidSize); } var pDebugEngines = Marshal.AllocCoTaskMem(size); From 18fd2ef8f4200fdc7d4b81be5682ee1728121506 Mon Sep 17 00:00:00 2001 From: Paul van Brenk Date: Fri, 24 Feb 2017 10:53:56 -0800 Subject: [PATCH 5/9] add new option to all locales --- .../NodejsGeneralOptionsControl.Designer.cs | 24 +- .../NodejsGeneralOptionsControl.cs.resx | 41 ++- .../NodejsGeneralOptionsControl.de.resx | 45 +++- .../NodejsGeneralOptionsControl.en.resx | 244 +++++++++--------- .../NodejsGeneralOptionsControl.es.resx | 87 ++++--- .../NodejsGeneralOptionsControl.fr.resx | 41 ++- .../NodejsGeneralOptionsControl.it.resx | 43 ++- .../NodejsGeneralOptionsControl.ja.resx | 43 ++- .../NodejsGeneralOptionsControl.ko.resx | 43 ++- .../NodejsGeneralOptionsControl.pl.resx | 43 ++- .../NodejsGeneralOptionsControl.pt-BR.resx | 43 ++- .../Options/NodejsGeneralOptionsControl.resx | 41 ++- .../NodejsGeneralOptionsControl.ru.resx | 43 ++- .../NodejsGeneralOptionsControl.tr.resx | 43 ++- .../NodejsGeneralOptionsControl.zh-Hans.resx | 43 ++- .../NodejsGeneralOptionsControl.zh-Hant.resx | 43 ++- 16 files changed, 641 insertions(+), 269 deletions(-) diff --git a/Nodejs/Product/Nodejs/Options/NodejsGeneralOptionsControl.Designer.cs b/Nodejs/Product/Nodejs/Options/NodejsGeneralOptionsControl.Designer.cs index b329f9b78..830624ea1 100644 --- a/Nodejs/Product/Nodejs/Options/NodejsGeneralOptionsControl.Designer.cs +++ b/Nodejs/Product/Nodejs/Options/NodejsGeneralOptionsControl.Designer.cs @@ -29,10 +29,10 @@ private void InitializeComponent() { this._editAndContinue = new System.Windows.Forms.CheckBox(); this._waitOnNormalExit = new System.Windows.Forms.CheckBox(); this._waitOnAbnormalExit = new System.Windows.Forms.CheckBox(); - this._webkitDebugger = new System.Windows.Forms.CheckBox(); this.tableLayoutPanel3 = new System.Windows.Forms.TableLayoutPanel(); - this._surveyNewsCheckCombo = new System.Windows.Forms.ComboBox(); this._surveyNewsCheckLabel = new System.Windows.Forms.Label(); + this._surveyNewsCheckCombo = new System.Windows.Forms.ComboBox(); + this._webkitDebugger = new System.Windows.Forms.CheckBox(); this._topOptionsPanel.SuspendLayout(); this.tableLayoutPanel3.SuspendLayout(); this.SuspendLayout(); @@ -71,12 +71,6 @@ private void InitializeComponent() { this._waitOnAbnormalExit.Name = "_waitOnAbnormalExit"; this._waitOnAbnormalExit.UseVisualStyleBackColor = true; // - // _webkitDebugger - // - resources.ApplyResources(this._webkitDebugger, "_webkitDebugger"); - this._webkitDebugger.Name = "_webkitDebugger"; - this._webkitDebugger.UseVisualStyleBackColor = true; - // // tableLayoutPanel3 // resources.ApplyResources(this.tableLayoutPanel3, "tableLayoutPanel3"); @@ -84,6 +78,11 @@ private void InitializeComponent() { this.tableLayoutPanel3.Controls.Add(this._surveyNewsCheckCombo, 1, 7); this.tableLayoutPanel3.Name = "tableLayoutPanel3"; // + // _surveyNewsCheckLabel + // + resources.ApplyResources(this._surveyNewsCheckLabel, "_surveyNewsCheckLabel"); + this._surveyNewsCheckLabel.Name = "_surveyNewsCheckLabel"; + // // _surveyNewsCheckCombo // resources.ApplyResources(this._surveyNewsCheckCombo, "_surveyNewsCheckCombo"); @@ -97,10 +96,11 @@ private void InitializeComponent() { resources.GetString("_surveyNewsCheckCombo.Items3")}); this._surveyNewsCheckCombo.Name = "_surveyNewsCheckCombo"; // - // _surveyNewsCheckLabel + // _webkitDebugger // - resources.ApplyResources(this._surveyNewsCheckLabel, "_surveyNewsCheckLabel"); - this._surveyNewsCheckLabel.Name = "_surveyNewsCheckLabel"; + resources.ApplyResources(this._webkitDebugger, "_webkitDebugger"); + this._webkitDebugger.Name = "_webkitDebugger"; + this._webkitDebugger.UseVisualStyleBackColor = true; // // NodejsGeneralOptionsControl // @@ -124,9 +124,9 @@ private void InitializeComponent() { private System.Windows.Forms.CheckBox _waitOnAbnormalExit; private System.Windows.Forms.CheckBox _editAndContinue; private System.Windows.Forms.CheckBox _checkForLongPaths; - private System.Windows.Forms.CheckBox _webkitDebugger; private System.Windows.Forms.TableLayoutPanel tableLayoutPanel3; private System.Windows.Forms.Label _surveyNewsCheckLabel; private System.Windows.Forms.ComboBox _surveyNewsCheckCombo; + private System.Windows.Forms.CheckBox _webkitDebugger; } } diff --git a/Nodejs/Product/Nodejs/Options/NodejsGeneralOptionsControl.cs.resx b/Nodejs/Product/Nodejs/Options/NodejsGeneralOptionsControl.cs.resx index 53571274f..edd97a0b1 100644 --- a/Nodejs/Product/Nodejs/Options/NodejsGeneralOptionsControl.cs.resx +++ b/Nodejs/Product/Nodejs/Options/NodejsGeneralOptionsControl.cs.resx @@ -208,7 +208,7 @@ Fill - 0, 97 + 0, 120 3, 4, 3, 4 @@ -217,7 +217,7 @@ 9 - 381, 193 + 381, 170 0 @@ -237,6 +237,33 @@ <?xml version="1.0" encoding="utf-16"?><TableLayoutSettings><Controls><Control Name="_surveyNewsCheckLabel" Row="7" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="_surveyNewsCheckCombo" Row="7" RowSpan="1" Column="1" ColumnSpan="1" /></Controls><Columns Styles="AutoSize,0,Percent,100" /><Rows Styles="AutoSize,0,AutoSize,0,AutoSize,0,AutoSize,0,AutoSize,0,AutoSize,0,AutoSize,0,AutoSize,0,Absolute,20" /></TableLayoutSettings> + + True + + + 4, 96 + + + 96, 17 + + + 5 + + + Use the new NodeJs debugger protocol (experimental since v6.8) + + + _webkitDebugger + + + System.Windows.Forms.CheckBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + _topOptionsPanel + + + 0 + True @@ -262,7 +289,7 @@ _topOptionsPanel - 0 + 1 True @@ -289,7 +316,7 @@ _topOptionsPanel - 1 + 2 True @@ -316,7 +343,7 @@ _topOptionsPanel - 2 + 3 True @@ -343,7 +370,7 @@ _topOptionsPanel - 3 + 4 Top @@ -352,7 +379,7 @@ 0, 0 - 381, 97 + 381, 120 1 diff --git a/Nodejs/Product/Nodejs/Options/NodejsGeneralOptionsControl.de.resx b/Nodejs/Product/Nodejs/Options/NodejsGeneralOptionsControl.de.resx index ab3d538b1..37e5e6f42 100644 --- a/Nodejs/Product/Nodejs/Options/NodejsGeneralOptionsControl.de.resx +++ b/Nodejs/Product/Nodejs/Options/NodejsGeneralOptionsControl.de.resx @@ -1,4 +1,4 @@ - + - - + + - + - - - - + + + + - - + + - - + + - - - - + + + + - + - + @@ -117,11 +117,11 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - + True - + GrowAndShrink @@ -134,7 +134,7 @@ True - + 6, 7 @@ -208,7 +208,7 @@ Fill - 0, 97 + 0, 120 3, 4, 3, 4 @@ -217,7 +217,7 @@ 9 - 381, 193 + 381, 170 0 @@ -235,7 +235,34 @@ 0 - <?xml version="1.0" encoding="utf-16"?><TableLayoutSettings><Controls><Control Name="_surveyNewsCheckLabel" Row="7" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="_surveyNewsCheckCombo" Row="7" RowSpan="1" Column="1" ColumnSpan="1" /></Controls><Columns Styles="AutoSize,0,Percent,100" /><Rows Styles="AutoSize,0,AutoSize,0,AutoSize,0,AutoSize,0,AutoSize,0,AutoSize,0,AutoSize,0,AutoSize,0,Absolute,20" /></TableLayoutSettings> + <?xml version="1.0" encoding="utf-16"?><TableLayoutSettings><Controls><Control Name="_surveyNewsCheckLabel" Row="7" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="_surveyNewsCheckCombo" Row="7" RowSpan="1" Column="1" ColumnSpan="1" /></Controls><Columns Styles="AutoSize,0,Percent,100" /><Rows Styles="AutoSize,0,AutoSize,0,AutoSize,0,AutoSize,0,AutoSize,0,AutoSize,0,AutoSize,0,AutoSize,0,Absolute,20" /></TableLayoutSettings> + + + True + + + 4, 96 + + + 96, 17 + + + 5 + + + Use the new NodeJs debugger protocol (experimental since v6.8) + + + _webkitDebugger + + + System.Windows.Forms.CheckBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + _topOptionsPanel + + + 0 True @@ -262,7 +289,7 @@ _topOptionsPanel - 0 + 1 True @@ -289,7 +316,7 @@ _topOptionsPanel - 1 + 2 True @@ -316,7 +343,7 @@ _topOptionsPanel - 2 + 3 True @@ -343,7 +370,7 @@ _topOptionsPanel - 3 + 4 Top @@ -352,7 +379,7 @@ 0, 0 - 381, 97 + 381, 120 1 @@ -387,4 +414,4 @@ System.Windows.Forms.UserControl, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - + \ No newline at end of file diff --git a/Nodejs/Product/Nodejs/Options/NodejsGeneralOptionsControl.fr.resx b/Nodejs/Product/Nodejs/Options/NodejsGeneralOptionsControl.fr.resx index bf774d993..eebfd7f5f 100644 --- a/Nodejs/Product/Nodejs/Options/NodejsGeneralOptionsControl.fr.resx +++ b/Nodejs/Product/Nodejs/Options/NodejsGeneralOptionsControl.fr.resx @@ -1,4 +1,4 @@ - + - - + + - + - - - - + + + + - - + + - - + + - - - - + + + + - + - + @@ -117,11 +117,11 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - + True - + GrowAndShrink @@ -134,7 +134,7 @@ True - + 6, 7 @@ -235,7 +235,7 @@ 0 - <?xml version="1.0" encoding="utf-16"?><TableLayoutSettings><Controls><Control Name="_surveyNewsCheckLabel" Row="7" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="_surveyNewsCheckCombo" Row="7" RowSpan="1" Column="1" ColumnSpan="1" /></Controls><Columns Styles="AutoSize,0,Percent,100" /><Rows Styles="AutoSize,0,AutoSize,0,AutoSize,0,AutoSize,0,AutoSize,0,AutoSize,0,AutoSize,0,AutoSize,0,Absolute,20" /></TableLayoutSettings> + <?xml version="1.0" encoding="utf-16"?><TableLayoutSettings><Controls><Control Name="_surveyNewsCheckLabel" Row="7" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="_surveyNewsCheckCombo" Row="7" RowSpan="1" Column="1" ColumnSpan="1" /></Controls><Columns Styles="AutoSize,0,Percent,100" /><Rows Styles="AutoSize,0,AutoSize,0,AutoSize,0,AutoSize,0,AutoSize,0,AutoSize,0,AutoSize,0,AutoSize,0,Absolute,20" /></TableLayoutSettings> True @@ -414,4 +414,4 @@ System.Windows.Forms.UserControl, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - \ No newline at end of file + From ecc16d5dd87e26df6187b784cf0ce86232060c3d Mon Sep 17 00:00:00 2001 From: Paul van Brenk Date: Fri, 24 Feb 2017 14:18:46 -0800 Subject: [PATCH 7/9] PR feedback and fix build break --- Common/Product/SharedProject/CommonUtils.cs | 8 +++++++- Common/Product/SharedProject/ProjectNode.cs | 4 ---- Nodejs/Product/Nodejs/Project/NodejsProjectLauncher.cs | 2 +- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/Common/Product/SharedProject/CommonUtils.cs b/Common/Product/SharedProject/CommonUtils.cs index 997a6b791..2af4cdbde 100644 --- a/Common/Product/SharedProject/CommonUtils.cs +++ b/Common/Product/SharedProject/CommonUtils.cs @@ -46,7 +46,6 @@ internal static Uri MakeUri(string path, bool isDirectory, UriKind kind, string } return new Uri(path, kind); - } catch (UriFormatException ex) { throw new ArgumentException("Path was invalid", throwParameterName, ex); } catch (ArgumentException ex) { @@ -62,6 +61,13 @@ public static string NormalizePath(string path) { return null; } + const string MdhaPrefix = "mdha:"; + + // webkit debugger prepends with 'mdha' + if (path.StartsWith(MdhaPrefix, StringComparison.OrdinalIgnoreCase)) { + path = path.Substring(MdhaPrefix.Length); + } + var uri = MakeUri(path, false, UriKind.RelativeOrAbsolute); if (uri.IsAbsoluteUri) { if (uri.IsFile) { diff --git a/Common/Product/SharedProject/ProjectNode.cs b/Common/Product/SharedProject/ProjectNode.cs index bb5baa52e..fa5addc06 100644 --- a/Common/Product/SharedProject/ProjectNode.cs +++ b/Common/Product/SharedProject/ProjectNode.cs @@ -5596,10 +5596,6 @@ public virtual int GetBuildSystemKind(out uint kind) { internal HierarchyNode FindNodeByFullPath(string name) { Site.GetUIThread().MustBeCalledFromUIThread(); - if (name.StartsWith("mdha:", StringComparison.OrdinalIgnoreCase)) { - return default(HierarchyNode); - } - Debug.Assert(Path.IsPathRooted(name)); HierarchyNode node; diff --git a/Nodejs/Product/Nodejs/Project/NodejsProjectLauncher.cs b/Nodejs/Product/Nodejs/Project/NodejsProjectLauncher.cs index a33d6f7e2..79b62a336 100644 --- a/Nodejs/Product/Nodejs/Project/NodejsProjectLauncher.cs +++ b/Nodejs/Product/Nodejs/Project/NodejsProjectLauncher.cs @@ -247,7 +247,7 @@ private string GetFullUrl() { } } - private static string GetFullUrl(string host, int port) { + internal static string GetFullUrl(string host, int port) { UriBuilder builder; Uri uri; if (Uri.TryCreate(host, UriKind.Absolute, out uri)) { From 8aaa4124d919f1a202cc0f5b94e1682a89458bd9 Mon Sep 17 00:00:00 2001 From: Paul van Brenk Date: Fri, 24 Feb 2017 14:45:27 -0800 Subject: [PATCH 8/9] Fix build break --- Nodejs/Product/Nodejs/Debugger/NodeDebugger.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Nodejs/Product/Nodejs/Debugger/NodeDebugger.cs b/Nodejs/Product/Nodejs/Debugger/NodeDebugger.cs index a82a34840..33c7c38a0 100644 --- a/Nodejs/Product/Nodejs/Debugger/NodeDebugger.cs +++ b/Nodejs/Product/Nodejs/Debugger/NodeDebugger.cs @@ -882,6 +882,10 @@ private IEnumerable GetLocalFrames(IEnumerable s return backtraceCommand.Running; } + internal IList GetThreads() { + return _threads.Values.ToList(); + } + internal void SendStepOver(int identity) { DebugWriteCommand("StepOver"); DebuggerClient.RunWithRequestExceptionsHandled(async () => { From 3fb4c47c26bb2428387c8917d4ba8e9dfeab75b0 Mon Sep 17 00:00:00 2001 From: Paul van Brenk Date: Tue, 28 Feb 2017 16:57:05 -0800 Subject: [PATCH 9/9] Make sure scripts are properly quoted when sending to the debugger. --- Common/Product/SharedProject/CommonProjectNode.cs | 2 +- Nodejs/Product/Nodejs/Debugger/NodeDebugger.cs | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Common/Product/SharedProject/CommonProjectNode.cs b/Common/Product/SharedProject/CommonProjectNode.cs index facb6260e..3ffbed354 100644 --- a/Common/Product/SharedProject/CommonProjectNode.cs +++ b/Common/Product/SharedProject/CommonProjectNode.cs @@ -1549,7 +1549,7 @@ protected override ConfigProvider CreateConfigProvider() { /// Returns resolved value of the current working directory property. /// public string GetWorkingDirectory() { - string workDir = CommonUtils.UnquotePath(GetProjectProperty(CommonConstants.WorkingDirectory, resetCache: false)); + var workDir = CommonUtils.UnquotePath(GetProjectProperty(CommonConstants.WorkingDirectory, resetCache: false)); return CommonUtils.GetAbsoluteDirectoryPath(ProjectHome, workDir); } diff --git a/Nodejs/Product/Nodejs/Debugger/NodeDebugger.cs b/Nodejs/Product/Nodejs/Debugger/NodeDebugger.cs index 33c7c38a0..c98c680e4 100644 --- a/Nodejs/Product/Nodejs/Debugger/NodeDebugger.cs +++ b/Nodejs/Product/Nodejs/Debugger/NodeDebugger.cs @@ -126,7 +126,7 @@ public static NodeProcess StartNodeProcessWithDebug( var debuggerPortOrDefault = debuggerPort ?? GetDebuggerPort(); // Node usage: node [options] [ -e script | script.js ] [arguments] - var allArgs = $"--debug-brk={debuggerPortOrDefault} --nolazy {interpreterOptions} \"{script}\""; + var allArgs = $"--debug-brk={debuggerPortOrDefault} --nolazy {interpreterOptions} \"{CommonUtils.UnquotePath(script)}\""; /* unquote the path so we can safely add quotes */ return StartNodeProcess(exe, dir, env, debugOptions, debuggerPortOrDefault, allArgs, createNodeWindow); } @@ -144,7 +144,7 @@ public static NodeProcess StartNodeProcessWithInspect( var debuggerPortOrDefault = debuggerPort ?? GetDebuggerPort(); // Node usage: node [options] [ -e script | script.js ] [arguments] - string allArgs = $"--inspect={debuggerPortOrDefault} --debug-brk --nolazy {interpreterOptions} \"{script}\""; + var allArgs = $"--inspect={debuggerPortOrDefault} --debug-brk --nolazy {interpreterOptions} \"{CommonUtils.UnquotePath(script)}\""; /* unquote the path so we can safely add quotes */ return StartNodeProcess(exe, dir, env, debugOptions, debuggerPortOrDefault, allArgs, createNodeWindow); } @@ -169,7 +169,7 @@ private static NodeProcess StartNodeProcess( var envValues = env.Split('\0'); foreach (var curValue in envValues) { var nameValue = curValue.Split(new[] { '=' }, 2); - if (nameValue.Length == 2 && !String.IsNullOrWhiteSpace(nameValue[0])) { + if (nameValue.Length == 2 && !string.IsNullOrWhiteSpace(nameValue[0])) { psi.EnvironmentVariables[nameValue[0]] = nameValue[1]; } }