Skip to content

Commit 9e98781

Browse files
authored
Merge pull request #1913 from paulvanbrenk/anyCodeFixes
Any code fixes
2 parents 8f9948a + 4488ed1 commit 9e98781

File tree

6 files changed

+73
-93
lines changed

6 files changed

+73
-93
lines changed

Common/Product/SharedProject/ProcessOutput.cs

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -162,13 +162,19 @@ public static ProcessOutput Run(
162162
QuoteSingleArgument(filename),
163163
GetArguments(arguments, quoteArgs)),
164164
CreateNoWindow = !visible,
165-
UseShellExecute = false,
166-
RedirectStandardError = !visible || (redirector != null),
167-
RedirectStandardOutput = !visible || (redirector != null),
168-
RedirectStandardInput = !visible
165+
UseShellExecute = false
169166
};
170-
psi.StandardOutputEncoding = outputEncoding ?? psi.StandardOutputEncoding;
171-
psi.StandardErrorEncoding = errorEncoding ?? outputEncoding ?? psi.StandardErrorEncoding;
167+
168+
if (!visible || (redirector != null))
169+
{
170+
psi.RedirectStandardError = true;
171+
psi.RedirectStandardOutput = true;
172+
psi.RedirectStandardInput = true;
173+
// only set the encoding when we're redirecting the output
174+
psi.StandardOutputEncoding = outputEncoding ?? psi.StandardOutputEncoding;
175+
psi.StandardErrorEncoding = errorEncoding ?? outputEncoding ?? psi.StandardErrorEncoding;
176+
}
177+
172178
if (env != null)
173179
{
174180
foreach (var kv in env)

Nodejs/Product/Nodejs/SharedProject/OutputWindowWrapper.cs

Lines changed: 23 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -17,95 +17,57 @@ public sealed class OutputPaneWrapper
1717

1818
// This is the package manager pane that ships with VS2015, and we should print there if available.
1919
private static readonly Guid VSPackageManagerPaneGuid = new Guid("C7E31C31-1451-4E05-B6BE-D11B6829E8BB");
20-
2120
private static readonly Guid TscPaneGuid = new Guid("7CCFA622-001E-4459-9D8B-5B60BE0A18C2");
2221

2322
[Import]
2423
private SVsServiceProvider ServiceProvider { get; set; }
2524

2625
private Dictionary<OutputWindowTarget, IVsOutputWindowPane> lazyOutputPaneCollection = new Dictionary<OutputWindowTarget, IVsOutputWindowPane>();
27-
private IVsWindowFrame lazyOutputWindow;
2826

29-
private IVsOutputWindowPane GetOutputPane(OutputWindowTarget target)
27+
private IVsOutputWindowPane InitializeOutputPane(string title, Guid paneId)
3028
{
31-
if (this.lazyOutputPaneCollection.TryGetValue(target, out var lazyOutputPane))
32-
{
33-
return lazyOutputPane;
34-
}
35-
else
36-
{
37-
ThreadHelper.ThrowIfNotOnUIThread();
38-
var (title, guid) = GetPaneInfo(target);
39-
var outputWindow = (IVsOutputWindow)this.ServiceProvider.GetService(typeof(SVsOutputWindow));
40-
41-
// Try to get the workspace pane if it has already been registered
42-
var hr = outputWindow.GetPane(guid, out lazyOutputPane);
43-
44-
// If the workspace pane has not been registered before, create it
45-
if (lazyOutputPane == null || ErrorHandler.Failed(hr))
46-
{
47-
48-
if (ErrorHandler.Failed(outputWindow.CreatePane(guid, title, fInitVisible: 1, fClearWithSolution: 1)) ||
49-
ErrorHandler.Failed(outputWindow.GetPane(guid, out lazyOutputPane)))
50-
{
51-
return null;
52-
}
53-
54-
// Must activate the workspace pane for it to show up in the output window
55-
lazyOutputPane.Activate();
56-
}
29+
ThreadHelper.ThrowIfNotOnUIThread();
30+
var outputWindow = (IVsOutputWindow)this.ServiceProvider.GetService(typeof(SVsOutputWindow));
5731

58-
this.lazyOutputPaneCollection.Add(target, lazyOutputPane);
59-
return lazyOutputPane;
60-
}
32+
// Try to get the workspace pane if it has already been registered
33+
var hr = outputWindow.GetPane(paneId, out var lazyOutputPane);
6134

62-
(string title, Guid guid) GetPaneInfo(OutputWindowTarget pane)
35+
// If the workspace pane has not been registered before, create it
36+
if (lazyOutputPane == null || ErrorHandler.Failed(hr))
6337
{
64-
switch (pane)
65-
{
66-
case OutputWindowTarget.Npm:
67-
return ("Npm", VSPackageManagerPaneGuid);
68-
case OutputWindowTarget.Tsc:
69-
return ("Tsc", TscPaneGuid); /* no need to localize since name of exe */
70-
default:
71-
throw new ArgumentOutOfRangeException(nameof(pane));
72-
}
73-
}
74-
}
7538

76-
private IVsWindowFrame OutputWindow
77-
{
78-
get
79-
{
80-
if (this.lazyOutputWindow == null && this.ServiceProvider.GetService(typeof(SVsUIShell)) is IVsUIShell shell)
39+
if (ErrorHandler.Failed(outputWindow.CreatePane(paneId, title, fInitVisible: 1, fClearWithSolution: 1)) ||
40+
ErrorHandler.Failed(outputWindow.GetPane(paneId, out lazyOutputPane)))
8141
{
82-
ThreadHelper.ThrowIfNotOnUIThread();
83-
84-
var windowGuid = OutputWindowGuid;
85-
var hr = shell.FindToolWindow((int)__VSFINDTOOLWIN.FTW_fForceCreate, ref windowGuid, out this.lazyOutputWindow);
86-
Debug.Assert(ErrorHandler.Succeeded(hr));
42+
return null;
8743
}
8844

89-
return this.lazyOutputWindow;
45+
// Must activate the workspace pane for it to show up in the output window
46+
lazyOutputPane.Activate();
9047
}
48+
49+
return lazyOutputPane;
9150
}
9251

9352
public void WriteLine(string message, OutputWindowTarget target = OutputWindowTarget.Npm)
9453
{
95-
if (this.lazyOutputWindow == null)
54+
if (!this.lazyOutputPaneCollection.TryGetValue(target, out var lazyOutputPane) || lazyOutputPane == null)
9655
{
97-
throw new InvalidOperationException($"Ensure the output window is initialized by calling '{nameof(ShowWindow)}' first.");
56+
throw new InvalidOperationException("You need to initialize the output panes before using them.");
9857
}
9958

100-
var hr = this.GetOutputPane(target).OutputStringThreadSafe(message + Environment.NewLine);
59+
var hr = lazyOutputPane.OutputStringThreadSafe(message + Environment.NewLine);
10160
Debug.Assert(ErrorHandler.Succeeded(hr));
10261
}
10362

104-
public void ShowWindow()
63+
public void InitializeOutputPanes()
10564
{
10665
ThreadHelper.ThrowIfNotOnUIThread();
107-
var hr = this.OutputWindow?.ShowNoActivate() ?? VSConstants.E_FAIL;
108-
Debug.Assert(ErrorHandler.Succeeded(hr));
66+
67+
var npmPane = InitializeOutputPane("Npm", VSPackageManagerPaneGuid);
68+
this.lazyOutputPaneCollection.Add(OutputWindowTarget.Npm, npmPane);
69+
var tscPane = InitializeOutputPane("Tsc", TscPaneGuid);
70+
this.lazyOutputPaneCollection.Add(OutputWindowTarget.Tsc, tscPane);
10971
}
11072
}
11173

Nodejs/Product/Nodejs/Workspace/ContextMenuProvider.cs

Lines changed: 27 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using System.Collections.Generic;
55
using System.ComponentModel.Composition;
66
using System.Diagnostics;
7+
using System.IO;
78
using System.Linq;
89
using System.Threading;
910
using Microsoft.NodejsTools.Npm;
@@ -75,26 +76,28 @@ public int Exec(List<WorkspaceVisualNodeBase> selection, Guid pguidCmdGroup, uin
7576

7677
if (pguidCmdGroup == Guids.NodeToolsWorkspaceCmdSet)
7778
{
78-
this.outputPane.ShowWindow();
79+
this.outputPane.InitializeOutputPanes();
80+
81+
var fileNode = ((IFileNode)node).FullPath;
7982

8083
switch (nCmdID)
8184
{
8285
case PkgCmdId.cmdidWorkSpaceNpmInstallMissing:
83-
ExecNpmInstallMissing(node);
86+
ExecNpmInstallMissing(fileNode);
8487
return VSConstants.S_OK;
8588

8689
case PkgCmdId.cmdidWorkSpaceNpmInstallNew:
87-
ExecNpmInstallNew(node);
90+
ExecNpmInstallNew(fileNode);
8891
return VSConstants.S_OK;
8992

9093
case PkgCmdId.cmdidWorkSpaceNpmUpdate:
91-
ExecNpmUpdate(node);
94+
ExecNpmUpdate(fileNode);
9295
return VSConstants.S_OK;
9396
}
9497

9598
if (nCmdID >= PkgCmdId.cmdidWorkSpaceNpmDynamicScript && nCmdID < PkgCmdId.cmdidWorkSpaceNpmDynamicScriptMax)
9699
{
97-
ExecDynamic(node, nCmdID);
100+
ExecDynamic(fileNode, nCmdID);
98101
return VSConstants.S_OK;
99102
}
100103
}
@@ -116,44 +119,42 @@ public int Exec(List<WorkspaceVisualNodeBase> selection, Guid pguidCmdGroup, uin
116119
// Note: all the Exec commands are async, this allows us to call them in a fire and forget
117120
// pattern, without blocking the UI or losing any logging
118121

119-
private async void ExecNpmInstallMissing(WorkspaceVisualNodeBase node)
122+
private async void ExecNpmInstallMissing(string filePath)
120123
{
121-
using (var npmController = this.CreateController(node.Workspace))
124+
using (var npmController = this.CreateController(filePath))
122125
using (var commander = npmController.CreateNpmCommander())
123126
{
124127
await commander.Install();
125128
}
126129
}
127130

128-
private void ExecNpmInstallNew(WorkspaceVisualNodeBase node)
131+
private void ExecNpmInstallNew(string filePath)
129132
{
130-
using (var npmController = this.CreateController(node.Workspace))
133+
using (var npmController = this.CreateController(filePath))
131134
using (var npmWorker = new NpmWorker(npmController))
132135
using (var manager = new NpmPackageInstallWindow(npmController, npmWorker))
133136
{
134137
manager.ShowModal();
135138
}
136139
}
137140

138-
private async void ExecNpmUpdate(WorkspaceVisualNodeBase node)
141+
private async void ExecNpmUpdate(string filePath)
139142
{
140-
using (var npmController = this.CreateController(node.Workspace))
143+
using (var npmController = this.CreateController(filePath))
141144
using (var commander = npmController.CreateNpmCommander())
142145
{
143146
await commander.UpdatePackagesAsync();
144147
}
145148
}
146149

147-
private async void ExecDynamic(WorkspaceVisualNodeBase node, uint nCmdID)
150+
private async void ExecDynamic(string filePath, uint nCmdID)
148151
{
149152
// Unfortunately the NpmController (and NpmCommander), used for the install and update commands
150153
// doesn't support running arbitrary scripts. And changing that is outside
151154
// the scope of these changes.
152-
var filePath = ((IFileNode)node).FullPath;
153155
if (TryGetCommand(nCmdID, filePath, out var commandName))
154156
{
155-
156-
using (var npmController = this.CreateController(node.Workspace))
157+
using (var npmController = this.CreateController(filePath))
157158
using (var commander = npmController.CreateNpmCommander())
158159
{
159160
await commander.ExecuteNpmCommandAsync($"run-script {commandName}", showConsole: true);
@@ -166,8 +167,13 @@ private async void ExecDebugAsync(WorkspaceVisualNodeBase node)
166167
var workspace = node.Workspace;
167168
var packageJson = PackageJsonFactory.Create(((IFileNode)node).FullPath);
168169

170+
if (string.IsNullOrEmpty(packageJson.Main))
171+
{
172+
return;
173+
}
174+
169175
//invoke debuglaunchtargetprovider on this file
170-
var fileContextActions = await node.Workspace.GetFileContextActionsAsync(packageJson.Main, new[] { DebugLaunchActionContext.ContextTypeGuid });
176+
var fileContextActions = await workspace.GetFileContextActionsAsync(packageJson.Main, new[] { DebugLaunchActionContext.ContextTypeGuid });
171177
if (fileContextActions.Any())
172178
{
173179
// we requested a single context, so there should be a single grouping. Use the First action, since they're ordered by priority.
@@ -265,9 +271,12 @@ private static bool TryGetCommand(uint nCmdID, string filePath, out string comma
265271
return false;
266272
}
267273

268-
private INpmController CreateController(IWorkspace workspace)
274+
private INpmController CreateController(string packageJsonPath)
269275
{
270-
var projectHome = workspace.Location;
276+
Debug.Assert(Path.IsPathRooted(packageJsonPath));
277+
Debug.Assert(PackageJsonFactory.IsPackageJsonFile(packageJsonPath));
278+
279+
var projectHome = Path.GetDirectoryName(packageJsonPath);
271280

272281
var npmController = NpmControllerFactory.Create(
273282
projectHome,

Nodejs/Product/Nodejs/Workspace/PackageJsonScannerFactory.cs

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -43,13 +43,16 @@ protected override Task<List<FileReferenceInfo>> ComputeFileReferencesAsync(stri
4343

4444
var packageJson = PackageJsonFactory.Create(filePath);
4545
var main = packageJson.Main;
46-
var fileReferences = new List<FileReferenceInfo>
46+
47+
var fileReferences = new List<FileReferenceInfo>();
48+
49+
if (!string.IsNullOrEmpty(main))
4750
{
48-
new FileReferenceInfo(main,
49-
context: "Debug",
50-
target: main,
51-
referenceType: (int)FileReferenceInfoType.Output)
52-
};
51+
fileReferences.Add(new FileReferenceInfo(main,
52+
context: "Debug",
53+
target: main,
54+
referenceType: (int)FileReferenceInfoType.Output));
55+
}
5356

5457
return Task.FromResult(fileReferences);
5558
}

Nodejs/Product/Nodejs/Workspace/TypeScriptActionProviderFactory.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ public async Task<IReadOnlyList<IFileContextAction>> GetActionsAsync(string file
6060
{
6161
await this.workspaceContext.JTF.SwitchToMainThreadAsync();
6262

63-
this.outputPane.ShowWindow();
63+
this.outputPane.InitializeOutputPanes();
6464

6565
var actions = new List<IFileContextAction>();
6666

Nodejs/Product/Npm/SPI/NpmCommand.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ await NpmHelpers.ExecuteNpmCommandAsync(
106106
cancelled = true;
107107
}
108108
OnCommandCompleted(this.Arguments, redirector?.HasErrors ?? false, cancelled);
109-
return !redirector.HasErrors;
109+
return redirector?.HasErrors != true; // return true when the command completed without errors, or redirector is null (which means we can't track)
110110
}
111111

112112
private sealed class NpmCommandRedirector : Redirector

0 commit comments

Comments
 (0)