From 966081a8ec14a0e9d918e4b2ce74701cb1e2420d Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Sat, 13 Jan 2018 13:45:47 -0800 Subject: [PATCH] Make json highlighting into an actual brace highlighting. --- .../BraceMatching/CSharpJsonBraceMatcher.cs | 15 ++++ .../BraceMatching/CSharpRegexBraceMatcher.cs | 14 +--- .../BraceMatching/CommonJsonBraceMatcher.cs} | 70 ++++++------------- .../BraceMatching/CommonRegexBraceMatcher.cs | 12 +++- .../VisualBasicRegexBraceMatcher.vb | 11 +-- .../VisualBasicJsonBraceMatcher.vb | 16 +++++ .../AbstractDocumentHighlightsService.cs | 8 +-- 7 files changed, 68 insertions(+), 78 deletions(-) create mode 100644 src/EditorFeatures/CSharp/BraceMatching/CSharpJsonBraceMatcher.cs rename src/{Features/Core/Portable/DocumentHighlighting/AbstractDocumentHighlightsService_Json.cs => EditorFeatures/Core/Implementation/BraceMatching/CommonJsonBraceMatcher.cs} (53%) create mode 100644 src/EditorFeatures/VisualBasic/VisualBasicJsonBraceMatcher.vb diff --git a/src/EditorFeatures/CSharp/BraceMatching/CSharpJsonBraceMatcher.cs b/src/EditorFeatures/CSharp/BraceMatching/CSharpJsonBraceMatcher.cs new file mode 100644 index 00000000000..d5744b3f90b --- /dev/null +++ b/src/EditorFeatures/CSharp/BraceMatching/CSharpJsonBraceMatcher.cs @@ -0,0 +1,15 @@ +// 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.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Editor.Implementation.BraceMatching; + +namespace Microsoft.CodeAnalysis.Editor.CSharp.BraceMatching +{ + [ExportBraceMatcher(LanguageNames.CSharp)] + internal class CSharpJsonBraceMatcher : IBraceMatcher + { + public Task FindBracesAsync(Document document, int position, CancellationToken cancellationToken) + => CommonJsonBraceMatcher.FindBracesAsync(document, position, cancellationToken); + } +} diff --git a/src/EditorFeatures/CSharp/BraceMatching/CSharpRegexBraceMatcher.cs b/src/EditorFeatures/CSharp/BraceMatching/CSharpRegexBraceMatcher.cs index ede380c6eab..08de2e25603 100644 --- a/src/EditorFeatures/CSharp/BraceMatching/CSharpRegexBraceMatcher.cs +++ b/src/EditorFeatures/CSharp/BraceMatching/CSharpRegexBraceMatcher.cs @@ -10,17 +10,7 @@ namespace Microsoft.CodeAnalysis.Editor.CSharp.BraceMatching [ExportBraceMatcher(LanguageNames.CSharp)] internal class CSharpRegexBraceMatcher : IBraceMatcher { - public async Task FindBracesAsync(Document document, int position, CancellationToken cancellationToken = default) - { - var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); - var token = root.FindToken(position); - if (token.Kind() != SyntaxKind.StringLiteralToken) - { - return null; - } - - return await CommonRegexBraceMatcher.FindBracesAsync( - document, token, position, cancellationToken).ConfigureAwait(false); - } + public Task FindBracesAsync(Document document, int position, CancellationToken cancellationToken) + => CommonRegexBraceMatcher.FindBracesAsync(document, position, cancellationToken); } } diff --git a/src/Features/Core/Portable/DocumentHighlighting/AbstractDocumentHighlightsService_Json.cs b/src/EditorFeatures/Core/Implementation/BraceMatching/CommonJsonBraceMatcher.cs similarity index 53% rename from src/Features/Core/Portable/DocumentHighlighting/AbstractDocumentHighlightsService_Json.cs rename to src/EditorFeatures/Core/Implementation/BraceMatching/CommonJsonBraceMatcher.cs index cd5978ee03d..d77c8ed062f 100644 --- a/src/Features/Core/Portable/DocumentHighlighting/AbstractDocumentHighlightsService_Json.cs +++ b/src/EditorFeatures/Core/Implementation/BraceMatching/CommonJsonBraceMatcher.cs @@ -1,7 +1,5 @@ // 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.Json; @@ -10,11 +8,11 @@ using Microsoft.CodeAnalysis.VirtualChars; using Roslyn.Utilities; -namespace Microsoft.CodeAnalysis.DocumentHighlighting +namespace Microsoft.CodeAnalysis.Editor.Implementation.BraceMatching { - internal abstract partial class AbstractDocumentHighlightsService : IDocumentHighlightsService + internal static class CommonJsonBraceMatcher { - private async Task> TryGetJsonHighlightsAsync( + internal static async Task FindBracesAsync( Document document, int position, CancellationToken cancellationToken) { var option = document.Project.Solution.Workspace.Options.GetOption(JsonOptions.HighlightRelatedJsonComponentsUnderCursor, document.Project.Language); @@ -46,79 +44,53 @@ internal abstract partial class AbstractDocumentHighlightsService : IDocumentHig return default; } - return GetHighlights(document, tree, position); + return GetMatchingBraces(tree, position); } - private ImmutableArray GetHighlights( - Document document, JsonTree tree, int position) - { - var bracesOnTheRight = GetHighlights(document, tree, position, caretOnLeft: true); - var bracesOnTheLeft = GetHighlights(document, tree, position - 1, caretOnLeft: false); - - if (!bracesOnTheRight.IsEmpty) - { - // We were on the left of an open open. Return these highlights, and any - // highlights if we were on the right of a close paren. - return bracesOnTheRight.Concat(bracesOnTheLeft); - } - - // Nothing was on the right of the caret. Return anything we were able to find on - // the left of the caret - return bracesOnTheLeft; - } - - private ImmutableArray GetHighlights( - Document document, JsonTree tree, int position, bool caretOnLeft) + private static BraceMatchingResult? GetMatchingBraces(JsonTree tree, int position) { var virtualChar = tree.Text.FirstOrNullable(vc => vc.Span.Contains(position)); if (virtualChar == null) { - return ImmutableArray.Empty; + return null; } var ch = virtualChar.Value; - if (caretOnLeft) - { - return ch == '{' || ch == '[' || ch == '(' - ? FindBraceHighlights(document, tree, ch) - : ImmutableArray.Empty; - } - else + if (ch == '{' || ch == '[' || ch == '(' || + ch == '}' || ch == ']' || ch == ')') { - return ch == '}' || ch == ']' || ch == ')' - ? FindBraceHighlights(document, tree, ch) - : ImmutableArray.Empty; + return FindBraceHighlights(tree, ch); } + + return null; } - private ImmutableArray FindBraceHighlights( - Document document, JsonTree tree, VirtualChar ch) + private static BraceMatchingResult? FindBraceHighlights(JsonTree tree, VirtualChar ch) { var node = FindObjectOrArrayNode(tree.Root, ch); switch (node) { - case JsonObjectNode obj: return Create(document, obj.OpenBraceToken, obj.CloseBraceToken); - case JsonArrayNode array: return Create(document, array.OpenBracketToken, array.CloseBracketToken); - case JsonConstructorNode cons: return Create(document, cons.OpenParenToken, cons.CloseParenToken); + case JsonObjectNode obj: return Create(obj.OpenBraceToken, obj.CloseBraceToken); + case JsonArrayNode array: return Create(array.OpenBracketToken, array.CloseBracketToken); + case JsonConstructorNode cons: return Create(cons.OpenParenToken, cons.CloseParenToken); } return default; } - private ImmutableArray Create(Document document, JsonToken open, JsonToken close) + private static BraceMatchingResult? Create(JsonToken open, JsonToken close) { if (open.IsMissing || close.IsMissing) { return default; } - return ImmutableArray.Create(new DocumentHighlights( - document, ImmutableArray.Create( - new HighlightSpan(JsonHelpers.GetSpan(open), HighlightSpanKind.None), - new HighlightSpan(JsonHelpers.GetSpan(close), HighlightSpanKind.None)))); + return new BraceMatchingResult( + JsonHelpers.GetSpan(open), + JsonHelpers.GetSpan(close)); } - private JsonValueNode FindObjectOrArrayNode(JsonNode node, VirtualChar ch) + private static JsonValueNode FindObjectOrArrayNode(JsonNode node, VirtualChar ch) { switch (node) { @@ -147,7 +119,7 @@ private JsonValueNode FindObjectOrArrayNode(JsonNode node, VirtualChar ch) return null; } - private bool Matches(JsonToken openToken, JsonToken closeToken, VirtualChar ch) + private static bool Matches(JsonToken openToken, JsonToken closeToken, VirtualChar ch) => openToken.VirtualChars.Contains(ch) || closeToken.VirtualChars.Contains(ch); } } diff --git a/src/EditorFeatures/Core/Implementation/BraceMatching/CommonRegexBraceMatcher.cs b/src/EditorFeatures/Core/Implementation/BraceMatching/CommonRegexBraceMatcher.cs index b8fb973f110..1dbf66aa308 100644 --- a/src/EditorFeatures/Core/Implementation/BraceMatching/CommonRegexBraceMatcher.cs +++ b/src/EditorFeatures/Core/Implementation/BraceMatching/CommonRegexBraceMatcher.cs @@ -13,8 +13,18 @@ namespace Microsoft.CodeAnalysis.Editor.Implementation.BraceMatching internal static class CommonRegexBraceMatcher { internal static async Task FindBracesAsync( - Document document, SyntaxToken token, int position, CancellationToken cancellationToken) + Document document, int position, CancellationToken cancellationToken) { + var option = document.Project.Solution.Workspace.Options.GetOption( + RegularExpressionsOptions.HighlightRelatedRegexComponentsUnderCursor, document.Project.Language); + if (!option) + { + return default; + } + + var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); + var token = root.FindToken(position); + var syntaxFacts = document.GetLanguageService(); if (RegexPatternDetector.IsDefinitelyNotPattern(token, syntaxFacts)) { diff --git a/src/EditorFeatures/VisualBasic/BraceMatching/VisualBasicRegexBraceMatcher.vb b/src/EditorFeatures/VisualBasic/BraceMatching/VisualBasicRegexBraceMatcher.vb index f1d248dcd41..feecae3052a 100644 --- a/src/EditorFeatures/VisualBasic/BraceMatching/VisualBasicRegexBraceMatcher.vb +++ b/src/EditorFeatures/VisualBasic/BraceMatching/VisualBasicRegexBraceMatcher.vb @@ -9,15 +9,8 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.BraceMatching Friend Class VisualBasicRegexBraceMatcher Implements IBraceMatcher - Public Async Function FindBracesAsync(document As Document, position As Integer, Optional cancellationToken As CancellationToken = Nothing) As Task(Of BraceMatchingResult?) Implements IBraceMatcher.FindBracesAsync - Dim root = Await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(False) - Dim token = root.FindToken(position) - If token.Kind() <> SyntaxKind.StringLiteralToken Then - Return Nothing - End If - - Return Await CommonRegexBraceMatcher.FindBracesAsync( - document, token, position, cancellationToken).ConfigureAwait(False) + Public Function FindBracesAsync(document As Document, position As Integer, Optional cancellationToken As CancellationToken = Nothing) As Task(Of BraceMatchingResult?) Implements IBraceMatcher.FindBracesAsync + Return CommonRegexBraceMatcher.FindBracesAsync(document, position, cancellationToken) End Function End Class End Namespace diff --git a/src/EditorFeatures/VisualBasic/VisualBasicJsonBraceMatcher.vb b/src/EditorFeatures/VisualBasic/VisualBasicJsonBraceMatcher.vb new file mode 100644 index 00000000000..5fc4a7606da --- /dev/null +++ b/src/EditorFeatures/VisualBasic/VisualBasicJsonBraceMatcher.vb @@ -0,0 +1,16 @@ +' Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +Imports System.Threading +Imports System.Threading.Tasks +Imports Microsoft.CodeAnalysis.Editor.Implementation.BraceMatching + +Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.BraceMatching + + Friend Class VisualBasicJsonBraceMatcher + Implements IBraceMatcher + + Public Function FindBracesAsync(document As Document, position As Integer, Optional cancellationToken As CancellationToken = Nothing) As Task(Of BraceMatchingResult?) Implements IBraceMatcher.FindBracesAsync + Return CommonJsonBraceMatcher.FindBracesAsync(document, position, cancellationToken) + End Function + End Class +End Namespace diff --git a/src/Features/Core/Portable/DocumentHighlighting/AbstractDocumentHighlightsService.cs b/src/Features/Core/Portable/DocumentHighlighting/AbstractDocumentHighlightsService.cs index 4f024d6297d..50b6477fcb5 100644 --- a/src/Features/Core/Portable/DocumentHighlighting/AbstractDocumentHighlightsService.cs +++ b/src/Features/Core/Portable/DocumentHighlighting/AbstractDocumentHighlightsService.cs @@ -60,13 +60,7 @@ internal abstract partial class AbstractDocumentHighlightsService : IDocumentHig private async Task> GetDocumentHighlightsInCurrentProcessAsync( Document document, int position, IImmutableSet documentsToSearch, CancellationToken cancellationToken) { - var result = await TryGetJsonHighlightsAsync(document, position, cancellationToken).ConfigureAwait(false); - if (!result.IsDefaultOrEmpty) - { - return result; - } - - result = await TryGetRegexPatternHighlightsAsync(document, position, cancellationToken).ConfigureAwait(false); + var result = await TryGetRegexPatternHighlightsAsync(document, position, cancellationToken).ConfigureAwait(false); if (!result.IsDefaultOrEmpty) { return result; -- GitLab