22
33namespace Microsoft.VisualStudio.FSharp.Editor
44
5+ // This implementation does not rely on Roslyn internals.
6+
57open System
68open System.Diagnostics
79open System.Threading
810open System.ComponentModel .Composition
9-
10- open Microsoft.CodeAnalysis
11- open Microsoft.CodeAnalysis .Text
12- open Microsoft.CodeAnalysis .Editor .Shared .Utilities
13- open Microsoft.CodeAnalysis .Host
14- open Microsoft.CodeAnalysis .Host .Mef
15- open Microsoft.CodeAnalysis .Classification
1611open Microsoft.VisualStudio .Text .BraceCompletion
1712open Microsoft.VisualStudio .Text .Operations
1813open Microsoft.VisualStudio .Text
1914open Microsoft.VisualStudio .Text .Editor
2015open Microsoft.VisualStudio .Utilities
16+ open Microsoft.CodeAnalysis
17+ open Microsoft.CodeAnalysis .Text
18+ open Microsoft.CodeAnalysis .Host
19+ open Microsoft.CodeAnalysis .Host .Mef
20+ open Microsoft.CodeAnalysis .Classification
2121
2222[<AutoOpen>]
23- module private FSharpBraceCompletionSessionProviderHelpers =
23+ module BraceCompletionSessionProviderHelpers =
2424
2525let getLanguageService < 'T when 'T :> ILanguageService and 'T : null > ( document : Document ) =
2626match document.Projectwith
@@ -37,11 +37,20 @@ module private FSharpBraceCompletionSessionProviderHelpers =
3737let getCaretPosition session =
3838 session|> getCaretPoint session.SubjectBuffer
3939
40+ let tryInsertAdditionalBracePair ( session : IBraceCompletionSession ) openingChar closingChar =
41+ let sourceCode = session.TextView.TextSnapshot
42+ let position = session.TextView.Caret.Position.BufferPosition.Position
43+ let start = position- 2
44+ let end ' = position
45+
46+ start>= 0 && end'< sourceCode.Length&&
47+ sourceCode.GetText( start, 1 ).[ 0 ] = openingChar&& sourceCode.GetText( end', 1 ).[ 0 ] = closingChar
48+
4049[<Literal>]
4150let BraceCompletion = " Brace_Completion"
4251
4352[<AllowNullLiteral>]
44- type internal IEditorBraceCompletionSession =
53+ type IEditorBraceCompletionSession =
4554inherit ILanguageService
4655
4756abstract CheckOpeningPoint : IBraceCompletionSession * CancellationToken -> bool
@@ -53,12 +62,12 @@ type internal IEditorBraceCompletionSession =
5362abstract AfterReturn : IBraceCompletionSession * CancellationToken -> unit
5463
5564[<AllowNullLiteral>]
56- type internal IEditorBraceCompletionSessionFactory =
65+ type IEditorBraceCompletionSessionFactory =
5766inherit ILanguageService
5867
5968abstract TryCreateSession : Document * openingPosition : int * openingBrace : char * CancellationToken -> IEditorBraceCompletionSession
6069
61- type internal FSharpBraceCompletionSession
70+ type BraceCompletionSession
6271(
6372 textView: ITextView,
6473 subjectBuffer: ITextBuffer,
@@ -74,7 +83,7 @@ type internal FSharpBraceCompletionSession
7483let mutable openingPoint : ITrackingPoint = null
7584let editorOperations = editorOperationsFactoryService.GetEditorOperations( textView)
7685
77- member this .EndSession() =
86+ member __ .EndSession() =
7887 closingPoint<- null
7988 openingPoint<- null
8089
@@ -142,7 +151,7 @@ type internal FSharpBraceCompletionSession
142151
143152 undo.Complete()
144153
145- member this .HasNoForwardTyping( caretPoint : SnapshotPoint , endPoint : SnapshotPoint ) =
154+ member __ .HasNoForwardTyping( caretPoint : SnapshotPoint , endPoint : SnapshotPoint ) =
146155 Debug.Assert( caretPoint.Snapshot= endPoint.Snapshot, " snapshots do not match" )
147156
148157if caretPoint.Snapshot= endPoint.Snapshotthen
@@ -304,31 +313,31 @@ type internal FSharpBraceCompletionSession
304313
305314member __.TextView = textView
306315
307- module private Parenthesis =
316+ module Parenthesis =
308317
309318[<Literal>]
310319let OpenCharacter = '('
311320
312321[<Literal>]
313322let CloseCharacter = ')'
314323
315- module private CurlyBrackets =
324+ module CurlyBrackets =
316325
317326[<Literal>]
318327let OpenCharacter = '{'
319328
320329[<Literal>]
321330let CloseCharacter = '}'
322331
323- module private SquareBrackets =
332+ module SquareBrackets =
324333
325334[<Literal>]
326335let OpenCharacter = '['
327336
328337[<Literal>]
329338let CloseCharacter = ']'
330339
331- module private DoubleQuote =
340+ module DoubleQuote =
332341
333342[<Literal>]
334343let OpenCharacter = '"'
@@ -338,7 +347,7 @@ module private DoubleQuote =
338347
339348(* This is for [| |] and {| |} , since the implementation deals with chars only.
340349 We have to test if there is a { or [ before the cursor position and insert the closing '|'.*)
341- module private VerticalBar =
350+ module VerticalBar =
342351
343352[<Literal>]
344353let OpenCharacter = '|'
@@ -348,7 +357,7 @@ module private VerticalBar =
348357
349358(* This is for attributes [< >] , since the implementation deals with chars only.
350359 We have to test if there is a [ before the cursor position and insert the closing '>'.*)
351- module private AngleBrackets =
360+ module AngleBrackets =
352361
353362[<Literal>]
354363let OpenCharacter = '<'
@@ -357,126 +366,104 @@ module private AngleBrackets =
357366let CloseCharacter = '>'
358367
359368(* For multiline comments like this, since the implementation deals with chars only*)
360- module private Asterisk =
369+ module Asterisk =
361370
362371[<Literal>]
363372let OpenCharacter = '*'
364373
365374[<Literal>]
366375let CloseCharacter = '*'
367376
368-
369- type internal ParenthesisCompletionSession () =
377+ type ParenthesisCompletionSession () =
370378
371379interface IEditorBraceCompletionSessionwith
372380
373- member this .AfterReturn( _session , _cancellationToken ) =
381+ member __ .AfterReturn( _session , _cancellationToken ) =
374382()
375383
376- member this .AfterStart( _session , _cancellationToken ) =
384+ member __ .AfterStart( _session , _cancellationToken ) =
377385()
378386
379- member this.AllowOverType ( _session , _cancellationToken ) =
380- // TODO: Implement this for F#
387+ member __.AllowOverType ( _session , _cancellationToken ) =
381388true
382389
383- member this.CheckOpeningPoint ( _session , _cancellationToken ) =
384- // TODO: Implement this for F#
390+ member __.CheckOpeningPoint ( _session , _cancellationToken ) =
385391true
386392
387- type internal DoubleQuoteCompletionSession () =
393+ type DoubleQuoteCompletionSession () =
388394
389395interface IEditorBraceCompletionSessionwith
390396
391- member this .AfterReturn( _session , _cancellationToken ) =
397+ member __ .AfterReturn( _session , _cancellationToken ) =
392398()
393399
394- member this .AfterStart( _session , _cancellationToken ) =
400+ member __ .AfterStart( _session , _cancellationToken ) =
395401()
396402
397- member this.AllowOverType ( _session , _cancellationToken ) =
398- // TODO: Implement this for F#
403+ member __.AllowOverType ( _session , _cancellationToken ) =
399404true
400405
401- member this.CheckOpeningPoint ( _session , _cancellationToken ) =
402- // TODO: Implement this for F#
406+ member __.CheckOpeningPoint ( _session , _cancellationToken ) =
403407true
404408
405- type internal VerticalBarCompletionSession () =
409+ type VerticalBarCompletionSession () =
406410
407411interface IEditorBraceCompletionSessionwith
408412
409- member this .AfterReturn( _session , _cancellationToken ) =
413+ member __ .AfterReturn( _session , _cancellationToken ) =
410414()
411415
412- member this .AfterStart( _session , _cancellationToken ) =
416+ member __ .AfterStart( _session , _cancellationToken ) =
413417()
414418
415- member this.AllowOverType ( _session , _cancellationToken ) =
416- // TODO: Implement this for F#
419+ member __.AllowOverType ( _session , _cancellationToken ) =
417420true
418421
419422(* This is for [| |] and {| |} , since the implementation deals with chars only.
420423 We have to test if there is a { or [ before the cursor position and insert the closing '|'.*)
421- member this.CheckOpeningPoint ( _session , _cancellationToken ) =
422- let sourceCode = _ session.TextView.TextSnapshot
423- //let document = _session.TextView.TextSnapshot.GetOpenDocumentInCurrentContextWithChanges()
424- let position = _ session.TextView.Caret.Position.BufferPosition.Position
425- let ret = position-2 >= 0 && position< sourceCode.Length&&
426- ( sourceCode.GetText( position-2 , 1 ) = " {" && sourceCode.GetText( position, 1 ) = " }"
427- || sourceCode.GetText( position-2 , 1 ) = " [" && sourceCode.GetText( position, 1 ) = " ]" )
428- ret
429-
430- type internal AngleBracketCompletionSession () =
424+ member __.CheckOpeningPoint ( session , _cancellationToken ) =
425+ tryInsertAdditionalBracePair session CurlyBrackets.OpenCharacter CurlyBrackets.CloseCharacter||
426+ tryInsertAdditionalBracePair session SquareBrackets.OpenCharacter SquareBrackets.CloseCharacter
427+
428+ type AngleBracketCompletionSession () =
431429
432430interface IEditorBraceCompletionSessionwith
433431
434- member this .AfterReturn( _session , _cancellationToken ) =
432+ member __ .AfterReturn( _session , _cancellationToken ) =
435433()
436434
437- member this .AfterStart( _session , _cancellationToken ) =
435+ member __ .AfterStart( _session , _cancellationToken ) =
438436()
439437
440- member this.AllowOverType ( _session , _cancellationToken ) =
441- // TODO: Implement this for F#
438+ member __.AllowOverType ( _session , _cancellationToken ) =
442439true
443440
444441(* This is for attributes [< >] , since the implementation deals with chars only.
445442 We have to test if there is a [ before the cursor position and insert the closing '>'.*)
446- member this.CheckOpeningPoint ( _session , _cancellationToken ) =
447- let sourceCode = _ session.TextView.TextSnapshot
448- let position = _ session.TextView.Caret.Position.BufferPosition.Position
449- let ret = position-2 >= 0 && position< sourceCode.Length&&
450- sourceCode.GetText( position-2 , 1 ) .Equals( " [" ) && sourceCode.GetText( position, 1 ) .Equals( " ]" )
451- ret
443+ member __.CheckOpeningPoint ( session , _cancellationToken ) =
444+ tryInsertAdditionalBracePair session SquareBrackets.OpenCharacter SquareBrackets.CloseCharacter
452445
453446(* For multi-line comments, test if it is between "()"*)
454- type internal AsteriskCompletionSession () =
447+ type AsteriskCompletionSession () =
455448
456449interface IEditorBraceCompletionSessionwith
457450
458- member this .AfterReturn( _session , _cancellationToken ) =
451+ member __ .AfterReturn( _session , _cancellationToken ) =
459452()
460453
461- member this .AfterStart( _session , _cancellationToken ) =
454+ member __ .AfterStart( _session , _cancellationToken ) =
462455()
463456
464- member this.AllowOverType ( _session , _cancellationToken ) =
465- // TODO: Implement this for F#
457+ member __.AllowOverType ( _session , _cancellationToken ) =
466458true
467459
468460(* This is for attributes [< >] , since the implementation deals with chars only.
469461 We have to test if there is a [ before the cursor position and insert the closing '>'.*)
470- member this.CheckOpeningPoint ( _session , _cancellationToken ) =
471- let sourceCode = _ session.TextView.TextSnapshot
472- let position = _ session.TextView.Caret.Position.BufferPosition.Position
473- let ret = position-2 >= 0 && position< sourceCode.Length&&
474- sourceCode.GetText( position-2 , 1 ) .Equals( " (" ) && sourceCode.GetText( position, 1 ) .Equals( " )" )
475- ret
462+ member __.CheckOpeningPoint ( session , _cancellationToken ) =
463+ tryInsertAdditionalBracePair session Parenthesis.OpenCharacter Parenthesis.CloseCharacter
476464
477465[<ExportLanguageService( typeof< IEditorBraceCompletionSessionFactory>, FSharpConstants.FSharpLanguageName) >]
478- type internal FSharpEditorBraceCompletionSessionFactory () =
479- inherit ForegroundThreadAffinitizedObject()
466+ type EditorBraceCompletionSessionFactory () =
480467
481468member __.IsSupportedOpeningBrace openingBrace =
482469match openingBracewith
@@ -485,26 +472,25 @@ type internal FSharpEditorBraceCompletionSessionFactory () =
485472| Asterisk.OpenCharacter-> true
486473| _ -> false
487474
488- member this.CheckCodeContext ( _document : Document , _position : int , _openingBrace , _cancellationToken ) =
489- this.AssertIsForeground()
490- // We need to know if we are inside a F# comment. If we are, then don't do automatic completion.
491- let sourceCodeTask = _ document.GetTextAsync(_ cancellationToken)
492- sourceCodeTask.Wait(_ cancellationToken)
475+ member __.CheckCodeContext ( document : Document , position : int , _openingBrace , cancellationToken ) =
476+ // We need to know if we are inside a F# comment. If we are, then don't do automatic completion.
477+ let sourceCodeTask = document.GetTextAsync( cancellationToken)
478+ sourceCodeTask.Wait( cancellationToken)
493479let sourceCode = sourceCodeTask.Result
494480
495- _ position = 0
496- || let colorizationData = Tokenizer.getColorizationData (_ document .Id, sourceCode, TextSpan(_ position - 1, 1 ), Some(_ document .FilePath), [], _ cancellationToken )
481+ position = 0
482+ || let colorizationData = Tokenizer.getClassifiedSpans ( document .Id, sourceCode, TextSpan( position - 1 , 1 ), Some( document .FilePath), [ ], cancellationToken )
497483in colorizationData.Count= 0
498- || colorizationData.Exists( fun classifiedSpan ->
499- classifiedSpan.TextSpan.IntersectsWith_ position &&
484+ || colorizationData.Exists( fun classifiedSpan ->
485+ classifiedSpan.TextSpan.IntersectsWithposition &&
500486(
501487match classifiedSpan.ClassificationTypewith
502488| ClassificationTypeNames.Comment
503489| ClassificationTypeNames.StringLiteral-> false
504490| _ -> true // anything else is a valid classification type
505491))
506492
507- member this .CreateEditorSession( _document : Document , _openingPosition : int , openingBrace : char , _cancellationToken : CancellationToken ) =
493+ member __ .CreateEditorSession( _document , _openingPosition , openingBrace , _cancellationToken ) =
508494match openingBracewith
509495| Parenthesis.OpenCharacter-> ParenthesisCompletionSession() :> IEditorBraceCompletionSession
510496| CurlyBrackets.OpenCharacter-> ParenthesisCompletionSession() :> IEditorBraceCompletionSession
@@ -517,9 +503,7 @@ type internal FSharpEditorBraceCompletionSessionFactory () =
517503
518504interface IEditorBraceCompletionSessionFactorywith
519505
520- member this.TryCreateSession ( document , openingPosition , openingBrace , cancellationToken ) : IEditorBraceCompletionSession =
521- this.AssertIsForeground()
522-
506+ member this.TryCreateSession ( document , openingPosition , openingBrace , cancellationToken ) =
523507if this.IsSupportedOpeningBrace( openingBrace) && this.CheckCodeContext( document, openingPosition, openingBrace, cancellationToken) then
524508 this.CreateEditorSession( document, openingPosition, openingBrace, cancellationToken)
525509else
@@ -534,20 +518,16 @@ type internal FSharpEditorBraceCompletionSessionFactory () =
534518[<BracePair( VerticalBar.OpenCharacter, VerticalBar.CloseCharacter) >]
535519[<BracePair( AngleBrackets.OpenCharacter, AngleBrackets.CloseCharacter) >]
536520[<BracePair( Asterisk.OpenCharacter, Asterisk.CloseCharacter) >]
537- type internal FSharpBraceCompletionSessionProvider
521+ type BraceCompletionSessionProvider
538522[<ImportingConstructor>]
539523(
540524 undoManager: ITextBufferUndoManagerProvider,
541525 editorOperationsFactoryService: IEditorOperationsFactoryService
542526) =
543527
544- inherit ForegroundThreadAffinitizedObject()
545-
546528interface IBraceCompletionSessionProviderwith
547529
548- member this.TryCreateSession ( textView , openingPoint , openingBrace , closingBrace , session ) =
549- this.AssertIsForeground();
550-
530+ member __.TryCreateSession ( textView , openingPoint , openingBrace , closingBrace , session ) =
551531let textSnapshot = openingPoint.Snapshot
552532
553533let newSession =
@@ -564,7 +544,7 @@ type internal FSharpBraceCompletionSessionProvider
564544| null -> null
565545| editorSession->
566546let undoHistory = undoManager.GetTextBufferUndoManager( textView.TextBuffer) .TextBufferUndoHistory
567- FSharpBraceCompletionSession (
547+ BraceCompletionSession (
568548 textView,
569549 openingPoint.Snapshot.TextBuffer,
570550 openingPoint,