Skip to content

Commit

Permalink
Merge pull request #9531 from Erarndt/dev/erarndt/languageServiceThre…
Browse files Browse the repository at this point in the history
…adSwitch

Avoid repeated switches to main thread to check if in command line mode
  • Loading branch information
drewnoakes authored Sep 6, 2024
2 parents be5d271 + d43d49d commit 8d5a9b8
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 47 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,6 @@ public LanguageServiceHost(
_isEnabled = new(
async () =>
{
await threadingService.JoinableTaskFactory.SwitchToMainThreadAsync();
// If VS is running in command line mode (e.g. "devenv.exe /build my.sln"),
// language services should not be enabled. The one exception to this is
// when we're populating a solution cache via "/populateSolutionCache".
Expand Down
Original file line number Diff line number Diff line change
@@ -1,75 +1,58 @@
// Licensed to the .NET Foundation under one or more agreements. The .NET Foundation licenses this file to you under the MIT license. See the LICENSE.md file in the project root for more information.

using Microsoft.VisualStudio.ProjectSystem;
using Microsoft.VisualStudio.ProjectSystem.VS;
using Microsoft.VisualStudio.ProjectSystem.VS.Interop;
using Microsoft.VisualStudio.Shell.Interop;
using Microsoft.VisualStudio.Threading;

namespace Microsoft.VisualStudio.Shell;

[Export(typeof(IVsShellServices))]
[AppliesTo(ProjectCapabilities.AlwaysApplicable)]
internal class VSShellServices : IVsShellServices
{

private readonly AsyncLazy<(bool IsCommandLineMode, bool IsPopulateSolutionCacheMode)> _initialization;
private readonly Task<bool> _isCommandLine;
private readonly Task<bool> _isPopulateCache;

[ImportingConstructor]
public VSShellServices(
IVsUIService<SVsShell, IVsShell> vsShellService,
IVsUIService<SVsAppCommandLine, IVsAppCommandLine> commandLineService,
JoinableTaskContext joinableTaskContext)
IVsService<IVsAppId> vsAppId,
IVsService<SVsAppCommandLine, IVsAppCommandLine> commandLine)
{
_initialization = new(
async () =>
{
// Initialisation must occur on the main thread.
await joinableTaskContext.Factory.SwitchToMainThreadAsync();
IVsShell? vsShell = vsShellService.Value;
IVsAppCommandLine? commandLine = commandLineService.Value;
bool isCommandLineMode = IsCommandLineMode();
_isCommandLine = IsCommandLineModeAsync(vsAppId);
_isPopulateCache = IsPopulateSolutionCacheModeAsync(commandLine);

if (isCommandLineMode)
{
return (IsCommandLineMode: true, IsPopulateSolutionCacheMode());
}
return (false, false);
bool IsCommandLineMode()
{
Assumes.Present(vsShell);
int hr = vsShell.GetProperty((int)__VSSPROPID.VSSPROPID_IsInCommandLineMode, out object result);
static async Task<bool> IsCommandLineModeAsync(IVsService<IVsAppId> vsAppIdService)
{
IVsAppId? vsAppId = await vsAppIdService.GetValueOrNullAsync();
if (vsAppId is not null)
{
const int VSAPROPID_IsInCommandLineMode = (int)Microsoft.Internal.VisualStudio.AppId.Interop.__VSAPROPID10.VSAPROPID_IsInCommandLineMode;
return ErrorHandler.Succeeded(vsAppId.GetProperty(VSAPROPID_IsInCommandLineMode, out object o)) && o is true;
}

return ErrorHandler.Succeeded(hr)
&& result is bool isCommandLineMode
&& isCommandLineMode;
}
return false;
}

bool IsPopulateSolutionCacheMode()
{
if (commandLine is null)
return false;
static async Task<bool> IsPopulateSolutionCacheModeAsync(IVsService<SVsAppCommandLine, IVsAppCommandLine> commandLineService)
{
IVsAppCommandLine? commandLine = await commandLineService.GetValueOrNullAsync();
if (commandLine is null)
return false;

int hr = commandLine.GetOption("populateSolutionCache", out int populateSolutionCache, out string commandValue);
int hr = commandLine.GetOption("populateSolutionCache", out int populateSolutionCache, out string _);

return ErrorHandler.Succeeded(hr)
&& Convert.ToBoolean(populateSolutionCache);
}
},
joinableTaskContext.Factory);
return ErrorHandler.Succeeded(hr)
&& Convert.ToBoolean(populateSolutionCache);
}
}

public async Task<bool> IsCommandLineModeAsync(CancellationToken cancellationToken)
{
return (await _initialization.GetValueAsync(cancellationToken)).IsCommandLineMode;
return await _isCommandLine;
}

public async Task<bool> IsPopulateSolutionCacheModeAsync(CancellationToken cancellationToken)
{
return (await _initialization.GetValueAsync(cancellationToken)).IsPopulateSolutionCacheMode;
return await _isPopulateCache;
}
}

0 comments on commit 8d5a9b8

Please sign in to comment.