33namespace Microsoft.VisualStudio.FSharp.Editor
44
55open System
6- open System.Composition
7- open System.Collections .Concurrent
8- open System.Collections .Generic
9- open System.Threading
106open System.Threading .Tasks
11- open System.Linq
12-
13- open Microsoft.CodeAnalysis
14- open Microsoft.CodeAnalysis .Classification
157open Microsoft.CodeAnalysis .Editor
16- open Microsoft.CodeAnalysis .Editor .Implementation .BraceMatching
17- open Microsoft.CodeAnalysis .Editor .Shared .Utilities
18- open Microsoft.CodeAnalysis .Host .Mef
19- open Microsoft.CodeAnalysis .Text
20-
218open Microsoft.VisualStudio .FSharp .LanguageService
22- open Microsoft.VisualStudio .Text
23- open Microsoft.VisualStudio .Text .Tagging
24-
25- open Microsoft.FSharp .Compiler .Parser
269open Microsoft.FSharp .Compiler .SourceCodeServices
2710
28- // FSROSLYNTODO: add defines flags if available from project sites and files
29-
3011[<ExportBraceMatcher( FSharpCommonConstants.FSharpLanguageName) >]
3112type internal FSharpBraceMatchingService () =
32-
33- static let supportedBraceTypes = [
34- ( '(' , ')' );
35- ( '<' , '>' );
36- ( '[' , ']' );
37- ( '{' , '}' );
38- ]
39-
40- static let ignoredClassificationTypes = [
41- ClassificationTypeNames.Comment;
42- ClassificationTypeNames.StringLiteral;
43- ClassificationTypeNames.ExcludedCode;
44- ]
45-
46- static let getBraceMatchingResult ( sourceText : SourceText , fileName : Option < string >, defines : string list , position : int , cancellationToken : CancellationToken ) : Option < BraceMatchingResult > =
47- if position < 0 || position >= sourceText.Length then
48- None
49- else
50- let shouldBeIgnored ( characterPosition ) =
51- let textSpan = TextSpan( characterPosition, 1 )
52- let classifiedSpans = FSharpColorizationService.GetColorizationData( sourceText, textSpan, fileName, defines, cancellationToken)
53- if classifiedSpans.Any() then
54- ignoredClassificationTypes |> Seq.contains ( classifiedSpans.First() .ClassificationType)
55- else
56- false
57-
58- if shouldBeIgnored( position) then
59- None
60- else
61- let currentCharacter = sourceText.[ position]
62-
63- let proceedToStartOfString ( i ) = i - 1
64- let proceedToEndOfString ( i ) = i + 1
6513
66- let afterEndOfString ( i ) = i >= sourceText.Length
67- let beforeStartOfString ( i ) = i < 0
68-
69- let pickBraceType ( leftBrace , rightBrace ) =
70- if currentCharacter = leftBrace then Some( proceedToEndOfString, afterEndOfString, leftBrace, rightBrace)
71- else if currentCharacter = rightBrace then Some( proceedToStartOfString, beforeStartOfString, rightBrace, leftBrace)
72- else None
73-
74- match supportedBraceTypes |> List.tryPick( pickBraceType) with
75- | None -> None
76- | Some( proceedFunc, stoppingCondition, matchedBrace, nonMatchedBrace) ->
77- let mutable currentPosition = proceedFunc position
78- let mutable result = None
79- let mutable braceDepth = 0
80-
81- while result.IsSome = false && stoppingCondition( currentPosition) = false do
82- cancellationToken.ThrowIfCancellationRequested()
83- if shouldBeIgnored( currentPosition) = false then
84- if sourceText.[ currentPosition] = matchedBrace then
85- braceDepth <- braceDepth + 1
86- else if sourceText.[ currentPosition] = nonMatchedBrace then
87- if braceDepth = 0 then
88- result <- Some( BraceMatchingResult( TextSpan( min position currentPosition, 1 ), TextSpan( max position currentPosition, 1 )))
89- else
90- braceDepth <- braceDepth - 1
91- currentPosition <- proceedFunc currentPosition
92- result
14+ static member GetBraceMatchingResult ( sourceText , fileName , options , position ) = async {
15+ let isPositionInRange ( range ) =
16+ let span = CommonRoslynHelpers.FSharpRangeToTextSpan( sourceText, range)
17+ span.Start <= position && position <= span.End
18+ let! matchedBraces = FSharpChecker.Instance.MatchBracesAlternate( fileName, sourceText.ToString(), options)
9319
20+ return matchedBraces |> Seq.tryFind( fun ( left , right ) -> isPositionInRange( left) || isPositionInRange( right))
21+ }
22+
9423 interface IBraceMatcher with
95- member this.FindBracesAsync ( document : Document , position : int , cancellationToken : CancellationToken ): Task < Nullable < BraceMatchingResult >> =
96- document.GetTextAsync( cancellationToken) .ContinueWith(
97- fun ( sourceTextTask : Task < SourceText >) ->
98- if sourceTextTask.Status = TaskStatus.RanToCompletion then
99- try match getBraceMatchingResult( sourceTextTask.Result, Some( document.Name), [], position, cancellationToken) with
100- | None -> Nullable()
101- | Some( braceMatchingResult) -> Nullable( braceMatchingResult)
102- with ex ->
103- Assert.Exception( ex)
104- reraise()
105- else
106- raise( sourceTextTask.Exception.GetBaseException())
107- , cancellationToken)
108-
109- // Helper function to proxy Roslyn types to tests
110- static member FindMatchingBrace ( sourceText : SourceText , fileName : Option < string >, defines : string list , position : int , cancellationToken : CancellationToken ) : Option < int > =
111- match getBraceMatchingResult( sourceText, fileName, defines, position, cancellationToken) with
112- | None -> None
113- | Some( braceMatchingResult) ->
114- if braceMatchingResult.LeftSpan.Start = position then
115- Some( braceMatchingResult.RightSpan.Start)
116- else if braceMatchingResult.RightSpan.Start = position then
117- Some( braceMatchingResult.LeftSpan.Start)
118- else
119- None
24+ member this.FindBracesAsync ( document , position , cancellationToken ) =
25+ let computation = async {
26+ let options = CommonRoslynHelpers.GetFSharpProjectOptionsForRoslynProject( document.Project)
27+ let! sourceText = document.GetTextAsync( cancellationToken) |> Async.AwaitTask
28+ let! result = FSharpBraceMatchingService.GetBraceMatchingResult( sourceText, document.Name, options, position)
29+
30+ return match result with
31+ | None -> Nullable()
32+ | Some( left, right) ->
33+ Nullable( BraceMatchingResult(
34+ CommonRoslynHelpers.FSharpRangeToTextSpan( sourceText, left),
35+ CommonRoslynHelpers.FSharpRangeToTextSpan( sourceText, right)))
36+ }
37+
38+ Async.StartAsTask( computation, TaskCreationOptions.None, cancellationToken)
39+ .ContinueWith( CommonRoslynHelpers.GetCompletedTaskResult, cancellationToken)
0 commit comments