未验证 提交 46954a82 编写于 作者: D David 提交者: GitHub

Merge pull request #40320 from dibarbet/ilanguageclient_pr

Begin migration to ILanguageClient for liveshare
......@@ -47,7 +47,7 @@ public CommandState GetCommandState(TCommandArgs args)
var findUsagesService = document?.GetLanguageService<TLanguageService>();
return findUsagesService != null
? CommandState.Available
: CommandState.Unavailable;
: CommandState.Unspecified;
}
public bool ExecuteCommand(TCommandArgs args, CommandExecutionContext context)
......
......@@ -46,7 +46,7 @@ public CommandState GetCommandState(FindReferencesCommandArgs args)
var (_, service) = GetDocumentAndService(args.SubjectBuffer.CurrentSnapshot);
return service != null
? CommandState.Available
: CommandState.Unavailable;
: CommandState.Unspecified;
}
public bool ExecuteCommand(FindReferencesCommandArgs args, CommandExecutionContext context)
......
......@@ -37,7 +37,7 @@ public CommandState GetCommandState(GoToDefinitionCommandArgs args)
var (_, service) = GetDocumentAndService(args.SubjectBuffer.CurrentSnapshot);
return service != null
? CommandState.Available
: CommandState.Unavailable;
: CommandState.Unspecified;
}
public bool ExecuteCommand(GoToDefinitionCommandArgs args, CommandExecutionContext context)
......
......@@ -12,5 +12,8 @@ internal static class ContentTypeNames
public const string XamlContentType = "XAML";
public const string JavaScriptContentTypeName = "JavaScript";
public const string TypeScriptContentTypeName = "TypeScript";
public const string CSharpLspContentTypeName = "C#_LSP";
public const string VBLspContentTypeName = "VB_LSP";
}
}
......@@ -26,13 +26,12 @@ public CodeActionsHandler(ICodeFixService codeFixService, ICodeRefactoringServic
}
public async Task<object[]> HandleRequestAsync(Solution solution, LSP.CodeActionParams request,
LSP.ClientCapabilities clientCapabilities, CancellationToken cancellationToken, bool keepThreadContext = false)
LSP.ClientCapabilities clientCapabilities, CancellationToken cancellationToken)
{
var codeActions = await GetCodeActionsAsync(solution,
request.TextDocument.Uri,
request.Range,
keepThreadContext,
cancellationToken).ConfigureAwait(keepThreadContext);
request.TextDocument.Uri,
request.Range,
cancellationToken).ConfigureAwait(false);
// Filter out code actions with options since they'll show dialogs and we can't remote the UI and the options.
codeActions = codeActions.Where(c => !(c is CodeActionWithOptions));
......
......@@ -26,7 +26,7 @@ public CodeActionsHandlerBase(ICodeFixService codeFixService, ICodeRefactoringSe
_codeRefactoringService = codeRefactoringService ?? throw new ArgumentNullException(nameof(codeRefactoringService));
}
public async Task<IEnumerable<CodeAction>> GetCodeActionsAsync(Solution solution, Uri documentUri, LSP.Range selection, bool keepThreadContext, CancellationToken cancellationToken)
public async Task<IEnumerable<CodeAction>> GetCodeActionsAsync(Solution solution, Uri documentUri, LSP.Range selection, CancellationToken cancellationToken)
{
var document = solution.GetDocumentFromURI(documentUri);
if (document == null)
......@@ -34,11 +34,11 @@ public async Task<IEnumerable<CodeAction>> GetCodeActionsAsync(Solution solution
return ImmutableArray<CodeAction>.Empty;
}
var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(keepThreadContext);
var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false);
var textSpan = ProtocolConversions.RangeToTextSpan(selection, text);
var codeFixCollections = await _codeFixService.GetFixesAsync(document, textSpan, true, cancellationToken).ConfigureAwait(keepThreadContext);
var codeRefactorings = await _codeRefactoringService.GetRefactoringsAsync(document, textSpan, cancellationToken).ConfigureAwait(keepThreadContext);
var codeFixCollections = await _codeFixService.GetFixesAsync(document, textSpan, true, cancellationToken).ConfigureAwait(false);
var codeRefactorings = await _codeRefactoringService.GetRefactoringsAsync(document, textSpan, cancellationToken).ConfigureAwait(false);
var codeActions = codeFixCollections.SelectMany(c => c.Fixes.Select(f => f.Action)).Concat(
codeRefactorings.SelectMany(r => r.CodeActions.Select(ca => ca.action)));
......
......@@ -24,20 +24,19 @@ public RunCodeActionsHandler(ICodeFixService codeFixService, ICodeRefactoringSer
}
public async Task<object> HandleRequestAsync(Solution solution, LSP.ExecuteCommandParams request, LSP.ClientCapabilities clientCapabilities,
CancellationToken cancellationToken, bool keepThreadContext = false)
CancellationToken cancellationToken)
{
var runRequest = ((JToken)request.Arguments.Single()).ToObject<RunCodeActionParams>();
var codeActions = await GetCodeActionsAsync(solution,
runRequest.CodeActionParams.TextDocument.Uri,
runRequest.CodeActionParams.Range,
keepThreadContext,
cancellationToken).ConfigureAwait(keepThreadContext);
runRequest.CodeActionParams.TextDocument.Uri,
runRequest.CodeActionParams.Range,
cancellationToken).ConfigureAwait(false);
var actionToRun = codeActions?.FirstOrDefault(a => a.Title == runRequest.Title);
if (actionToRun != null)
{
foreach (var operation in await actionToRun.GetOperationsAsync(cancellationToken).ConfigureAwait(keepThreadContext))
foreach (var operation in await actionToRun.GetOperationsAsync(cancellationToken).ConfigureAwait(false))
{
operation.Apply(solution.Workspace, cancellationToken);
}
......
......@@ -40,7 +40,7 @@ public ExecuteWorkspaceCommandHandler([ImportMany] IEnumerable<Lazy<IExecuteWork
/// by delegating to a handler for the specific command requested.
/// </summary>
public Task<object> HandleRequestAsync(Solution solution, LSP.ExecuteCommandParams request, LSP.ClientCapabilities clientCapabilities,
CancellationToken cancellationToken, bool keepThreadContext = false)
CancellationToken cancellationToken)
{
var commandName = request.Command;
if (string.IsNullOrEmpty(commandName) || !_executeCommandHandlers.TryGetValue(commandName, out var executeCommandHandler))
......@@ -48,7 +48,7 @@ public ExecuteWorkspaceCommandHandler([ImportMany] IEnumerable<Lazy<IExecuteWork
throw new ArgumentException(string.Format("Command name ({0}) is invalid", commandName));
}
return executeCommandHandler.Value.HandleRequestAsync(solution, request, clientCapabilities, cancellationToken, keepThreadContext);
return executeCommandHandler.Value.HandleRequestAsync(solution, request, clientCapabilities, cancellationToken);
}
}
}
......@@ -11,6 +11,6 @@ internal interface IExecuteWorkspaceCommandHandler
/// <summary>
/// Handles a specific command from a <see cref="Methods.WorkspaceExecuteCommandName"/> request.
/// </summary>
Task<object> HandleRequestAsync(Solution solution, ExecuteCommandParams request, ClientCapabilities clientCapabilities, CancellationToken cancellationToken, bool keepThreadContext = false);
Task<object> HandleRequestAsync(Solution solution, ExecuteCommandParams request, ClientCapabilities clientCapabilities, CancellationToken cancellationToken);
}
}
......@@ -22,7 +22,7 @@ namespace Microsoft.CodeAnalysis.LanguageServer.Handler
internal class CompletionHandler : IRequestHandler<LSP.CompletionParams, object>
{
public async Task<object> HandleRequestAsync(Solution solution, LSP.CompletionParams request, LSP.ClientCapabilities clientCapabilities,
CancellationToken cancellationToken, bool keepThreadContext = false)
CancellationToken cancellationToken)
{
var document = solution.GetDocumentFromURI(request.TextDocument.Uri);
if (document == null)
......@@ -30,10 +30,10 @@ internal class CompletionHandler : IRequestHandler<LSP.CompletionParams, object>
return Array.Empty<LSP.CompletionItem>();
}
var position = await document.GetPositionFromLinePositionAsync(ProtocolConversions.PositionToLinePosition(request.Position), cancellationToken).ConfigureAwait(keepThreadContext);
var position = await document.GetPositionFromLinePositionAsync(ProtocolConversions.PositionToLinePosition(request.Position), cancellationToken).ConfigureAwait(false);
var completionService = document.Project.LanguageServices.GetService<CompletionService>();
var list = await completionService.GetCompletionsAsync(document, position, cancellationToken: cancellationToken).ConfigureAwait(keepThreadContext);
var list = await completionService.GetCompletionsAsync(document, position, cancellationToken: cancellationToken).ConfigureAwait(false);
if (list == null)
{
return Array.Empty<LSP.CompletionItem>();
......
......@@ -20,7 +20,7 @@ namespace Microsoft.CodeAnalysis.LanguageServer.Handler
internal class CompletionResolveHandler : IRequestHandler<LSP.CompletionItem, LSP.CompletionItem>
{
public async Task<LSP.CompletionItem> HandleRequestAsync(Solution solution, LSP.CompletionItem completionItem,
LSP.ClientCapabilities clientCapabilities, CancellationToken cancellationToken, bool keepThreadContext)
LSP.ClientCapabilities clientCapabilities, CancellationToken cancellationToken)
{
CompletionResolveData data;
if (completionItem.Data is CompletionResolveData)
......@@ -40,10 +40,10 @@ internal class CompletionResolveHandler : IRequestHandler<LSP.CompletionItem, LS
return completionItem;
}
var position = await document.GetPositionFromLinePositionAsync(ProtocolConversions.PositionToLinePosition(request.Position), cancellationToken).ConfigureAwait(keepThreadContext);
var position = await document.GetPositionFromLinePositionAsync(ProtocolConversions.PositionToLinePosition(request.Position), cancellationToken).ConfigureAwait(false);
var completionService = document.Project.LanguageServices.GetService<CompletionService>();
var list = await completionService.GetCompletionsAsync(document, position, cancellationToken: cancellationToken).ConfigureAwait(keepThreadContext);
var list = await completionService.GetCompletionsAsync(document, position, cancellationToken: cancellationToken).ConfigureAwait(false);
if (list == null)
{
return completionItem;
......@@ -55,7 +55,7 @@ internal class CompletionResolveHandler : IRequestHandler<LSP.CompletionItem, LS
return completionItem;
}
var description = await completionService.GetDescriptionAsync(document, selectedItem, cancellationToken).ConfigureAwait(keepThreadContext);
var description = await completionService.GetDescriptionAsync(document, selectedItem, cancellationToken).ConfigureAwait(false);
var lspVSClientCapability = clientCapabilities?.HasVisualStudioLspCapability() == true;
LSP.CompletionItem resolvedCompletionItem;
......
......@@ -18,9 +18,9 @@ public GoToDefinitionHandler(IMetadataAsSourceFileService metadataAsSourceFileSe
}
public async Task<object> HandleRequestAsync(Solution solution, LSP.TextDocumentPositionParams request,
LSP.ClientCapabilities clientCapabilities, CancellationToken cancellationToken, bool keepThreadContext = false)
LSP.ClientCapabilities clientCapabilities, CancellationToken cancellationToken)
{
return await GetDefinitionAsync(solution, request, typeOnly: false, keepThreadContext, cancellationToken).ConfigureAwait(keepThreadContext);
return await GetDefinitionAsync(solution, request, typeOnly: false, cancellationToken: cancellationToken).ConfigureAwait(false);
}
}
}
......@@ -21,7 +21,7 @@ public GoToDefinitionHandlerBase(IMetadataAsSourceFileService metadataAsSourceFi
_metadataAsSourceFileService = metadataAsSourceFileService;
}
protected async Task<LSP.Location[]> GetDefinitionAsync(Solution solution, LSP.TextDocumentPositionParams request, bool typeOnly, bool keepThreadContext, CancellationToken cancellationToken)
protected async Task<LSP.Location[]> GetDefinitionAsync(Solution solution, LSP.TextDocumentPositionParams request, bool typeOnly, CancellationToken cancellationToken)
{
var locations = ArrayBuilder<LSP.Location>.GetInstance();
......@@ -31,10 +31,10 @@ protected async Task<LSP.Location[]> GetDefinitionAsync(Solution solution, LSP.T
return locations.ToArrayAndFree();
}
var position = await document.GetPositionFromLinePositionAsync(ProtocolConversions.PositionToLinePosition(request.Position), cancellationToken).ConfigureAwait(keepThreadContext);
var position = await document.GetPositionFromLinePositionAsync(ProtocolConversions.PositionToLinePosition(request.Position), cancellationToken).ConfigureAwait(false);
var definitionService = document.Project.LanguageServices.GetService<IGoToDefinitionService>();
var definitions = await definitionService.FindDefinitionsAsync(document, position, cancellationToken).ConfigureAwait(keepThreadContext);
var definitions = await definitionService.FindDefinitionsAsync(document, position, cancellationToken).ConfigureAwait(false);
if (definitions != null && definitions.Count() > 0)
{
foreach (var definition in definitions)
......@@ -44,7 +44,7 @@ protected async Task<LSP.Location[]> GetDefinitionAsync(Solution solution, LSP.T
continue;
}
var definitionText = await definition.Document.GetTextAsync(cancellationToken).ConfigureAwait(keepThreadContext);
var definitionText = await definition.Document.GetTextAsync(cancellationToken).ConfigureAwait(false);
locations.Add(new LSP.Location
{
Uri = definition.Document.GetURI(),
......@@ -55,12 +55,12 @@ protected async Task<LSP.Location[]> GetDefinitionAsync(Solution solution, LSP.T
else if (document.SupportsSemanticModel && _metadataAsSourceFileService != null)
{
// No definition found - see if we can get metadata as source but that's only applicable for C#\VB.
var symbol = await SymbolFinder.FindSymbolAtPositionAsync(document, position, cancellationToken).ConfigureAwait(keepThreadContext);
var symbol = await SymbolFinder.FindSymbolAtPositionAsync(document, position, cancellationToken).ConfigureAwait(false);
if (symbol != null && symbol.Locations != null && !symbol.Locations.IsEmpty && symbol.Locations.First().IsInMetadata)
{
if (!typeOnly || symbol is ITypeSymbol)
{
var declarationFile = await _metadataAsSourceFileService.GetGeneratedFileAsync(document.Project, symbol, false, cancellationToken).ConfigureAwait(keepThreadContext);
var declarationFile = await _metadataAsSourceFileService.GetGeneratedFileAsync(document.Project, symbol, false, cancellationToken).ConfigureAwait(false);
var linePosSpan = declarationFile.IdentifierLocation.GetLineSpan().Span;
locations.Add(new LSP.Location
......
......@@ -18,9 +18,9 @@ public GoToTypeDefinitionHandler(IMetadataAsSourceFileService metadataAsSourceFi
}
public async Task<LSP.Location[]> HandleRequestAsync(Solution solution, LSP.TextDocumentPositionParams request,
LSP.ClientCapabilities clientCapabilities, CancellationToken cancellationToken, bool keepThreadContext)
LSP.ClientCapabilities clientCapabilities, CancellationToken cancellationToken)
{
return await GetDefinitionAsync(solution, request, typeOnly: true, keepThreadContext, cancellationToken).ConfigureAwait(keepThreadContext);
return await GetDefinitionAsync(solution, request, typeOnly: true, cancellationToken: cancellationToken).ConfigureAwait(false);
}
}
}
......@@ -14,7 +14,7 @@ namespace Microsoft.CodeAnalysis.LanguageServer.Handler
internal class FoldingRangesHandler : IRequestHandler<FoldingRangeParams, FoldingRange[]>
{
public async Task<FoldingRange[]> HandleRequestAsync(Solution solution, FoldingRangeParams request,
ClientCapabilities clientCapabilities, CancellationToken cancellationToken, bool keepThreadContext = false)
ClientCapabilities clientCapabilities, CancellationToken cancellationToken)
{
var foldingRanges = ArrayBuilder<FoldingRange>.GetInstance();
......@@ -30,13 +30,13 @@ internal class FoldingRangesHandler : IRequestHandler<FoldingRangeParams, Foldin
return foldingRanges.ToArrayAndFree();
}
var blockStructure = await blockStructureService.GetBlockStructureAsync(document, cancellationToken).ConfigureAwait(keepThreadContext);
var blockStructure = await blockStructureService.GetBlockStructureAsync(document, cancellationToken).ConfigureAwait(false);
if (blockStructure == null)
{
return foldingRanges.ToArrayAndFree();
}
var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(keepThreadContext);
var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false);
foreach (var span in blockStructure.Spans)
{
......
......@@ -12,9 +12,9 @@ namespace Microsoft.CodeAnalysis.LanguageServer.Handler
internal class FormatDocumentHandler : FormatDocumentHandlerBase, IRequestHandler<LSP.DocumentFormattingParams, LSP.TextEdit[]>
{
public async Task<LSP.TextEdit[]> HandleRequestAsync(Solution solution, LSP.DocumentFormattingParams request, LSP.ClientCapabilities clientCapabilities,
CancellationToken cancellationToken, bool keepThreadContext = false)
CancellationToken cancellationToken)
{
return await GetTextEdits(solution, request.TextDocument.Uri, keepThreadContext, cancellationToken).ConfigureAwait(keepThreadContext);
return await GetTextEdits(solution, request.TextDocument.Uri, cancellationToken).ConfigureAwait(false);
}
}
}
......@@ -15,7 +15,7 @@ namespace Microsoft.CodeAnalysis.LanguageServer.Handler
{
internal class FormatDocumentHandlerBase
{
protected async Task<LSP.TextEdit[]> GetTextEdits(Solution solution, Uri documentUri, bool keepThreadContext, CancellationToken cancellationToken, LSP.Range range = null)
protected async Task<LSP.TextEdit[]> GetTextEdits(Solution solution, Uri documentUri, CancellationToken cancellationToken, LSP.Range range = null)
{
var edits = new ArrayBuilder<LSP.TextEdit>();
var document = solution.GetDocumentFromURI(documentUri);
......@@ -23,14 +23,14 @@ protected async Task<LSP.TextEdit[]> GetTextEdits(Solution solution, Uri documen
if (document != null)
{
var formattingService = document.Project.LanguageServices.GetService<IEditorFormattingService>();
var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(keepThreadContext);
var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false);
TextSpan? textSpan = null;
if (range != null)
{
textSpan = ProtocolConversions.RangeToTextSpan(range, text);
}
var textChanges = await formattingService.GetFormattingChangesAsync(document, textSpan, cancellationToken).ConfigureAwait(keepThreadContext);
var textChanges = await formattingService.GetFormattingChangesAsync(document, textSpan, cancellationToken).ConfigureAwait(false);
edits.AddRange(textChanges.Select(change => ProtocolConversions.TextChangeToTextEdit(change, text)));
}
......
......@@ -18,14 +18,14 @@ namespace Microsoft.CodeAnalysis.LanguageServer.Handler
internal class FormatDocumentOnTypeHandler : IRequestHandler<DocumentOnTypeFormattingParams, TextEdit[]>
{
public async Task<TextEdit[]> HandleRequestAsync(Solution solution, DocumentOnTypeFormattingParams request, ClientCapabilities clientCapabilities,
CancellationToken cancellationToken, bool keepThreadContext = false)
CancellationToken cancellationToken)
{
var edits = new ArrayBuilder<TextEdit>();
var document = solution.GetDocumentFromURI(request.TextDocument.Uri);
if (document != null)
{
var formattingService = document.Project.LanguageServices.GetService<IEditorFormattingService>();
var position = await document.GetPositionFromLinePositionAsync(ProtocolConversions.PositionToLinePosition(request.Position), cancellationToken).ConfigureAwait(keepThreadContext);
var position = await document.GetPositionFromLinePositionAsync(ProtocolConversions.PositionToLinePosition(request.Position), cancellationToken).ConfigureAwait(false);
if (string.IsNullOrEmpty(request.Character))
{
......@@ -35,14 +35,14 @@ internal class FormatDocumentOnTypeHandler : IRequestHandler<DocumentOnTypeForma
IList<TextChange> textChanges;
if (SyntaxFacts.IsNewLine(request.Character[0]))
{
textChanges = await formattingService.GetFormattingChangesOnReturnAsync(document, position, cancellationToken).ConfigureAwait(keepThreadContext);
textChanges = await formattingService.GetFormattingChangesOnReturnAsync(document, position, cancellationToken).ConfigureAwait(false);
}
else
{
textChanges = await formattingService.GetFormattingChangesAsync(document, request.Character[0], position, cancellationToken).ConfigureAwait(keepThreadContext);
textChanges = await formattingService.GetFormattingChangesAsync(document, request.Character[0], position, cancellationToken).ConfigureAwait(false);
}
var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(keepThreadContext);
var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false);
if (textChanges != null)
{
edits.AddRange(textChanges.Select(change => ProtocolConversions.TextChangeToTextEdit(change, text)));
......
......@@ -12,9 +12,9 @@ namespace Microsoft.CodeAnalysis.LanguageServer.Handler
internal class FormatDocumentRangeHandler : FormatDocumentHandlerBase, IRequestHandler<DocumentRangeFormattingParams, TextEdit[]>
{
public async Task<TextEdit[]> HandleRequestAsync(Solution solution, DocumentRangeFormattingParams request, ClientCapabilities clientCapabilities,
CancellationToken cancellationToken, bool keepThreadContext = false)
CancellationToken cancellationToken)
{
return await GetTextEdits(solution, request.TextDocument.Uri, keepThreadContext, cancellationToken, range: request.Range).ConfigureAwait(keepThreadContext);
return await GetTextEdits(solution, request.TextDocument.Uri, cancellationToken, range: request.Range).ConfigureAwait(false);
}
}
}
......@@ -16,7 +16,7 @@ namespace Microsoft.CodeAnalysis.LanguageServer.Handler
internal class DocumentHighlightsHandler : IRequestHandler<TextDocumentPositionParams, DocumentHighlight[]>
{
public async Task<DocumentHighlight[]> HandleRequestAsync(Solution solution, TextDocumentPositionParams request,
ClientCapabilities clientCapabilities, CancellationToken cancellationToken, bool keepThreadContext)
ClientCapabilities clientCapabilities, CancellationToken cancellationToken)
{
var document = solution.GetDocumentFromURI(request.TextDocument.Uri);
if (document == null)
......@@ -25,19 +25,19 @@ internal class DocumentHighlightsHandler : IRequestHandler<TextDocumentPositionP
}
var documentHighlightService = document.Project.LanguageServices.GetService<IDocumentHighlightsService>();
var position = await document.GetPositionFromLinePositionAsync(ProtocolConversions.PositionToLinePosition(request.Position), cancellationToken).ConfigureAwait(keepThreadContext);
var position = await document.GetPositionFromLinePositionAsync(ProtocolConversions.PositionToLinePosition(request.Position), cancellationToken).ConfigureAwait(false);
var highlights = await documentHighlightService.GetDocumentHighlightsAsync(
document,
position,
ImmutableHashSet.Create(document),
cancellationToken).ConfigureAwait(keepThreadContext);
cancellationToken).ConfigureAwait(false);
if (!highlights.IsDefaultOrEmpty)
{
// LSP requests are only for a single document. So just get the highlights for the requested document.
var highlightsForDocument = highlights.FirstOrDefault(h => h.Document.Id == document.Id);
var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(keepThreadContext);
var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false);
return highlightsForDocument.HighlightSpans.Select(h => new DocumentHighlight
{
......
......@@ -15,7 +15,7 @@ namespace Microsoft.CodeAnalysis.LanguageServer.Handler
internal class HoverHandler : IRequestHandler<TextDocumentPositionParams, Hover>
{
public async Task<Hover> HandleRequestAsync(Solution solution, TextDocumentPositionParams request,
ClientCapabilities clientCapabilities, CancellationToken cancellationToken, bool keepThreadContext = false)
ClientCapabilities clientCapabilities, CancellationToken cancellationToken)
{
var document = solution.GetDocumentFromURI(request.TextDocument.Uri);
if (document == null)
......@@ -23,16 +23,16 @@ internal class HoverHandler : IRequestHandler<TextDocumentPositionParams, Hover>
return null;
}
var position = await document.GetPositionFromLinePositionAsync(ProtocolConversions.PositionToLinePosition(request.Position), cancellationToken).ConfigureAwait(keepThreadContext);
var position = await document.GetPositionFromLinePositionAsync(ProtocolConversions.PositionToLinePosition(request.Position), cancellationToken).ConfigureAwait(false);
var quickInfoService = document.Project.LanguageServices.GetService<QuickInfoService>();
var info = await quickInfoService.GetQuickInfoAsync(document, position, cancellationToken).ConfigureAwait(keepThreadContext);
var info = await quickInfoService.GetQuickInfoAsync(document, position, cancellationToken).ConfigureAwait(false);
if (info == null)
{
return null;
}
var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(keepThreadContext);
var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false);
return new Hover
{
Range = ProtocolConversions.TextSpanToRange(info.Span, text),
......
......@@ -22,8 +22,7 @@ internal interface IRequestHandler<RequestType, ResponseType> : IRequestHandler
/// <param name="request">the lsp request.</param>
/// <param name="clientCapabilities">the client capabilities for the request.</param>
/// <param name="cancellationToken">a cancellation token.</param>
/// <param name="keepThreadContext">a value to set if the threading context in the handler should be kept from the caller.</param>
/// <returns>the lps response.</returns>
Task<ResponseType> HandleRequestAsync(Solution solution, RequestType request, ClientCapabilities clientCapabilities, CancellationToken cancellationToken, bool keepThreadContext = false);
/// <returns>the LSP response.</returns>
Task<ResponseType> HandleRequestAsync(Solution solution, RequestType request, ClientCapabilities clientCapabilities, CancellationToken cancellationToken);
}
}
......@@ -16,24 +16,20 @@ internal class InitializeHandler : IRequestHandler<InitializeParams, InitializeR
Capabilities = new ServerCapabilities
{
DefinitionProvider = true,
ReferencesProvider = true,
ImplementationProvider = true,
CompletionProvider = new CompletionOptions { ResolveProvider = true, TriggerCharacters = new[] { "." } },
HoverProvider = true,
SignatureHelpProvider = new SignatureHelpOptions { TriggerCharacters = new[] { "(", "," } },
CodeActionProvider = true,
DocumentSymbolProvider = true,
WorkspaceSymbolProvider = true,
DocumentFormattingProvider = true,
DocumentRangeFormattingProvider = true,
DocumentOnTypeFormattingProvider = new DocumentOnTypeFormattingOptions { FirstTriggerCharacter = "}", MoreTriggerCharacter = new[] { ";", "\n" } },
DocumentHighlightProvider = true,
RenameProvider = true,
ExecuteCommandProvider = new ExecuteCommandOptions()
}
};
public Task<InitializeResult> HandleRequestAsync(Solution solution, InitializeParams request, ClientCapabilities clientCapabilities, CancellationToken cancellationToken, bool keepThreadContext = false)
public Task<InitializeResult> HandleRequestAsync(Solution solution, InitializeParams request, ClientCapabilities clientCapabilities, CancellationToken cancellationToken)
=> Task.FromResult(s_initializeResult);
}
}
......@@ -15,7 +15,7 @@ namespace Microsoft.CodeAnalysis.LanguageServer.Handler
internal class FindImplementationsHandler : IRequestHandler<LSP.TextDocumentPositionParams, object>
{
public async Task<object> HandleRequestAsync(Solution solution, LSP.TextDocumentPositionParams request,
LSP.ClientCapabilities clientCapabilities, CancellationToken cancellationToken, bool keepThreadContext = false)
LSP.ClientCapabilities clientCapabilities, CancellationToken cancellationToken)
{
var locations = ArrayBuilder<LSP.Location>.GetInstance();
......@@ -26,11 +26,11 @@ internal class FindImplementationsHandler : IRequestHandler<LSP.TextDocumentPosi
}
var findUsagesService = document.Project.LanguageServices.GetService<IFindUsagesService>();
var position = await document.GetPositionFromLinePositionAsync(ProtocolConversions.PositionToLinePosition(request.Position), cancellationToken).ConfigureAwait(keepThreadContext);
var position = await document.GetPositionFromLinePositionAsync(ProtocolConversions.PositionToLinePosition(request.Position), cancellationToken).ConfigureAwait(false);
var context = new SimpleFindUsagesContext(cancellationToken);
await findUsagesService.FindImplementationsAsync(document, position, context).ConfigureAwait(keepThreadContext);
await findUsagesService.FindImplementationsAsync(document, position, context).ConfigureAwait(false);
foreach (var definition in context.GetDefinitions())
{
......@@ -39,11 +39,11 @@ internal class FindImplementationsHandler : IRequestHandler<LSP.TextDocumentPosi
{
if (clientCapabilities?.HasVisualStudioLspCapability() == true)
{
locations.Add(await ProtocolConversions.DocumentSpanToLocationWithTextAsync(sourceSpan, text, cancellationToken).ConfigureAwait(keepThreadContext));
locations.Add(await ProtocolConversions.DocumentSpanToLocationWithTextAsync(sourceSpan, text, cancellationToken).ConfigureAwait(false));
}
else
{
locations.Add(await ProtocolConversions.DocumentSpanToLocationAsync(sourceSpan, cancellationToken).ConfigureAwait(keepThreadContext));
locations.Add(await ProtocolConversions.DocumentSpanToLocationAsync(sourceSpan, cancellationToken).ConfigureAwait(false));
}
}
}
......
......@@ -28,7 +28,7 @@ public SignatureHelpHandler([ImportMany] IEnumerable<Lazy<ISignatureHelpProvider
}
public async Task<LSP.SignatureHelp> HandleRequestAsync(Solution solution, LSP.TextDocumentPositionParams request,
LSP.ClientCapabilities clientCapabilities, CancellationToken cancellationToken, bool keepThreadContext = false)
LSP.ClientCapabilities clientCapabilities, CancellationToken cancellationToken)
{
var document = solution.GetDocumentFromURI(request.TextDocument.Uri);
if (document == null)
......@@ -36,14 +36,14 @@ public SignatureHelpHandler([ImportMany] IEnumerable<Lazy<ISignatureHelpProvider
return new LSP.SignatureHelp();
}
var position = await document.GetPositionFromLinePositionAsync(ProtocolConversions.PositionToLinePosition(request.Position), cancellationToken).ConfigureAwait(keepThreadContext);
var position = await document.GetPositionFromLinePositionAsync(ProtocolConversions.PositionToLinePosition(request.Position), cancellationToken).ConfigureAwait(false);
var providers = _allProviders.Where(p => p.Metadata.Language == document.Project.Language);
var triggerInfo = new SignatureHelpTriggerInfo(SignatureHelpTriggerReason.InvokeSignatureHelpCommand);
foreach (var provider in providers)
{
var items = await provider.Value.GetItemsAsync(document, position, triggerInfo, cancellationToken).ConfigureAwait(keepThreadContext);
var items = await provider.Value.GetItemsAsync(document, position, triggerInfo, cancellationToken).ConfigureAwait(false);
if (items != null)
{
......
......@@ -21,7 +21,7 @@ namespace Microsoft.CodeAnalysis.LanguageServer.Handler
internal class DocumentSymbolsHandler : IRequestHandler<DocumentSymbolParams, object[]>
{
public async Task<object[]> HandleRequestAsync(Solution solution, DocumentSymbolParams request,
ClientCapabilities clientCapabilities, CancellationToken cancellationToken, bool keepThreadContext = false)
ClientCapabilities clientCapabilities, CancellationToken cancellationToken)
{
var document = solution.GetDocumentFromURI(request.TextDocument.Uri);
if (document == null)
......@@ -32,15 +32,15 @@ internal class DocumentSymbolsHandler : IRequestHandler<DocumentSymbolParams, ob
var symbols = ArrayBuilder<object>.GetInstance();
var navBarService = document.Project.LanguageServices.GetService<INavigationBarItemService>();
var navBarItems = await navBarService.GetItemsAsync(document, cancellationToken).ConfigureAwait(keepThreadContext);
var navBarItems = await navBarService.GetItemsAsync(document, cancellationToken).ConfigureAwait(false);
if (navBarItems.Count == 0)
{
return symbols.ToArrayAndFree();
}
var compilation = await document.Project.GetCompilationAsync(cancellationToken).ConfigureAwait(keepThreadContext);
var tree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(keepThreadContext);
var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(keepThreadContext);
var compilation = await document.Project.GetCompilationAsync(cancellationToken).ConfigureAwait(false);
var tree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false);
var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false);
// TODO - Return more than 2 levels of symbols.
// https://github.com/dotnet/roslyn/projects/45#card-20033869
......@@ -49,7 +49,7 @@ internal class DocumentSymbolsHandler : IRequestHandler<DocumentSymbolParams, ob
foreach (var item in navBarItems)
{
// only top level ones
symbols.Add(await GetDocumentSymbolAsync(item, compilation, tree, text, keepThreadContext, cancellationToken).ConfigureAwait(keepThreadContext));
symbols.Add(await GetDocumentSymbolAsync(item, compilation, tree, text, cancellationToken).ConfigureAwait(false));
}
}
else
......@@ -110,7 +110,7 @@ static SymbolInformation Create(NavigationBarItem item, TextSpan span, string co
/// Get a document symbol from a specified nav bar item.
/// </summary>
private static async Task<DocumentSymbol> GetDocumentSymbolAsync(NavigationBarItem item, Compilation compilation, SyntaxTree tree,
SourceText text, bool keepThreadContext, CancellationToken cancellationToken)
SourceText text, CancellationToken cancellationToken)
{
// it is actually symbol location getter. but anyway.
var location = GetLocation(item, compilation, tree, cancellationToken);
......@@ -119,7 +119,7 @@ static SymbolInformation Create(NavigationBarItem item, TextSpan span, string co
return null;
}
var symbol = await GetSymbolAsync(location, compilation, keepThreadContext, cancellationToken).ConfigureAwait(keepThreadContext);
var symbol = await GetSymbolAsync(location, compilation, cancellationToken).ConfigureAwait(false);
if (symbol == null)
{
return null;
......@@ -133,25 +133,25 @@ static SymbolInformation Create(NavigationBarItem item, TextSpan span, string co
Deprecated = symbol.GetAttributes().Any(x => x.AttributeClass.MetadataName == "ObsoleteAttribute"),
Range = ProtocolConversions.TextSpanToRange(item.Spans.First(), text),
SelectionRange = ProtocolConversions.TextSpanToRange(location.SourceSpan, text),
Children = await GetChildrenAsync(item.ChildItems, compilation, tree, text, keepThreadContext, cancellationToken).ConfigureAwait(keepThreadContext),
Children = await GetChildrenAsync(item.ChildItems, compilation, tree, text, cancellationToken).ConfigureAwait(false),
};
static async Task<DocumentSymbol[]> GetChildrenAsync(IEnumerable<NavigationBarItem> items, Compilation compilation, SyntaxTree tree,
SourceText text, bool keepThreadContext, CancellationToken cancellationToken)
SourceText text, CancellationToken cancellationToken)
{
var list = new ArrayBuilder<DocumentSymbol>();
foreach (var item in items)
{
list.Add(await GetDocumentSymbolAsync(item, compilation, tree, text, keepThreadContext, cancellationToken).ConfigureAwait(keepThreadContext));
list.Add(await GetDocumentSymbolAsync(item, compilation, tree, text, cancellationToken).ConfigureAwait(false));
}
return list.ToArrayAndFree();
}
static async Task<ISymbol> GetSymbolAsync(Location location, Compilation compilation, bool keepThreadContext, CancellationToken cancellationToken)
static async Task<ISymbol> GetSymbolAsync(Location location, Compilation compilation, CancellationToken cancellationToken)
{
var model = compilation.GetSemanticModel(location.SourceTree);
var root = await model.SyntaxTree.GetRootAsync(cancellationToken).ConfigureAwait(keepThreadContext);
var root = await model.SyntaxTree.GetRootAsync(cancellationToken).ConfigureAwait(false);
var node = root.FindNode(location.SourceSpan);
while (node != null)
......
......@@ -15,13 +15,13 @@ namespace Microsoft.CodeAnalysis.LanguageServer.Handler
internal class WorkspaceSymbolsHandler : IRequestHandler<WorkspaceSymbolParams, SymbolInformation[]>
{
public async Task<SymbolInformation[]> HandleRequestAsync(Solution solution, WorkspaceSymbolParams request,
ClientCapabilities clientCapabilities, CancellationToken cancellationToken, bool keepThreadContext = false)
ClientCapabilities clientCapabilities, CancellationToken cancellationToken)
{
var searchTasks = Task.WhenAll(solution.Projects.Select(project => SearchProjectAsync(project, request, keepThreadContext, cancellationToken)));
return (await searchTasks.ConfigureAwait(keepThreadContext)).SelectMany(s => s).ToArray();
var searchTasks = Task.WhenAll(solution.Projects.Select(project => SearchProjectAsync(project, request, cancellationToken)));
return (await searchTasks.ConfigureAwait(false)).SelectMany(s => s).ToArray();
// local functions
static async Task<ImmutableArray<SymbolInformation>> SearchProjectAsync(Project project, WorkspaceSymbolParams request, bool keepThreadContext, CancellationToken cancellationToken)
static async Task<ImmutableArray<SymbolInformation>> SearchProjectAsync(Project project, WorkspaceSymbolParams request, CancellationToken cancellationToken)
{
var searchService = project.LanguageServices.GetService<INavigateToSearchService_RemoveInterfaceAboveAndRenameThisAfterInternalsVisibleToUsersUpdate>();
if (searchService != null)
......@@ -33,20 +33,20 @@ static async Task<ImmutableArray<SymbolInformation>> SearchProjectAsync(Project
ImmutableArray<Document>.Empty,
request.Query,
searchService.KindsProvided,
cancellationToken).ConfigureAwait(keepThreadContext);
var projectSymbolsTasks = Task.WhenAll(items.Select(item => CreateSymbolInformation(item, keepThreadContext, cancellationToken)));
return (await projectSymbolsTasks.ConfigureAwait(keepThreadContext)).ToImmutableArray();
cancellationToken).ConfigureAwait(false);
var projectSymbolsTasks = Task.WhenAll(items.Select(item => CreateSymbolInformation(item, cancellationToken)));
return (await projectSymbolsTasks.ConfigureAwait(false)).ToImmutableArray();
}
return ImmutableArray.Create<SymbolInformation>();
static async Task<SymbolInformation> CreateSymbolInformation(INavigateToSearchResult result, bool keepThreadContext, CancellationToken cancellationToken)
static async Task<SymbolInformation> CreateSymbolInformation(INavigateToSearchResult result, CancellationToken cancellationToken)
{
return new SymbolInformation
{
Name = result.Name,
Kind = ProtocolConversions.NavigateToKindToSymbolKind(result.Kind),
Location = await ProtocolConversions.TextSpanToLocationAsync(result.NavigableItem.Document, result.NavigableItem.SourceSpan, cancellationToken).ConfigureAwait(keepThreadContext),
Location = await ProtocolConversions.TextSpanToLocationAsync(result.NavigableItem.Document, result.NavigableItem.SourceSpan, cancellationToken).ConfigureAwait(false),
};
}
}
......
......@@ -29,6 +29,7 @@
<ItemGroup>
<InternalsVisibleTo Include="Microsoft.CodeAnalysis.LanguageServer.Protocol.UnitTests" />
<InternalsVisibleTo Include="Microsoft.VisualStudio.LanguageServices" />
<InternalsVisibleTo Include="Microsoft.VisualStudio.LanguageServices.LiveShare" />
<InternalsVisibleTo Include="Microsoft.VisualStudio.LanguageServices.LiveShare.UnitTests" />
<InternalsVisibleTo Include="Microsoft.CodeAnalysis.Remote.ServiceHub" />
......
......@@ -25,16 +25,13 @@ private static async Task<LSP.InitializeResult> RunInitializeAsync(Solution solu
private static void AssertServerCapabilities(LSP.ServerCapabilities actual)
{
Assert.True(actual.DefinitionProvider);
Assert.True(actual.ReferencesProvider);
Assert.True(actual.ImplementationProvider);
Assert.True(actual.HoverProvider);
Assert.True(actual.CodeActionProvider);
Assert.True(actual.DocumentSymbolProvider);
Assert.True(actual.WorkspaceSymbolProvider);
Assert.True(actual.DocumentFormattingProvider);
Assert.True(actual.DocumentRangeFormattingProvider);
Assert.True(actual.DocumentHighlightProvider);
Assert.True(actual.RenameProvider);
Assert.True(actual.CompletionProvider.ResolveProvider);
Assert.Equal(new[] { "." }, actual.CompletionProvider.TriggerCharacters);
......@@ -43,8 +40,6 @@ private static void AssertServerCapabilities(LSP.ServerCapabilities actual)
Assert.Equal("}", actual.DocumentOnTypeFormattingProvider.FirstTriggerCharacter);
Assert.Equal(new[] { ";", "\n" }, actual.DocumentOnTypeFormattingProvider.MoreTriggerCharacter);
Assert.NotNull(actual.ExecuteCommandProvider);
}
}
}
......@@ -17,6 +17,7 @@
<ProjectReference Include="..\..\..\EditorFeatures\Text\Microsoft.CodeAnalysis.EditorFeatures.Text.csproj" />
<ProjectReference Include="..\..\..\Features\Core\Portable\Microsoft.CodeAnalysis.Features.csproj" />
<ProjectReference Include="..\..\..\Features\CSharp\Portable\Microsoft.CodeAnalysis.CSharp.Features.csproj" />
<ProjectReference Include="..\..\..\Features\LanguageServer\Protocol\Microsoft.CodeAnalysis.LanguageServer.Protocol.csproj" />
<ProjectReference Include="..\..\..\Interactive\Host\Microsoft.CodeAnalysis.InteractiveHost.csproj" />
<ProjectReference Include="..\..\..\Scripting\Core\Microsoft.CodeAnalysis.Scripting.csproj" />
<ProjectReference Include="..\..\..\Test\Utilities\Portable\Roslyn.Test.Utilities.csproj" />
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
#nullable enable
using System;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.ErrorReporting;
using Microsoft.CodeAnalysis.LanguageServer;
using Microsoft.VisualStudio.LanguageServer.Client;
using Microsoft.VisualStudio.LanguageServer.Protocol;
using Newtonsoft.Json.Linq;
using StreamJsonRpc;
namespace Microsoft.VisualStudio.LanguageServices.Implementation.LanguageService
{
/// <summary>
/// Defines the language server to be hooked up to an <see cref="ILanguageClient"/> using StreamJsonRpc.
/// This runs in proc as not all features provided by this server are available out of proc (e.g. some diagnostics).
/// </summary>
internal class InProcLanguageServer
{
private readonly IDiagnosticService _diagnosticService;
private readonly JsonRpc _jsonRpc;
private readonly LanguageServerProtocol _protocol;
private readonly Workspace _workspace;
private VSClientCapabilities? _clientCapabilities;
public InProcLanguageServer(Stream inputStream, Stream outputStream, LanguageServerProtocol protocol,
Workspace workspace, IDiagnosticService diagnosticService)
{
_protocol = protocol;
_workspace = workspace;
_jsonRpc = new JsonRpc(outputStream, inputStream, this);
_jsonRpc.StartListening();
_diagnosticService = diagnosticService;
_diagnosticService.DiagnosticsUpdated += DiagnosticService_DiagnosticsUpdated;
}
/// <summary>
/// Handle the LSP initialize request by storing the client capabilities
/// and responding with the server capabilities.
/// The specification assures that the initialize request is sent only once.
/// </summary>
[JsonRpcMethod(Methods.InitializeName)]
public Task<InitializeResult> Initialize(JToken input, CancellationToken cancellationToken)
{
// InitializeParams only references ClientCapabilities, but the VS LSP client
// sends additional VS specific capabilities, so directly deserialize them into the VSClientCapabilities
// to avoid losing them.
_clientCapabilities = input["capabilities"].ToObject<VSClientCapabilities>();
return _protocol.InitializeAsync(_workspace.CurrentSolution, input.ToObject<InitializeParams>(), _clientCapabilities, cancellationToken);
}
[JsonRpcMethod(Methods.InitializedName)]
public Task Initialized() => Task.CompletedTask;
[JsonRpcMethod(Methods.ShutdownName)]
public object? Shutdown(CancellationToken _) => null;
[JsonRpcMethod(Methods.ExitName)]
public void Exit()
{
}
[JsonRpcMethod(Methods.TextDocumentDefinitionName)]
public Task<object> GetTextDocumentDefinitionAsync(JToken input, CancellationToken cancellationToken)
{
var textDocumentPositionParams = input.ToObject<TextDocumentPositionParams>();
return _protocol.GoToDefinitionAsync(_workspace.CurrentSolution, textDocumentPositionParams, _clientCapabilities, cancellationToken);
}
[JsonRpcMethod(Methods.TextDocumentCompletionName)]
public Task<object> GetTextDocumentCompletionAsync(JToken input, CancellationToken cancellationToken)
{
var completionParams = input.ToObject<CompletionParams>();
return _protocol.GetCompletionsAsync(_workspace.CurrentSolution, completionParams, _clientCapabilities, cancellationToken);
}
[JsonRpcMethod(Methods.TextDocumentCompletionResolveName)]
public Task<CompletionItem> ResolveCompletionItemAsync(JToken input, CancellationToken cancellationToken)
{
var completionItem = input.ToObject<CompletionItem>();
return _protocol.ResolveCompletionItemAsync(_workspace.CurrentSolution, completionItem, _clientCapabilities, cancellationToken);
}
[JsonRpcMethod(Methods.TextDocumentDocumentHighlightName)]
public Task<DocumentHighlight[]> GetTextDocumentDocumentHighlightsAsync(JToken input, CancellationToken cancellationToken)
{
var textDocumentPositionParams = input.ToObject<TextDocumentPositionParams>();
return _protocol.GetDocumentHighlightAsync(_workspace.CurrentSolution, textDocumentPositionParams, _clientCapabilities, cancellationToken);
}
[JsonRpcMethod(Methods.TextDocumentDocumentSymbolName)]
public Task<object[]> GetTextDocumentDocumentSymbolsAsync(JToken input, CancellationToken cancellationToken)
{
var documentSymbolParams = input.ToObject<DocumentSymbolParams>();
return _protocol.GetDocumentSymbolsAsync(_workspace.CurrentSolution, documentSymbolParams, _clientCapabilities, cancellationToken);
}
[JsonRpcMethod(Methods.TextDocumentFormattingName)]
public Task<TextEdit[]> GetTextDocumentFormattingAsync(JToken input, CancellationToken cancellationToken)
{
var documentFormattingParams = input.ToObject<DocumentFormattingParams>();
return _protocol.FormatDocumentAsync(_workspace.CurrentSolution, documentFormattingParams, _clientCapabilities, cancellationToken);
}
[JsonRpcMethod(Methods.TextDocumentOnTypeFormattingName)]
public Task<TextEdit[]> GetTextDocumentFormattingOnTypeAsync(JToken input, CancellationToken cancellationToken)
{
var documentOnTypeFormattingParams = input.ToObject<DocumentOnTypeFormattingParams>();
return _protocol.FormatDocumentOnTypeAsync(_workspace.CurrentSolution, documentOnTypeFormattingParams, _clientCapabilities, cancellationToken);
}
[JsonRpcMethod(Methods.TextDocumentImplementationName)]
public Task<object> GetTextDocumentImplementationsAsync(JToken input, CancellationToken cancellationToken)
{
var textDocumentPositionParams = input.ToObject<TextDocumentPositionParams>();
return _protocol.FindImplementationsAsync(_workspace.CurrentSolution, textDocumentPositionParams, _clientCapabilities, cancellationToken);
}
[JsonRpcMethod(Methods.TextDocumentRangeFormattingName)]
public Task<TextEdit[]> GetTextDocumentRangeFormattingAsync(JToken input, CancellationToken cancellationToken)
{
var documentRangeFormattingParams = input.ToObject<DocumentRangeFormattingParams>();
return _protocol.FormatDocumentRangeAsync(_workspace.CurrentSolution, documentRangeFormattingParams, _clientCapabilities, cancellationToken);
}
[JsonRpcMethod(Methods.TextDocumentSignatureHelpName)]
public async Task<SignatureHelp> GetTextDocumentSignatureHelpAsync(JToken input, CancellationToken cancellationToken)
{
var textDocumentPositionParams = input.ToObject<TextDocumentPositionParams>();
return await _protocol.GetSignatureHelpAsync(_workspace.CurrentSolution, textDocumentPositionParams, _clientCapabilities, cancellationToken).ConfigureAwait(false);
}
[JsonRpcMethod(Methods.WorkspaceSymbolName)]
public async Task<SymbolInformation[]> GetWorkspaceSymbolsAsync(JToken input, CancellationToken cancellationToken)
{
var workspaceSymbolParams = input.ToObject<WorkspaceSymbolParams>();
return await _protocol.GetWorkspaceSymbolsAsync(_workspace.CurrentSolution, workspaceSymbolParams, _clientCapabilities, cancellationToken).ConfigureAwait(false);
}
#pragma warning disable VSTHRD100 // Avoid async void methods
private async void DiagnosticService_DiagnosticsUpdated(object sender, DiagnosticsUpdatedArgs e)
#pragma warning restore VSTHRD100 // Avoid async void methods
{
// Since this is an async void method, exceptions here will crash the host VS. We catch exceptions here to make sure that we don't crash the host since
// the worst outcome here is that guests may not see all diagnostics.
try
{
// LSP doesnt support diagnostics without a document. So if we get project level diagnostics without a document, ignore them.
if (e.DocumentId != null && e.Solution != null)
{
var document = e.Solution.GetDocument(e.DocumentId);
if (document == null || document.FilePath == null)
{
return;
}
// Only publish document diagnostics for the languages this provider supports.
if (document.Project.Language != LanguageNames.CSharp && document.Project.Language != LanguageNames.VisualBasic)
{
return;
}
// LSP does not currently support publishing diagnostics incrememntally, so we re-publish all diagnostics.
var diagnostics = await GetDiagnosticsAsync(e.Solution, document, CancellationToken.None).ConfigureAwait(false);
var publishDiagnosticsParams = new PublishDiagnosticParams { Diagnostics = diagnostics, Uri = document.GetURI() };
await _jsonRpc.NotifyWithParameterObjectAsync(Methods.TextDocumentPublishDiagnosticsName, publishDiagnosticsParams).ConfigureAwait(false);
}
}
catch (Exception ex) when (FatalError.ReportWithoutCrash(ex))
{
}
}
private async Task<LanguageServer.Protocol.Diagnostic[]> GetDiagnosticsAsync(Solution solution, Document document, CancellationToken cancellationToken)
{
var diagnostics = _diagnosticService.GetDiagnostics(solution.Workspace, document.Project.Id, document.Id, null, false, cancellationToken);
var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false);
return diagnostics.Select(diagnostic => new LanguageServer.Protocol.Diagnostic
{
Code = diagnostic.Id,
Message = diagnostic.Message,
Severity = ProtocolConversions.DiagnosticSeverityToLspDiagnositcSeverity(diagnostic.Severity),
Range = ProtocolConversions.TextSpanToRange(DiagnosticData.GetExistingOrCalculatedTextSpan(diagnostic.DataLocation, text), text),
// Only the unnecessary diagnostic tag is currently supported via LSP.
Tags = diagnostic.CustomTags.Contains("Unnecessary") ? new DiagnosticTag[] { DiagnosticTag.Unnecessary } : Array.Empty<DiagnosticTag>()
}).ToArray();
}
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
#nullable enable
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Editor;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.LanguageServer;
using Microsoft.CodeAnalysis.Remote;
using Microsoft.VisualStudio.LanguageServer.Client;
using Microsoft.VisualStudio.Threading;
using Microsoft.VisualStudio.Utilities;
using Nerdbank.Streams;
namespace Microsoft.VisualStudio.LanguageServices.Implementation.LanguageService
{
[ContentType(ContentTypeNames.CSharpLspContentTypeName)]
[ContentType(ContentTypeNames.VBLspContentTypeName)]
[Export(typeof(ILanguageClient))]
internal class LiveShareLanguageServerClient : ILanguageClient
{
private readonly IDiagnosticService _diagnosticService;
private readonly LanguageServerProtocol _languageServerProtocol;
private readonly Workspace _workspace;
/// <summary>
/// Gets the name of the language client (displayed to the user).
/// </summary>
public string Name => ServicesVSResources.Live_Share_CSharp_Visual_Basic_Language_Server_Client;
/// <summary>
/// Unused, implementing <see cref="ILanguageClient"/>
/// No additional settings are provided for this server, so we do not need any configuration section names.
/// </summary>
public IEnumerable<string>? ConfigurationSections { get; } = null;
/// <summary>
/// Gets the initialization options object the client wants to send when 'initialize' message is sent.
/// See https://microsoft.github.io/language-server-protocol/specifications/specification-3-14/#initialize
/// We do not provide any additional initialization options.
/// </summary>
public object? InitializationOptions { get; } = null;
/// <summary>
/// Unused, implementing <see cref="ILanguageClient"/>
/// Files that we care about are already provided and watched by the workspace.
/// </summary>
public IEnumerable<string>? FilesToWatch { get; } = null;
public event AsyncEventHandler<EventArgs>? StartAsync;
/// <summary>
/// Unused, implementing <see cref="ILanguageClient"/>
/// </summary>
public event AsyncEventHandler<EventArgs>? StopAsync { add { } remove { } }
[ImportingConstructor]
[Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
public LiveShareLanguageServerClient(LanguageServerProtocol languageServerProtocol, VisualStudioWorkspace workspace, IDiagnosticService diagnosticService)
{
_languageServerProtocol = languageServerProtocol;
_workspace = workspace;
_diagnosticService = diagnosticService;
}
public Task<Connection> ActivateAsync(CancellationToken token)
{
var (clientStream, serverStream) = FullDuplexStream.CreatePair();
_ = new InProcLanguageServer(serverStream, serverStream, _languageServerProtocol, _workspace, _diagnosticService);
return Task.FromResult(new Connection(clientStream, clientStream));
}
/// <summary>
/// Signals that the extension has been loaded. The server can be started immediately, or wait for user action to start.
/// To start the server, invoke the <see cref="StartAsync"/> event;
/// </summary>
public async Task OnLoadedAsync()
{
await StartAsync.InvokeAsync(this, EventArgs.Empty).ConfigureAwait(false);
}
/// <summary>
/// Signals the extension that the language server has been successfully initialized.
/// </summary>
/// <returns>A <see cref="Task"/> which completes when actions that need to be performed when the server is ready are done.</returns>
public Task OnServerInitializedAsync()
{
// We don't have any tasks that need to be triggered after the server has successfully initialized.
return Task.CompletedTask;
}
/// <summary>
/// Signals the extension that the language server failed to initialize.
/// </summary>
/// <returns>A <see cref="Task"/> which completes when additional actions that need to be performed when the server fails to initialize are done.</returns>
public Task OnServerInitializeFailedAsync(Exception e)
{
// We don't need to provide additional exception handling here, liveshare already handles failure cases for this server.
return Task.CompletedTask;
}
}
}
......@@ -78,6 +78,7 @@
<ProjectReference Include="..\..\..\EditorFeatures\Core\Microsoft.CodeAnalysis.EditorFeatures.csproj" PrivateAssets="all" />
<ProjectReference Include="..\..\..\EditorFeatures\Core.Wpf\Microsoft.CodeAnalysis.EditorFeatures.Wpf.csproj" PrivateAssets="all" />
<ProjectReference Include="..\..\..\EditorFeatures\Text\Microsoft.CodeAnalysis.EditorFeatures.Text.csproj" />
<ProjectReference Include="..\..\..\Features\LanguageServer\Protocol\Microsoft.CodeAnalysis.LanguageServer.Protocol.csproj" />
<ProjectReference Include="..\..\..\Workspaces\Core\Portable\Microsoft.CodeAnalysis.Workspaces.csproj" />
<ProjectReference Include="..\..\..\Features\Core\Portable\Microsoft.CodeAnalysis.Features.csproj" />
<ProjectReference Include="..\..\..\Interactive\Host\Microsoft.CodeAnalysis.InteractiveHost.csproj" PrivateAssets="all" Aliases="InteractiveHost" />
......
......@@ -1478,6 +1478,15 @@ internal class ServicesVSResources {
}
}
/// <summary>
/// Looks up a localized string similar to Live Share C#/Visual Basic Language Server Client.
/// </summary>
internal static string Live_Share_CSharp_Visual_Basic_Language_Server_Client {
get {
return ResourceManager.GetString("Live_Share_CSharp_Visual_Basic_Language_Server_Client", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Location:.
/// </summary>
......
......@@ -1356,4 +1356,8 @@ I agree to all of the foregoing:</value>
<data name="CSharp_Visual_Basic_Language_Server_Client" xml:space="preserve">
<value>C#/Visual Basic Language Server Client</value>
</data>
<data name="Live_Share_CSharp_Visual_Basic_Language_Server_Client" xml:space="preserve">
<value>Live Share C#/Visual Basic Language Server Client</value>
<comment>'Live Share' is a product name and does not need to be localized.</comment>
</data>
</root>
\ No newline at end of file
......@@ -172,6 +172,11 @@
<target state="translated">Druh</target>
<note />
</trans-unit>
<trans-unit id="Live_Share_CSharp_Visual_Basic_Language_Server_Client">
<source>Live Share C#/Visual Basic Language Server Client</source>
<target state="new">Live Share C#/Visual Basic Language Server Client</target>
<note>'Live Share' is a product name and does not need to be localized.</note>
</trans-unit>
<trans-unit id="Live_analysis_VSIX_extension">
<source>Live analysis (VSIX extension)</source>
<target state="translated">Živá analýza (rozšíření VSIX)</target>
......
......@@ -172,6 +172,11 @@
<target state="translated">Art</target>
<note />
</trans-unit>
<trans-unit id="Live_Share_CSharp_Visual_Basic_Language_Server_Client">
<source>Live Share C#/Visual Basic Language Server Client</source>
<target state="new">Live Share C#/Visual Basic Language Server Client</target>
<note>'Live Share' is a product name and does not need to be localized.</note>
</trans-unit>
<trans-unit id="Live_analysis_VSIX_extension">
<source>Live analysis (VSIX extension)</source>
<target state="translated">Liveanalyse (VSIX-Erweiterung)</target>
......
......@@ -172,6 +172,11 @@
<target state="translated">Tipo</target>
<note />
</trans-unit>
<trans-unit id="Live_Share_CSharp_Visual_Basic_Language_Server_Client">
<source>Live Share C#/Visual Basic Language Server Client</source>
<target state="new">Live Share C#/Visual Basic Language Server Client</target>
<note>'Live Share' is a product name and does not need to be localized.</note>
</trans-unit>
<trans-unit id="Live_analysis_VSIX_extension">
<source>Live analysis (VSIX extension)</source>
<target state="translated">Análisis en directo (extensión VSIX)</target>
......
......@@ -172,6 +172,11 @@
<target state="translated">Genre</target>
<note />
</trans-unit>
<trans-unit id="Live_Share_CSharp_Visual_Basic_Language_Server_Client">
<source>Live Share C#/Visual Basic Language Server Client</source>
<target state="new">Live Share C#/Visual Basic Language Server Client</target>
<note>'Live Share' is a product name and does not need to be localized.</note>
</trans-unit>
<trans-unit id="Live_analysis_VSIX_extension">
<source>Live analysis (VSIX extension)</source>
<target state="translated">Analyse en temps réel (extension VSIX)</target>
......
......@@ -172,6 +172,11 @@
<target state="translated">Tipo</target>
<note />
</trans-unit>
<trans-unit id="Live_Share_CSharp_Visual_Basic_Language_Server_Client">
<source>Live Share C#/Visual Basic Language Server Client</source>
<target state="new">Live Share C#/Visual Basic Language Server Client</target>
<note>'Live Share' is a product name and does not need to be localized.</note>
</trans-unit>
<trans-unit id="Live_analysis_VSIX_extension">
<source>Live analysis (VSIX extension)</source>
<target state="translated">Analisi in tempo reale (estensione VSIX)</target>
......
......@@ -172,6 +172,11 @@
<target state="translated">種類</target>
<note />
</trans-unit>
<trans-unit id="Live_Share_CSharp_Visual_Basic_Language_Server_Client">
<source>Live Share C#/Visual Basic Language Server Client</source>
<target state="new">Live Share C#/Visual Basic Language Server Client</target>
<note>'Live Share' is a product name and does not need to be localized.</note>
</trans-unit>
<trans-unit id="Live_analysis_VSIX_extension">
<source>Live analysis (VSIX extension)</source>
<target state="translated">ライブ分析 (VSIX 拡張機能)</target>
......
......@@ -172,6 +172,11 @@
<target state="translated">종류</target>
<note />
</trans-unit>
<trans-unit id="Live_Share_CSharp_Visual_Basic_Language_Server_Client">
<source>Live Share C#/Visual Basic Language Server Client</source>
<target state="new">Live Share C#/Visual Basic Language Server Client</target>
<note>'Live Share' is a product name and does not need to be localized.</note>
</trans-unit>
<trans-unit id="Live_analysis_VSIX_extension">
<source>Live analysis (VSIX extension)</source>
<target state="translated">실시간 분석(VSIX 확장)</target>
......
......@@ -172,6 +172,11 @@
<target state="translated">Rodzaj</target>
<note />
</trans-unit>
<trans-unit id="Live_Share_CSharp_Visual_Basic_Language_Server_Client">
<source>Live Share C#/Visual Basic Language Server Client</source>
<target state="new">Live Share C#/Visual Basic Language Server Client</target>
<note>'Live Share' is a product name and does not need to be localized.</note>
</trans-unit>
<trans-unit id="Live_analysis_VSIX_extension">
<source>Live analysis (VSIX extension)</source>
<target state="translated">Analiza na żywo (rozszerzenie VSIX)</target>
......
......@@ -172,6 +172,11 @@
<target state="translated">Tipo</target>
<note />
</trans-unit>
<trans-unit id="Live_Share_CSharp_Visual_Basic_Language_Server_Client">
<source>Live Share C#/Visual Basic Language Server Client</source>
<target state="new">Live Share C#/Visual Basic Language Server Client</target>
<note>'Live Share' is a product name and does not need to be localized.</note>
</trans-unit>
<trans-unit id="Live_analysis_VSIX_extension">
<source>Live analysis (VSIX extension)</source>
<target state="translated">Análise em tempo real (extensão do VSIX)</target>
......
......@@ -172,6 +172,11 @@
<target state="translated">Вид</target>
<note />
</trans-unit>
<trans-unit id="Live_Share_CSharp_Visual_Basic_Language_Server_Client">
<source>Live Share C#/Visual Basic Language Server Client</source>
<target state="new">Live Share C#/Visual Basic Language Server Client</target>
<note>'Live Share' is a product name and does not need to be localized.</note>
</trans-unit>
<trans-unit id="Live_analysis_VSIX_extension">
<source>Live analysis (VSIX extension)</source>
<target state="translated">Динамический анализ (расширение VSIX)</target>
......
......@@ -172,6 +172,11 @@
<target state="translated">Tür</target>
<note />
</trans-unit>
<trans-unit id="Live_Share_CSharp_Visual_Basic_Language_Server_Client">
<source>Live Share C#/Visual Basic Language Server Client</source>
<target state="new">Live Share C#/Visual Basic Language Server Client</target>
<note>'Live Share' is a product name and does not need to be localized.</note>
</trans-unit>
<trans-unit id="Live_analysis_VSIX_extension">
<source>Live analysis (VSIX extension)</source>
<target state="translated">Canlı analiz (VSIX uzantısı)</target>
......
......@@ -172,6 +172,11 @@
<target state="translated">种类</target>
<note />
</trans-unit>
<trans-unit id="Live_Share_CSharp_Visual_Basic_Language_Server_Client">
<source>Live Share C#/Visual Basic Language Server Client</source>
<target state="new">Live Share C#/Visual Basic Language Server Client</target>
<note>'Live Share' is a product name and does not need to be localized.</note>
</trans-unit>
<trans-unit id="Live_analysis_VSIX_extension">
<source>Live analysis (VSIX extension)</source>
<target state="translated">实时分析(VSIX 扩展)</target>
......
......@@ -172,6 +172,11 @@
<target state="translated">種類</target>
<note />
</trans-unit>
<trans-unit id="Live_Share_CSharp_Visual_Basic_Language_Server_Client">
<source>Live Share C#/Visual Basic Language Server Client</source>
<target state="new">Live Share C#/Visual Basic Language Server Client</target>
<note>'Live Share' is a product name and does not need to be localized.</note>
</trans-unit>
<trans-unit id="Live_analysis_VSIX_extension">
<source>Live analysis (VSIX extension)</source>
<target state="translated">即時分析 (VSIX 延伸模組)</target>
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Composition;
using Microsoft.CodeAnalysis.Completion;
namespace Microsoft.VisualStudio.LanguageServices.LiveShare.Client.Completion
{
[ExportCompletionProvider("CSharpLspCompletionProvider", StringConstants.CSharpLspLanguageName), Shared]
internal class CSharpLspCompletionProvider : RoslynCompletionProvider
{
[ImportingConstructor]
public CSharpLspCompletionProvider(CSharpLspClientServiceFactory csharpLspClientServiceFactory)
: base(csharpLspClientServiceFactory)
{
}
}
[ExportCompletionProvider("VBLspCompletionProvider", StringConstants.VBLspLanguageName), Shared]
internal class VBLspCompletionProvider : RoslynCompletionProvider
{
[ImportingConstructor]
public VBLspCompletionProvider(VisualBasicLspClientServiceFactory vbLspClientServiceFactory)
: base(vbLspClientServiceFactory)
{
}
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Immutable;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Completion;
using Microsoft.CodeAnalysis.LanguageServer;
using Microsoft.CodeAnalysis.LanguageServer.CustomProtocol;
using Microsoft.CodeAnalysis.Text;
using Microsoft.VisualStudio.LanguageServices.LiveShare.Protocol;
using Microsoft.VisualStudio.LiveShare.LanguageServices;
using Newtonsoft.Json.Linq;
using LSP = Microsoft.VisualStudio.LanguageServer.Protocol;
namespace Microsoft.VisualStudio.LanguageServices.LiveShare.Client.Completion
{
internal class RoslynCompletionProvider : CommonCompletionProvider
{
private readonly AbstractLspClientServiceFactory _roslynLspClientServiceFactory;
public RoslynCompletionProvider(AbstractLspClientServiceFactory roslynLspClientServiceFactory)
{
_roslynLspClientServiceFactory = roslynLspClientServiceFactory ?? throw new ArgumentNullException(nameof(roslynLspClientServiceFactory));
}
public override async Task ProvideCompletionsAsync(CompletionContext context)
{
// This provider is exported for all workspaces - so limit it to just our workspace & the debugger's intellisense workspace
if (context.Document.Project.Solution.Workspace.Kind != WorkspaceKind.AnyCodeRoslynWorkspace &&
context.Document.Project.Solution.Workspace.Kind != StringConstants.DebuggerIntellisenseWorkspaceKind)
{
return;
}
var lspClient = _roslynLspClientServiceFactory.ActiveLanguageServerClient;
if (lspClient == null)
{
return;
}
var text = await context.Document.GetTextAsync(context.CancellationToken).ConfigureAwait(false);
var completionParams = new LSP.CompletionParams
{
TextDocument = ProtocolConversions.DocumentToTextDocumentIdentifier(context.Document),
Position = ProtocolConversions.LinePositionToPosition(text.Lines.GetLinePosition(context.Position)),
Context = new LSP.CompletionContext { TriggerCharacter = context.Trigger.Character.ToString(), TriggerKind = GetTriggerKind(context.Trigger) }
};
var completionObject = await lspClient.RequestAsync(LSP.Methods.TextDocumentCompletion.ToLSRequest(), completionParams, context.CancellationToken).ConfigureAwait(false);
if (completionObject == null)
{
return;
}
var completionList = ((JToken)completionObject).ToObject<RoslynCompletionItem[]>();
foreach (var item in completionList)
{
ImmutableArray<string> tags;
if (item.Tags != null)
{
tags = item.Tags.AsImmutable();
}
else
{
var glyph = ProtocolConversions.CompletionItemKindToGlyph(item.Kind);
tags = GlyphTags.GetTags(glyph);
}
var properties = ImmutableDictionary.CreateBuilder<string, string>();
if (!string.IsNullOrEmpty(item.Detail))
{
// The display text is encoded as TaggedText | value
properties.Add("Description", $"Text|{item.Detail}");
}
properties.Add("InsertionText", item.InsertText);
properties.Add("ResolveData", JToken.FromObject(item).ToString());
var completionItem = CompletionItem.Create(item.Label, item.FilterText, item.SortText, properties: properties.ToImmutable(), tags: tags);
context.AddItem(completionItem);
}
}
protected override async Task<CompletionDescription> GetDescriptionWorkerAsync(Document document, CompletionItem item, CancellationToken cancellationToken)
{
var lspClient = _roslynLspClientServiceFactory.ActiveLanguageServerClient;
if (lspClient == null)
{
return await base.GetDescriptionWorkerAsync(document, item, cancellationToken).ConfigureAwait(false);
}
if (!item.Properties.TryGetValue("ResolveData", out var serializedItem))
{
return await base.GetDescriptionWorkerAsync(document, item, cancellationToken).ConfigureAwait(false);
}
var completionItem = JToken.Parse(serializedItem).ToObject<RoslynCompletionItem>();
var request = new LspRequest<RoslynCompletionItem, RoslynCompletionItem>(LSP.Methods.TextDocumentCompletionResolveName);
var resolvedCompletionItem = await lspClient.RequestAsync(request, completionItem, cancellationToken).ConfigureAwait(false);
if (resolvedCompletionItem?.Description == null)
{
return await base.GetDescriptionWorkerAsync(document, item, cancellationToken).ConfigureAwait(false);
}
var parts = resolvedCompletionItem.Description.Select(tt => tt.ToTaggedText()).AsImmutable();
return CompletionDescription.Create(parts);
}
private LSP.CompletionTriggerKind GetTriggerKind(CompletionTrigger trigger)
{
if (trigger.Kind == CompletionTriggerKind.Insertion || trigger.Kind == CompletionTriggerKind.Deletion)
{
return LSP.CompletionTriggerKind.TriggerCharacter;
}
return LSP.CompletionTriggerKind.Invoked;
}
public override Task<TextChange?> GetTextChangeAsync(Document document, CompletionItem selectedItem, char? ch, CancellationToken cancellationToken)
{
selectedItem.Properties.TryGetValue("InsertionText", out var text);
if (text != null)
{
return Task.FromResult<TextChange?>(new TextChange(selectedItem.Span, text));
}
return Task.FromResult<TextChange?>(null);
}
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Composition;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Completion;
using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.Host.Mef;
namespace Microsoft.VisualStudio.LanguageServices.LiveShare.Client.Completion
{
[ExportLanguageServiceFactory(typeof(CompletionService), StringConstants.CSharpLspLanguageName), Shared]
internal class CSharpLspCompletionServiceFactory : ILanguageServiceFactory
{
public ILanguageService CreateLanguageService(HostLanguageServices languageServices)
{
var originalService = languageServices.GetOriginalLanguageService<CompletionService>();
return new RoslynCompletionService(languageServices.WorkspaceServices.Workspace,
originalService, StringConstants.CSharpLspLanguageName);
}
}
[ExportLanguageServiceFactory(typeof(CompletionService), StringConstants.VBLspLanguageName), Shared]
internal class VBLspCompletionServiceFactory : ILanguageServiceFactory
{
public ILanguageService CreateLanguageService(HostLanguageServices languageServices)
{
var originalService = languageServices.GetOriginalLanguageService<CompletionService>();
return new RoslynCompletionService(languageServices.WorkspaceServices.Workspace,
originalService, StringConstants.VBLspLanguageName);
}
}
// In d16, this export is to disable local TypeScript completion within a Live Share session; it is not used
[ExportLanguageServiceFactory(typeof(CompletionService), StringConstants.TypeScriptLanguageName, WorkspaceKind.AnyCodeRoslynWorkspace), Shared]
internal class TypeScriptLspCompletionServiceFactory : ILanguageServiceFactory
{
private readonly VisualStudioWorkspace _visualStudioWorkspace;
[ImportingConstructor]
public TypeScriptLspCompletionServiceFactory(VisualStudioWorkspace visualStudioWorkspace)
{
_visualStudioWorkspace = visualStudioWorkspace ?? throw new ArgumentNullException(nameof(visualStudioWorkspace));
}
public ILanguageService CreateLanguageService(HostLanguageServices languageServices)
{
var originalService = _visualStudioWorkspace.Services.GetLanguageServices(StringConstants.TypeScriptLanguageName).GetService<CompletionService>();
return new RoslynCompletionService(languageServices.WorkspaceServices.Workspace,
originalService, StringConstants.TypeScriptLanguageName);
}
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Immutable;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Completion;
using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.Text;
namespace Microsoft.VisualStudio.LanguageServices.LiveShare.Client.Completion
{
internal class RoslynCompletionService : CompletionServiceWithProviders
{
private readonly CompletionService _originalService;
private readonly string _language;
public RoslynCompletionService(Workspace workspace, CompletionService originalService, string language)
: base(workspace)
{
_originalService = originalService ?? throw new ArgumentNullException(nameof(originalService));
_language = language ?? throw new ArgumentNullException(nameof(language));
workspace.Options = workspace.Options.WithChangedOption(CompletionOptions.BlockForCompletionItems, language, false);
}
public override string Language => _language;
public override bool ShouldTriggerCompletion(SourceText text, int caretPosition, CompletionTrigger trigger, ImmutableHashSet<string> roles = null, OptionSet options = null)
{
// Just ask the local service if we should trigger completion based on its rules since that determination is based on just looking at the current buffer.
return _originalService.ShouldTriggerCompletion(text, caretPosition, trigger, roles, options);
}
}
}
......@@ -6,7 +6,7 @@
namespace Microsoft.VisualStudio.LanguageServices.LiveShare.Client.Debugging
{
[ExportContentTypeLanguageService(StringConstants.CSharpLspContentTypeName, StringConstants.CSharpLspLanguageName), Shared]
[ExportContentTypeLanguageService(ContentTypeNames.CSharpLspContentTypeName, StringConstants.CSharpLspLanguageName), Shared]
internal class CSharpLspContentTypeLanguageService : IContentTypeLanguageService
{
private readonly IContentTypeRegistryService _contentTypeRegistry;
......
......@@ -5,6 +5,7 @@
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Editor;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.VisualStudio.ComponentModelHost;
using Microsoft.VisualStudio.LanguageServices.Implementation.DebuggerIntelliSense;
......@@ -40,7 +41,7 @@ internal class CSharpLspDebuggerIntelliSenseContext : AbstractDebuggerIntelliSen
currentStatementSpan,
componentModel,
serviceProvider,
componentModel.GetService<IContentTypeRegistryService>().GetContentType(StringConstants.CSharpLspContentTypeName))
componentModel.GetService<IContentTypeRegistryService>().GetContentType(ContentTypeNames.CSharpLspContentTypeName))
{
}
......
......@@ -2,6 +2,7 @@
using System;
using System.Runtime.InteropServices;
using Microsoft.CodeAnalysis.Editor;
using Microsoft.VisualStudio.ComponentModelHost;
using Microsoft.VisualStudio.LanguageServices.Implementation.DebuggerIntelliSense;
using Microsoft.VisualStudio.LanguageServices.Implementation.LanguageService;
......@@ -28,7 +29,7 @@ internal CSharpLspLanguageService(CSharpLspPackage package)
public override Guid LanguageServiceId { get; } = LanguageServiceGuid;
protected override string ContentTypeName => StringConstants.CSharpLspContentTypeName;
protected override string ContentTypeName => ContentTypeNames.CSharpLspContentTypeName;
protected override string LanguageName => StringConstants.CSharpLspLanguageName;
......
......@@ -6,7 +6,7 @@
namespace Microsoft.VisualStudio.LanguageServices.LiveShare.Client.Debugging
{
[ExportContentTypeLanguageService(StringConstants.VBLspContentTypeName, StringConstants.VBLspLanguageName), Shared]
[ExportContentTypeLanguageService(ContentTypeNames.VBLspContentTypeName, StringConstants.VBLspLanguageName), Shared]
internal class VBLspContentTypeLanguageService : IContentTypeLanguageService
{
private readonly IContentTypeRegistryService _contentTypeRegistry;
......@@ -19,7 +19,7 @@ public VBLspContentTypeLanguageService(IContentTypeRegistryService contentTypeRe
public IContentType GetDefaultContentType()
{
return _contentTypeRegistry.GetContentType(StringConstants.VBLspContentTypeName);
return _contentTypeRegistry.GetContentType(ContentTypeNames.VBLspContentTypeName);
}
}
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Immutable;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Host;
namespace Microsoft.VisualStudio.LanguageServices.LiveShare.Client.Diagnostics
{
/// <summary>
/// A service to get diagnostics for a given document from the remote machine.
/// </summary>
internal interface IRemoteDiagnosticsService : ILanguageService
{
/// <summary>
/// Given a document get the diagnostics in that document.
/// </summary>
Task<ImmutableArray<Diagnostic>> GetDiagnosticsAsync(Document document, CancellationToken cancellationToken);
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Immutable;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Diagnostics;
namespace Microsoft.VisualStudio.LanguageServices.LiveShare.Client.Diagnostics
{
/// <summary>
/// A diagnostic analyzer that fetches diagnostics from the remote side.
/// </summary>
/// <remarks>
/// Since DiagnosticAnalyzers don't participate in MEF composition, we get the diagnostics through a
/// language service called <see cref="IRemoteDiagnosticsService"/>
/// </remarks>
[DiagnosticAnalyzer(StringConstants.CSharpLspLanguageName, StringConstants.VBLspLanguageName)]
internal class RoslynDocumentDiagnosticAnalyzer : DocumentDiagnosticAnalyzer
{
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => ImmutableArray<DiagnosticDescriptor>.Empty;
public override async Task<ImmutableArray<Diagnostic>> AnalyzeSemanticsAsync(Document document, CancellationToken cancellationToken)
{
var diagnosticsService = document.Project.LanguageServices.GetService<IRemoteDiagnosticsService>();
if (diagnosticsService == null)
{
return ImmutableArray<Diagnostic>.Empty;
}
return await diagnosticsService.GetDiagnosticsAsync(document, cancellationToken).ConfigureAwait(false);
}
public override Task<ImmutableArray<Diagnostic>> AnalyzeSyntaxAsync(Document document, CancellationToken cancellationToken)
{
return Task.FromResult(ImmutableArray<Diagnostic>.Empty);
}
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Composition;
using Microsoft.CodeAnalysis.Host.Mef;
namespace Microsoft.VisualStudio.LanguageServices.LiveShare.Client.Diagnostics
{
[ExportLanguageService(typeof(IRemoteDiagnosticsService), StringConstants.CSharpLspLanguageName), Shared]
internal class CSharpLspRemoteDiagnosticsService : RoslynRemoteDiagnosticsService
{
[ImportingConstructor]
public CSharpLspRemoteDiagnosticsService(CSharpLspClientServiceFactory csharpLspClientServiceFactory)
: base(csharpLspClientServiceFactory)
{
}
}
[ExportLanguageService(typeof(IRemoteDiagnosticsService), StringConstants.VBLspLanguageName), Shared]
internal class VBLspRemoteDiagnosticsService : RoslynRemoteDiagnosticsService
{
[ImportingConstructor]
public VBLspRemoteDiagnosticsService(VisualBasicLspClientServiceFactory vbLspClientServiceFactory)
: base(vbLspClientServiceFactory)
{
}
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Immutable;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.LanguageServer;
using Microsoft.VisualStudio.LanguageServices.LiveShare.CustomProtocol;
using Microsoft.VisualStudio.LanguageServices.LiveShare.Protocol;
using Microsoft.VisualStudio.LiveShare.LanguageServices;
using CustomMethods = Microsoft.VisualStudio.LiveShare.LanguageServices.Protocol.CustomMethods;
using LSP = Microsoft.VisualStudio.LanguageServer.Protocol;
namespace Microsoft.VisualStudio.LanguageServices.LiveShare.Client.Diagnostics
{
internal class RoslynRemoteDiagnosticsService : IRemoteDiagnosticsService
{
private readonly AbstractLspClientServiceFactory _roslynLspClientServiceFactory;
public RoslynRemoteDiagnosticsService(AbstractLspClientServiceFactory roslynLspClientServiceFactory)
{
_roslynLspClientServiceFactory = roslynLspClientServiceFactory ?? throw new ArgumentNullException(nameof(roslynLspClientServiceFactory));
}
public async Task<ImmutableArray<Diagnostic>> GetDiagnosticsAsync(Document document, CancellationToken cancellationToken)
{
var lspClient = _roslynLspClientServiceFactory.ActiveLanguageServerClient;
if (lspClient == null)
{
return ImmutableArray<Diagnostic>.Empty;
}
var textDocumentParams = new TextDocumentParams
{
TextDocument = new LSP.TextDocumentIdentifier
{
Uri = lspClient.ProtocolConverter.ToProtocolUri(new Uri(document.FilePath))
}
};
var request = new LspRequest<TextDocumentParams, RoslynDiagnostic[]>(CustomMethods.GetDocumentDiagnosticsName);
var lspDiagnostics = await lspClient.RequestAsync(request, textDocumentParams, cancellationToken).ConfigureAwait(false);
if (lspDiagnostics == null)
{
return ImmutableArray<Diagnostic>.Empty;
}
var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false);
var diagnostics = ImmutableArray.CreateBuilder<Diagnostic>();
foreach (var diagnostic in lspDiagnostics)
{
var location = Location.Create(document.FilePath, ProtocolConversions.RangeToTextSpan(diagnostic.Range, text),
ProtocolConversions.RangeToLinePositionSpan(diagnostic.Range));
var severity = ToDiagnosticSeverity(diagnostic.Severity);
var diag = Diagnostic.Create(diagnostic.Code ?? "VSLS", string.Empty, diagnostic.Message, severity, severity,
true, severity == DiagnosticSeverity.Error ? 0 : 1, location: location, customTags: diagnostic.Tags);
diagnostics.Add(diag);
}
return diagnostics.ToImmutableArray();
}
private static DiagnosticSeverity ToDiagnosticSeverity(LSP.DiagnosticSeverity severity)
{
switch (severity)
{
case LSP.DiagnosticSeverity.Error:
return DiagnosticSeverity.Error;
case LSP.DiagnosticSeverity.Warning:
return DiagnosticSeverity.Warning;
case LSP.DiagnosticSeverity.Information:
return DiagnosticSeverity.Info;
case LSP.DiagnosticSeverity.Hint:
return DiagnosticSeverity.Hidden;
default:
throw new InvalidOperationException("Unknown severity");
}
}
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Composition;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Editor;
using Microsoft.CodeAnalysis.Editor.Host;
using Microsoft.CodeAnalysis.Editor.Shared.Utilities;
using Microsoft.CodeAnalysis.Host.Mef;
namespace Microsoft.VisualStudio.LanguageServices.LiveShare.Client.GotoDefinition
{
[ExportLanguageService(typeof(IGoToDefinitionService), StringConstants.CSharpLspLanguageName), Shared]
internal class CSharpLspGotoDefinitionService : RoslynGotoDefinitionService
{
[ImportingConstructor]
public CSharpLspGotoDefinitionService(IStreamingFindUsagesPresenter streamingPresenter, CSharpLspClientServiceFactory csharpLspClientServiceFactory,
RemoteLanguageServiceWorkspace remoteWorkspace, IThreadingContext threadingContext)
: base(streamingPresenter, csharpLspClientServiceFactory, remoteWorkspace, threadingContext) { }
}
[ExportLanguageService(typeof(IGoToDefinitionService), StringConstants.VBLspLanguageName), Shared]
internal class VBLspGotoDefinitionService : RoslynGotoDefinitionService
{
[ImportingConstructor]
public VBLspGotoDefinitionService(IStreamingFindUsagesPresenter streamingPresenter, VisualBasicLspClientServiceFactory vbLspClientServiceFactory,
RemoteLanguageServiceWorkspace remoteWorkspace, IThreadingContext threadingContext)
: base(streamingPresenter, vbLspClientServiceFactory, remoteWorkspace, threadingContext) { }
}
[ExportLanguageService(typeof(IGoToDefinitionService), StringConstants.TypeScriptLanguageName, WorkspaceKind.AnyCodeRoslynWorkspace), Shared]
internal class TypeScriptLspGotoDefinitionService : RoslynGotoDefinitionService
{
[ImportingConstructor]
public TypeScriptLspGotoDefinitionService(IStreamingFindUsagesPresenter streamingPresenter, TypeScriptLspClientServiceFactory typeScriptLspClientServiceFactory,
RemoteLanguageServiceWorkspace remoteWorkspace, IThreadingContext threadingContext)
: base(streamingPresenter, typeScriptLspClientServiceFactory, remoteWorkspace, threadingContext)
{
}
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Threading;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Editor;
using Microsoft.CodeAnalysis.Editor.Host;
using Microsoft.CodeAnalysis.Editor.Shared.Utilities;
using Microsoft.CodeAnalysis.FindSymbols;
using Microsoft.CodeAnalysis.FindUsages;
using Microsoft.CodeAnalysis.LanguageServer;
using Microsoft.CodeAnalysis.Navigation;
using Microsoft.VisualStudio.LanguageServices.LiveShare.Protocol;
using Newtonsoft.Json.Linq;
using LSP = Microsoft.VisualStudio.LanguageServer.Protocol;
using TPL = System.Threading.Tasks;
namespace Microsoft.VisualStudio.LanguageServices.LiveShare.Client.GotoDefinition
{
internal class RoslynGotoDefinitionService : IGoToDefinitionService
{
private readonly IStreamingFindUsagesPresenter _streamingPresenter;
private readonly AbstractLspClientServiceFactory _roslynLspClientServiceFactory;
private readonly RemoteLanguageServiceWorkspace _remoteWorkspace;
private readonly IThreadingContext _threadingContext;
public RoslynGotoDefinitionService(
IStreamingFindUsagesPresenter streamingPresenter,
AbstractLspClientServiceFactory roslynLspClientServiceFactory,
RemoteLanguageServiceWorkspace remoteWorkspace,
IThreadingContext threadingContext)
{
_streamingPresenter = streamingPresenter ?? throw new ArgumentNullException(nameof(streamingPresenter));
_roslynLspClientServiceFactory = roslynLspClientServiceFactory ?? throw new ArgumentNullException(nameof(roslynLspClientServiceFactory));
_remoteWorkspace = remoteWorkspace ?? throw new ArgumentNullException(nameof(remoteWorkspace));
_threadingContext = threadingContext ?? throw new ArgumentNullException(nameof(threadingContext));
}
public async TPL.Task<IEnumerable<INavigableItem>> FindDefinitionsAsync(Document document, int position, CancellationToken cancellationToken)
{
var definitionItems = await GetDefinitionItemsAsync(document, position, cancellationToken).ConfigureAwait(false);
if (definitionItems.IsDefaultOrEmpty)
{
return ImmutableArray<INavigableItem>.Empty;
}
var navigableItems = ImmutableArray.CreateBuilder<INavigableItem>();
foreach (var documentSpan in definitionItems.SelectMany(di => di.SourceSpans))
{
var declaredSymbolInfo = new DeclaredSymbolInfo(Roslyn.Utilities.StringTable.GetInstance(),
string.Empty,
string.Empty,
string.Empty,
string.Empty,
DeclaredSymbolInfoKind.Class,
Accessibility.NotApplicable,
documentSpan.SourceSpan,
ImmutableArray<string>.Empty);
navigableItems.Add(NavigableItemFactory.GetItemFromDeclaredSymbolInfo(declaredSymbolInfo, documentSpan.Document));
}
return navigableItems.ToArray();
}
public bool TryGoToDefinition(Document document, int position, CancellationToken cancellationToken)
{
return _threadingContext.JoinableTaskFactory.Run(async () =>
{
var definitionItems = await GetDefinitionItemsAsync(document, position, cancellationToken).ConfigureAwait(true);
return await _streamingPresenter.TryNavigateToOrPresentItemsAsync(document.Project.Solution.Workspace,
"GoTo Definition",
definitionItems).ConfigureAwait(true);
});
}
private async TPL.Task<ImmutableArray<DefinitionItem>> GetDefinitionItemsAsync(Document document, int position, CancellationToken cancellationToken)
{
var lspClient = _roslynLspClientServiceFactory.ActiveLanguageServerClient;
if (lspClient == null)
{
return ImmutableArray<DefinitionItem>.Empty;
}
var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false);
var textDocumentPositionParams = ProtocolConversions.PositionToTextDocumentPositionParams(position, text, document);
var response = await lspClient.RequestAsync(LSP.Methods.TextDocumentDefinition.ToLSRequest(), textDocumentPositionParams, cancellationToken).ConfigureAwait(false);
var locations = ((JToken)response)?.ToObject<LSP.Location[]>();
if (locations == null)
{
return ImmutableArray<DefinitionItem>.Empty;
}
var definitionItems = ImmutableArray.CreateBuilder<DefinitionItem>();
foreach (var location in locations)
{
DocumentSpan? documentSpan;
if (lspClient.ProtocolConverter.IsExternalDocument(location.Uri))
{
var externalDocument = _remoteWorkspace.GetOrAddExternalDocument(location.Uri.LocalPath, document.Project.Language);
var externalText = await externalDocument.GetTextAsync(cancellationToken).ConfigureAwait(false);
var textSpan = ProtocolConversions.RangeToTextSpan(location.Range, externalText);
documentSpan = new DocumentSpan(externalDocument, textSpan);
}
else
{
documentSpan = await _remoteWorkspace.GetDocumentSpanFromLocation(location, cancellationToken).ConfigureAwait(false);
if (documentSpan == null)
{
continue;
}
}
definitionItems.Add(DefinitionItem.Create(ImmutableArray<string>.Empty, ImmutableArray<TaggedText>.Empty, documentSpan.Value));
}
return definitionItems.ToImmutable();
}
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Composition;
using Microsoft.CodeAnalysis.DocumentHighlighting;
using Microsoft.CodeAnalysis.Host.Mef;
namespace Microsoft.VisualStudio.LanguageServices.LiveShare.Client.Highlights
{
[ExportLanguageService(typeof(IDocumentHighlightsService), StringConstants.CSharpLspLanguageName), Shared]
internal class CSharpLspDocumentHighlightsService : RoslynDocumentHighlightsService
{
[ImportingConstructor]
public CSharpLspDocumentHighlightsService(CSharpLspClientServiceFactory csharpLspClientServiceFactory)
: base(csharpLspClientServiceFactory)
{
}
}
[ExportLanguageService(typeof(IDocumentHighlightsService), StringConstants.VBLspLanguageName), Shared]
internal class VBLspDocumentHighlightsService : RoslynDocumentHighlightsService
{
[ImportingConstructor]
public VBLspDocumentHighlightsService(VisualBasicLspClientServiceFactory vbLspClientServiceFactory)
: base(vbLspClientServiceFactory)
{
}
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Immutable;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.DocumentHighlighting;
using Microsoft.CodeAnalysis.LanguageServer;
using Microsoft.VisualStudio.LanguageServer.Protocol;
using Microsoft.VisualStudio.LanguageServices.LiveShare.Protocol;
namespace Microsoft.VisualStudio.LanguageServices.LiveShare.Client.Highlights
{
internal class RoslynDocumentHighlightsService : IDocumentHighlightsService
{
private readonly AbstractLspClientServiceFactory _roslynLspClientServiceFactory;
public RoslynDocumentHighlightsService(AbstractLspClientServiceFactory roslynLspClientServiceFactory)
{
_roslynLspClientServiceFactory = roslynLspClientServiceFactory ?? throw new ArgumentNullException(nameof(roslynLspClientServiceFactory));
}
public async Task<ImmutableArray<DocumentHighlights>> GetDocumentHighlightsAsync(Document document, int position, IImmutableSet<Document> documentsToSearch, CancellationToken cancellationToken)
{
var lspClient = _roslynLspClientServiceFactory.ActiveLanguageServerClient;
if (lspClient == null)
{
return ImmutableArray<DocumentHighlights>.Empty;
}
var text = await document.GetTextAsync().ConfigureAwait(false);
var textDocumentPositionParams = ProtocolConversions.PositionToTextDocumentPositionParams(position, text, document);
var highlights = await lspClient.RequestAsync(Methods.TextDocumentDocumentHighlight.ToLSRequest(), textDocumentPositionParams, cancellationToken).ConfigureAwait(false);
if (highlights == null)
{
return ImmutableArray<DocumentHighlights>.Empty;
}
var highlightSpans = highlights.Select(highlight => new HighlightSpan(ProtocolConversions.RangeToTextSpan(highlight.Range, text), ToHighlightSpanKind(highlight.Kind)));
return ImmutableArray.Create(new DocumentHighlights(document, highlightSpans.ToImmutableArray()));
}
private HighlightSpanKind ToHighlightSpanKind(DocumentHighlightKind kind)
{
switch (kind)
{
case DocumentHighlightKind.Text:
return HighlightSpanKind.Definition;
case DocumentHighlightKind.Read:
return HighlightSpanKind.Reference;
case DocumentHighlightKind.Write:
return HighlightSpanKind.WrittenReference;
default:
return HighlightSpanKind.None;
}
}
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Composition;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Editor;
using Microsoft.CodeAnalysis.Host.Mef;
namespace Microsoft.VisualStudio.LanguageServices.LiveShare.Client.Navigation
{
[ExportLanguageService(typeof(INavigationBarItemService), StringConstants.CSharpLspLanguageName), Shared]
internal class CSharpLspNavigationBarItemService : RoslynNavigationBarItemService
{
[ImportingConstructor]
protected CSharpLspNavigationBarItemService(CSharpLspClientServiceFactory csharpLspClientServiceFactory)
: base(csharpLspClientServiceFactory)
{
}
}
[ExportLanguageService(typeof(INavigationBarItemService), StringConstants.VBLspLanguageName), Shared]
internal class VBLspNavigationBarItemService : RoslynNavigationBarItemService
{
[ImportingConstructor]
protected VBLspNavigationBarItemService(VisualBasicLspClientServiceFactory vbLspClientServiceFactory)
: base(vbLspClientServiceFactory)
{
}
}
[ExportLanguageService(typeof(INavigationBarItemService), StringConstants.TypeScriptLanguageName, WorkspaceKind.AnyCodeRoslynWorkspace), Shared]
internal class TypeScriptLspNavigationBarItemService : RoslynNavigationBarItemService
{
[ImportingConstructor]
protected TypeScriptLspNavigationBarItemService(TypeScriptLspClientServiceFactory typeScriptLspClientServiceFactory)
: base(typeScriptLspClientServiceFactory)
{
}
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Editor;
using Microsoft.CodeAnalysis.Editor.Extensibility.NavigationBar;
using Microsoft.CodeAnalysis.Editor.Shared.Utilities;
using Microsoft.CodeAnalysis.ErrorReporting;
using Microsoft.CodeAnalysis.LanguageServer;
using Microsoft.CodeAnalysis.Navigation;
using Microsoft.CodeAnalysis.Text;
using Microsoft.VisualStudio.LanguageServer.Protocol;
using Microsoft.VisualStudio.LanguageServices.LiveShare.Protocol;
using Microsoft.VisualStudio.Text.Editor;
namespace Microsoft.VisualStudio.LanguageServices.LiveShare.Client.Navigation
{
internal class RoslynNavigationBarItemService : AbstractNavigationBarItemService
{
private readonly AbstractLspClientServiceFactory _roslynLspClientServiceFactory;
internal RoslynNavigationBarItemService(AbstractLspClientServiceFactory roslynLspClientServiceFactory)
{
_roslynLspClientServiceFactory = roslynLspClientServiceFactory ?? throw new ArgumentNullException(nameof(roslynLspClientServiceFactory));
}
public override async Task<IList<NavigationBarItem>> GetItemsAsync(Document document, CancellationToken cancellationToken)
{
var lspClient = _roslynLspClientServiceFactory.ActiveLanguageServerClient;
if (lspClient == null)
{
return ImmutableArray<NavigationBarItem>.Empty;
}
var documentSymbolParams = new DocumentSymbolParams
{
TextDocument = new TextDocumentIdentifier { Uri = new Uri(document.FilePath) }
};
var symbols = await lspClient.RequestAsync(Methods.TextDocumentDocumentSymbol.ToLSRequest(), documentSymbolParams, cancellationToken).ConfigureAwait(false);
if (symbols == null)
{
return ImmutableArray<NavigationBarItem>.Empty;
}
var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false);
var navBarItems = new List<NavigationBarItem>();
var containerGroups = symbols.GroupBy(s => s.ContainerName);
// Add symbols that are containers with children.
foreach (var containerGroup in containerGroups)
{
var containerSymbol = symbols.Where(s => s.Name == containerGroup.Key).FirstOrDefault();
if (containerSymbol == null)
{
continue;
}
var children = new List<NavigationBarItem>();
foreach (var child in containerGroup)
{
children.Add(CreateNavigationBarItem(child, text, ImmutableArray<NavigationBarItem>.Empty));
}
navBarItems.Add(CreateNavigationBarItem(containerSymbol, text, ImmutableArray.CreateRange(children.Where(nbi => nbi != null))));
}
// Now add top-level items that are not containers.
var topLevelSymbols = symbols.Where(s => s.ContainerName == null);
var containerNames = containerGroups.Select(g => g.Key).Where(c => c != null);
var topLevelSymbolsWithoutChildren = topLevelSymbols.Where(s => !containerNames.Contains(s.Name));
navBarItems.AddRange(topLevelSymbolsWithoutChildren.Select(symbol => CreateNavigationBarItem(symbol, text, ImmutableArray<NavigationBarItem>.Empty)));
return ImmutableList.CreateRange(navBarItems.Where(nbi => nbi != null));
}
private static NavigationBarItem CreateNavigationBarItem(SymbolInformation symbolInformation, SourceText text, ImmutableArray<NavigationBarItem> children)
{
try
{
var name = symbolInformation.Name;
var glyph = ProtocolConversions.SymbolKindToGlyph(symbolInformation.Kind);
var textSpan = ProtocolConversions.RangeToTextSpan(symbolInformation.Location.Range, text);
return new RemoteNavigationBarItem(name, glyph, ImmutableArray.Create(textSpan), children);
}
catch (ArgumentOutOfRangeException ex) when (FatalError.ReportWithoutCrash(ex))
{
return null;
}
}
public override void NavigateToItem(Document document, NavigationBarItem item, ITextView textView, CancellationToken cancellationToken)
{
if (item.Spans.Count > 0)
{
var workspace = document.Project.Solution.Workspace;
var navigationService = workspace.Services.GetService<IDocumentNavigationService>();
navigationService.TryNavigateToPosition(workspace, document.Id, item.Spans[0].Start);
}
}
protected internal override VirtualTreePoint? GetSymbolItemNavigationPoint(Document document, NavigationBarSymbolItem item, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
private class RemoteNavigationBarItem : NavigationBarItem
{
public RemoteNavigationBarItem(string text, Glyph glyph, IList<TextSpan> spans, IList<NavigationBarItem> childItems = null, int indent = 0, bool bolded = false, bool grayed = false)
: base(text, glyph, spans, childItems, indent, bolded, grayed)
{
}
}
}
}
......@@ -4,6 +4,7 @@
using System;
using System.ComponentModel.Composition;
using Microsoft.CodeAnalysis.Editor;
using Microsoft.VisualStudio.ComponentModelHost;
using Microsoft.VisualStudio.LanguageServices.Implementation.Venus;
using Microsoft.VisualStudio.LanguageServices.LiveShare.Client.Debugging;
......@@ -33,7 +34,7 @@ internal class CSharpLspContainedLanguageProvider : IContainedLanguageProvider
public IContentType GetContentType(string filePath)
{
return _contentTypeRegistry.GetContentType(StringConstants.CSharpLspContentTypeName);
return _contentTypeRegistry.GetContentType(ContentTypeNames.CSharpLspContentTypeName);
}
public IVsContainedLanguage GetLanguage(string filePath, IVsTextBufferCoordinator bufferCoordinator)
......
......@@ -8,7 +8,6 @@
using Microsoft.CodeAnalysis.FindUsages;
using Microsoft.CodeAnalysis.LanguageServer;
using Microsoft.VisualStudio.LanguageServices.LiveShare.Protocol;
using Newtonsoft.Json.Linq;
using LSP = Microsoft.VisualStudio.LanguageServer.Protocol;
namespace Microsoft.VisualStudio.LanguageServices.LiveShare.Client.References
......@@ -24,40 +23,10 @@ public RoslynFindUsagesService(AbstractLspClientServiceFactory roslynLspClientSe
_remoteLanguageServiceWorkspace = remoteLanguageServiceWorkspace ?? throw new ArgumentNullException(nameof(remoteLanguageServiceWorkspace));
}
public async Task FindImplementationsAsync(Document document, int position, IFindUsagesContext context)
public Task FindImplementationsAsync(Document document, int position, IFindUsagesContext context)
{
var text = await document.GetTextAsync().ConfigureAwait(false);
var lspClient = _roslynLspClientServiceFactory.ActiveLanguageServerClient;
if (lspClient == null)
{
return;
}
var documentPositionParams = ProtocolConversions.PositionToTextDocumentPositionParams(position, text, document);
var response = await lspClient.RequestAsync(LSP.Methods.TextDocumentImplementation.ToLSRequest(), documentPositionParams, context.CancellationToken).ConfigureAwait(false);
var locations = ((JToken)response)?.ToObject<LSP.Location[]>();
if (locations == null)
{
return;
}
foreach (var location in locations)
{
var documentSpan = await _remoteLanguageServiceWorkspace.GetDocumentSpanFromLocation(location, context.CancellationToken).ConfigureAwait(false);
if (documentSpan == null)
{
continue;
}
// Get the text for the line containing the definition to show in the UI.
var docText = await documentSpan.Value.Document.GetTextAsync(context.CancellationToken).ConfigureAwait(false);
var lineText = docText.GetSubText(docText.Lines[location.Range.Start.Line].Span).ToString();
await context.OnDefinitionFoundAsync(DefinitionItem.Create(ImmutableArray<string>.Empty,
ImmutableArray.Create(new TaggedText(TextTags.Text, lineText)), documentSpan.Value)).ConfigureAwait(false);
}
// Find implementations is now handled by the VS LSP client.
return Task.CompletedTask;
}
public async Task FindReferencesAsync(Document document, int position, IFindUsagesContext context)
......
......@@ -12,6 +12,7 @@
using Task = System.Threading.Tasks.Task;
using LS = Microsoft.VisualStudio.LiveShare.LanguageServices;
using Microsoft.VisualStudio.Shell;
using Microsoft.CodeAnalysis.Editor;
namespace Microsoft.VisualStudio.LanguageServices.LiveShare.Client
{
......@@ -85,32 +86,15 @@ public Task<ICollaborationService> CreateServiceAsync(CollaborationSession colla
})));
languageServerGuestService.RegisterClientMetadata(
new string[] { StringConstants.CSharpLspContentTypeName, StringConstants.VBLspLanguageName },
new string[] { ContentTypeNames.CSharpLspContentTypeName, ContentTypeNames.VBLspContentTypeName },
new LS.LanguageServerClientMetadata(
true,
JObject.FromObject(new ServerCapabilities
{
// Uses Roslyn client.
DocumentOnTypeFormattingProvider = new DocumentOnTypeFormattingOptions(),
DocumentRangeFormattingProvider = true,
DocumentFormattingProvider = true,
DocumentSymbolProvider = true,
CodeActionProvider = true,
ExecuteCommandProvider = new ExecuteCommandOptions(),
DocumentHighlightProvider = true,
ReferencesProvider = true,
DefinitionProvider = true,
SignatureHelpProvider = new SignatureHelpOptions() { },
CompletionProvider = new CompletionOptions(),
ImplementationProvider = true,
// Uses LSP SDK client.
DocumentLinkProvider = null,
RenameProvider = false,
CodeLensProvider = null,
WorkspaceSymbolProvider = false,
HoverProvider = false,
TextDocumentSync = null,
})));
var lifeTimeService = LspClientLifeTimeService;
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Composition;
using Microsoft.CodeAnalysis.SignatureHelp;
namespace Microsoft.VisualStudio.LanguageServices.LiveShare.Client.SignatureHelp
{
[Shared]
[ExportSignatureHelpProvider("CSharpLspSignatureHelpProvider", StringConstants.CSharpLspLanguageName)]
internal class CSharpLspSignatureHelpProvider : RoslynSignatureHelpProvider
{
[ImportingConstructor]
public CSharpLspSignatureHelpProvider(CSharpLspClientServiceFactory csharpLspClientServiceFactory)
: base(csharpLspClientServiceFactory)
{
}
}
[Shared]
[ExportSignatureHelpProvider("VBLspSignatureHelpProvider", StringConstants.VBLspLanguageName)]
internal class VBLspSignatureHelpProvider : RoslynSignatureHelpProvider
{
[ImportingConstructor]
public VBLspSignatureHelpProvider(VisualBasicLspClientServiceFactory vbLspClientServiceFactory)
: base(vbLspClientServiceFactory)
{
}
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.LanguageServer;
using Microsoft.CodeAnalysis.SignatureHelp;
using Microsoft.VisualStudio.LanguageServer.Protocol;
using Microsoft.VisualStudio.LanguageServices.LiveShare.Protocol;
namespace Microsoft.VisualStudio.LanguageServices.LiveShare.Client.SignatureHelp
{
class RoslynSignatureHelpProvider : ISignatureHelpProvider
{
private readonly AbstractLspClientServiceFactory _roslynLspClientServiceFactory;
public RoslynSignatureHelpProvider(AbstractLspClientServiceFactory roslynLspClientServiceFactory)
{
_roslynLspClientServiceFactory = roslynLspClientServiceFactory ?? throw new ArgumentNullException(nameof(roslynLspClientServiceFactory));
}
public bool IsTriggerCharacter(char ch)
{
return ch == '(' || ch == ',';
}
public bool IsRetriggerCharacter(char ch)
{
return ch == ')';
}
public async Task<SignatureHelpItems> GetItemsAsync(Document document, int position, SignatureHelpTriggerInfo triggerInfo, CancellationToken cancellationToken)
{
// This provider is exported for all workspaces - so limit it to just our workspace.
if (document.Project.Solution.Workspace.Kind != WorkspaceKind.AnyCodeRoslynWorkspace)
{
return null;
}
var lspClient = _roslynLspClientServiceFactory.ActiveLanguageServerClient;
if (lspClient == null)
{
return null;
}
var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false);
var textDocumentPositionParams = ProtocolConversions.PositionToTextDocumentPositionParams(position, text, document);
var signatureHelp = await lspClient.RequestAsync(Methods.TextDocumentSignatureHelp.ToLSRequest(), textDocumentPositionParams, cancellationToken).ConfigureAwait(false);
if (signatureHelp == null || signatureHelp.Signatures == null || signatureHelp.Signatures.Length <= 0)
{
return null;
}
var items = new List<SignatureHelpItem>();
foreach (var signature in signatureHelp.Signatures)
{
items.Add(CreateSignatureHelpItem(signature));
}
var linePosition = text.Lines.GetLinePosition(position);
var applicableSpan = text.Lines.GetTextSpan(new CodeAnalysis.Text.LinePositionSpan(linePosition, linePosition));
return new SignatureHelpItems(items, applicableSpan, signatureHelp.ActiveParameter, signatureHelp.ActiveParameter, null, signatureHelp.ActiveSignature);
}
private SignatureHelpItem CreateSignatureHelpItem(SignatureInformation signatureInformation)
{
var signatureText = signatureInformation.Label;
var emptyText = ToTaggedText(string.Empty);
var parameters = signatureInformation.Parameters.Select(parameter =>
{
Func<CancellationToken, IEnumerable<TaggedText>> paramDocumentationFactory = (ct) => ToTaggedText(parameter.Documentation?.Value);
return new SignatureHelpParameter((string)parameter.Label, false, paramDocumentationFactory, emptyText);
});
return new SignatureHelpItem(false, DocumentationFactory, ToTaggedText(signatureInformation.Label), emptyText, emptyText, parameters, emptyText);
// local functions
IEnumerable<TaggedText> DocumentationFactory(CancellationToken ct) => ToTaggedText(signatureInformation.Documentation?.Value);
}
private IEnumerable<TaggedText> ToTaggedText(string text)
{
return ImmutableArray.Create(new TaggedText(TextTags.Text, text ?? string.Empty));
}
}
}
......@@ -19,10 +19,8 @@ internal class StringConstants
public const string AnyProviderName = "any";
public const string CSharpLspLanguageName = "C#_LSP";
public const string CSharpLspContentTypeName = "C#_LSP";
public const string TypeScriptLanguageName = "TypeScript";
public const string VBLspLanguageName = "VB_LSP";
public const string VBLspContentTypeName = "VB_LSP";
public const string CSharpLspPackageGuidString = "BB7E83F4-EAF6-456C-B140-F8C027A7ED8A";
public const string CSharpLspLanguageServiceGuidString = "B7B576C5-24AE-4FBB-965E-382125FD4889";
......
......@@ -3,6 +3,7 @@
using System;
using System.ComponentModel.Composition;
using System.Diagnostics;
using Microsoft.CodeAnalysis.Editor;
using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.Text.Editor;
using Microsoft.VisualStudio.Text.Tagging;
......@@ -17,7 +18,7 @@ namespace Microsoft.VisualStudio.LanguageServices.LiveShare.Client.Tagger
[Export(typeof(ITaggerProvider))]
[PartCreationPolicy(CreationPolicy.Shared)]
[TagType(typeof(IClassificationTag))]
[ContentType(StringConstants.CSharpLspContentTypeName)]
[ContentType(ContentTypeNames.CSharpLspContentTypeName)]
[TextViewRole(PredefinedTextViewRoles.Document)]
internal sealed class CSharpModeAwareSyntacticClassificationTaggerProvider : ModeAwareSyntacticClassificationTaggerProvider
{
......@@ -34,7 +35,7 @@ internal sealed class CSharpModeAwareSyntacticClassificationTaggerProvider : Mod
[Export(typeof(ITaggerProvider))]
[PartCreationPolicy(CreationPolicy.Shared)]
[TagType(typeof(IClassificationTag))]
[ContentType(StringConstants.VBLspContentTypeName)]
[ContentType(ContentTypeNames.VBLspContentTypeName)]
[TextViewRole(PredefinedTextViewRoles.Document)]
internal sealed class VBModeAwareSyntacticClassificationTaggerProvider : ModeAwareSyntacticClassificationTaggerProvider
{
......
......@@ -3,6 +3,7 @@
using System;
using System.ComponentModel.Composition;
using System.Diagnostics;
using Microsoft.CodeAnalysis.Editor;
using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.Text.Editor;
using Microsoft.VisualStudio.Text.Tagging;
......@@ -17,7 +18,7 @@ namespace Microsoft.VisualStudio.LanguageServices.LiveShare.Client.Tagger
[Export(typeof(IViewTaggerProvider))]
[PartCreationPolicy(CreationPolicy.Shared)]
[TagType(typeof(IClassificationTag))]
[ContentType(StringConstants.CSharpLspContentTypeName)]
[ContentType(ContentTypeNames.CSharpLspContentTypeName)]
[TextViewRole(PredefinedTextViewRoles.Document)]
internal sealed class CSharpModeAwareSyntacticClassificationViewTaggerProvider : ModeAwareSyntacticClassificationViewTaggerProvider
{
......@@ -34,7 +35,7 @@ internal sealed class CSharpModeAwareSyntacticClassificationViewTaggerProvider :
[Export(typeof(IViewTaggerProvider))]
[PartCreationPolicy(CreationPolicy.Shared)]
[TagType(typeof(IClassificationTag))]
[ContentType(StringConstants.VBLspContentTypeName)]
[ContentType(ContentTypeNames.VBLspContentTypeName)]
[TextViewRole(PredefinedTextViewRoles.Document)]
internal sealed class VBModeAwareSyntacticClassificationViewTaggerProvider : ModeAwareSyntacticClassificationViewTaggerProvider
{
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Immutable;
using System.ComponentModel.Composition;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.VisualStudio.LiveShare.LanguageServices;
using CustomMethods = Microsoft.VisualStudio.LiveShare.LanguageServices.Protocol.CustomMethods;
namespace Microsoft.VisualStudio.LanguageServices.LiveShare
{
[Export(LiveShareConstants.RoslynContractName, typeof(ILspNotificationProvider))]
[ExportLspRequestHandler(LiveShareConstants.RoslynContractName, CustomMethods.GetDocumentDiagnosticsName)]
[Obsolete("Used for backwards compatibility with old liveshare clients.")]
internal class RoslynDiagnosticsHandler : DiagnosticsHandler
{
[ImportingConstructor]
public RoslynDiagnosticsHandler(IDiagnosticService diagnosticService)
: base(diagnosticService)
{
}
protected override ImmutableArray<string> SupportedLanguages => ImmutableArray.Create(LanguageNames.CSharp, LanguageNames.VisualBasic);
}
[Export(LiveShareConstants.CSharpContractName, typeof(ILspNotificationProvider))]
[ExportLspRequestHandler(LiveShareConstants.CSharpContractName, CustomMethods.GetDocumentDiagnosticsName)]
internal class CSharpDiagnosticsHandler : DiagnosticsHandler
{
[ImportingConstructor]
public CSharpDiagnosticsHandler(IDiagnosticService diagnosticService)
: base(diagnosticService)
{
}
protected override ImmutableArray<string> SupportedLanguages => ImmutableArray.Create(LanguageNames.CSharp);
}
[Export(LiveShareConstants.VisualBasicContractName, typeof(ILspNotificationProvider))]
[ExportLspRequestHandler(LiveShareConstants.VisualBasicContractName, CustomMethods.GetDocumentDiagnosticsName)]
internal class VisualBasicDiagnosticsHandler : DiagnosticsHandler
{
[ImportingConstructor]
public VisualBasicDiagnosticsHandler(IDiagnosticService diagnosticService)
: base(diagnosticService)
{
}
protected override ImmutableArray<string> SupportedLanguages => ImmutableArray.Create(LanguageNames.VisualBasic);
}
/// <summary>
/// <see cref="LiveShareConstants.RoslynLSPSDKContractName"/> is only used for typescript.
/// </summary>
[Export(LiveShareConstants.RoslynLSPSDKContractName, typeof(ILspNotificationProvider))]
[ExportLspRequestHandler(LiveShareConstants.RoslynLSPSDKContractName, CustomMethods.GetDocumentDiagnosticsName)]
internal class RoslynLSPSDKDiagnosticsHandler : DiagnosticsHandler
{
[ImportingConstructor]
public RoslynLSPSDKDiagnosticsHandler(IDiagnosticService diagnosticService)
: base(diagnosticService)
{
}
protected override ImmutableArray<string> SupportedLanguages => ImmutableArray.Create("TypeScript");
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Immutable;
using System.ComponentModel.Composition;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.ErrorReporting;
using Microsoft.CodeAnalysis.LanguageServer;
using Microsoft.VisualStudio.LanguageServices.LiveShare.CustomProtocol;
using Microsoft.VisualStudio.LanguageServices.LiveShare.Protocol;
using Microsoft.VisualStudio.LiveShare.LanguageServices;
using Microsoft.VisualStudio.Threading;
using LSP = Microsoft.VisualStudio.LanguageServer.Protocol;
namespace Microsoft.VisualStudio.LanguageServices.LiveShare
{
/// <summary>
/// Handles a request to get diagnostics. This is a custom request that is issued on document
/// open. This type also provides notifications when diagnostics change.
/// TODO - Move implementation to lower LSP layer once we figure out how to deal with notify / client interactions.
/// </summary>
internal abstract class DiagnosticsHandler : ILspRequestHandler<TextDocumentParams, LSP.Diagnostic[], Solution>, ILspNotificationProvider
{
private readonly IDiagnosticService _diagnosticService;
protected abstract ImmutableArray<string> SupportedLanguages { get; }
public event AsyncEventHandler<LanguageServiceNotifyEventArgs> NotifyAsync;
[ImportingConstructor]
public DiagnosticsHandler(IDiagnosticService diagnosticService)
{
_diagnosticService = diagnosticService ?? throw new ArgumentNullException(nameof(diagnosticService));
_diagnosticService.DiagnosticsUpdated += DiagnosticService_DiagnosticsUpdated;
}
#pragma warning disable VSTHRD100 // Avoid async void methods
private async void DiagnosticService_DiagnosticsUpdated(object sender, DiagnosticsUpdatedArgs e)
#pragma warning restore VSTHRD100 // Avoid async void methods
{
// Since this is an async void method, exceptions here will crash the host VS. We catch exceptions here to make sure that we don't crash the host since
// the worst outcome here is that guests may not see all diagnostics.
try
{
// LSP doesnt support diagnostics without a document. So if we get project level diagnostics without a document, ignore them.
if (e.DocumentId != null && e.Solution != null)
{
var document = e.Solution.GetDocument(e.DocumentId);
if (document == null || document.FilePath == null)
{
return;
}
// Only publish document diagnostics for the languages this provider supports.
if (!SupportedLanguages.Contains(document.Project.Language))
{
return;
}
var lspDiagnostics = await GetDiagnosticsAsync(e.Solution, document, CancellationToken.None).ConfigureAwait(false);
var publishDiagnosticsParams = new LSP.PublishDiagnosticParams { Diagnostics = lspDiagnostics, Uri = document.GetURI() };
var eventArgs = new LanguageServiceNotifyEventArgs(LSP.Methods.TextDocumentPublishDiagnosticsName, publishDiagnosticsParams);
await (NotifyAsync?.InvokeAsync(this, eventArgs)).ConfigureAwait(false);
}
}
catch (Exception ex) when (FatalError.ReportWithoutCrash(ex))
{
}
}
public async Task<LSP.Diagnostic[]> HandleAsync(TextDocumentParams request, RequestContext<Solution> requestContext, CancellationToken cancellationToken)
{
var solution = requestContext.Context;
var document = solution.GetDocumentFromURI(request.TextDocument.Uri);
if (document == null)
{
return Array.Empty<LSP.Diagnostic>();
}
return await GetDiagnosticsAsync(solution, document, cancellationToken).ConfigureAwait(false);
}
private async Task<LSP.Diagnostic[]> GetDiagnosticsAsync(Solution solution, Document document, CancellationToken cancellationToken)
{
var diagnostics = _diagnosticService.GetDiagnostics(solution.Workspace, document.Project.Id, document.Id, null, false, cancellationToken);
var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false);
return diagnostics.Select(diag => new RoslynDiagnostic
{
Code = diag.Id,
Message = diag.Message,
Severity = ProtocolConversions.DiagnosticSeverityToLspDiagnositcSeverity(diag.Severity),
Range = ProtocolConversions.TextSpanToRange(DiagnosticData.GetExistingOrCalculatedTextSpan(diag.DataLocation, text), text),
Tags = diag.CustomTags.Where(s => s == "Unnecessary").ToArray()
}).ToArray();
}
}
}
......@@ -20,6 +20,8 @@
namespace Microsoft.VisualStudio.LanguageServices.LiveShare
{
// TODO - This should move to the ILanguageClient when we remove the UI thread dependency.
// https://github.com/dotnet/roslyn/issues/38477
internal class FindAllReferencesHandler : ILspRequestHandler<LSP.ReferenceParams, object[], Solution>
{
private readonly IThreadingContext _threadingContext;
......
......@@ -28,10 +28,9 @@ public async Task<LSP.TextEdit[]> HandleAsync(RunCodeActionParams request, Reque
var edits = ArrayBuilder<LSP.TextEdit>.GetInstance();
var solution = requestContext.Context;
var codeActions = await GetCodeActionsAsync(solution,
request.CodeActionParams.TextDocument.Uri,
request.CodeActionParams.Range,
keepThreadContext: false,
cancellationToken).ConfigureAwait(false);
request.CodeActionParams.TextDocument.Uri,
request.CodeActionParams.Range,
cancellationToken).ConfigureAwait(false);
var actionToRun = codeActions?.FirstOrDefault(a => a.Title == request.Title);
......
......@@ -57,7 +57,7 @@ public override async Task<ResponseType> HandleAsync(RequestType param, RequestC
/// </summary>
private Task<ResponseType> HandleAsyncPreserveThreadContext(RequestType param, RequestContext<Solution> requestContext, CancellationToken cancellationToken)
{
return ((IRequestHandler<RequestType, ResponseType>)LazyRequestHandler.Value).HandleRequestAsync(requestContext.Context, param, requestContext.ClientCapabilities?.ToObject<ClientCapabilities>(), cancellationToken, keepThreadContext: true);
return ((IRequestHandler<RequestType, ResponseType>)LazyRequestHandler.Value).HandleRequestAsync(requestContext.Context, param, requestContext.ClientCapabilities?.ToObject<ClientCapabilities>(), cancellationToken);
}
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Linq;
using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces;
using Microsoft.VisualStudio.LiveShare.LanguageServices;
using Xunit;
namespace Microsoft.VisualStudio.LanguageServices.LiveShare.UnitTests
{
public class LiveShareRequestHandlerShimsTests : AbstractLiveShareRequestHandlerTests
{
// For now we're just testing that the right liveshare handlers are exported.
// This ensures that for shims the right handler is found from roslyn handlers.
// Functionality will be tested in the code analysis language server layer.
[Fact]
public void TestLiveShareRequestHandlersExported()
{
var (solution, _) = CreateTestSolution(string.Empty);
var workspace = (TestWorkspace)solution.Workspace;
var handlers = workspace.ExportProvider.GetExportedValues<ILspRequestHandler>(LiveShareConstants.RoslynContractName).ToArray();
// Verify there are exactly the number of liveshare request handlers as expected.
// Liveshare shims will verify there is a matching roslyn request handler when they are created.
Assert.Equal(21, handlers.Length);
}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册