Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ open Microsoft.CodeAnalysis.Host.Mef
open Microsoft.CodeAnalysis.Text

open Microsoft.VisualStudio.FSharp.LanguageService

open Microsoft.FSharp.Compiler.SourceCodeServices

[<ExportLanguageService(typeof<IEditorClassificationService>, FSharpCommonConstants.FSharpLanguageName)>]
Expand All @@ -37,25 +36,16 @@ type internal FSharpColorizationService
} |> CommonRoslynHelpers.StartAsyncUnitAsTask cancellationToken

member this.AddSemanticClassificationsAsync(document: Document, textSpan: TextSpan, result: List<ClassifiedSpan>, cancellationToken: CancellationToken) =
async {
match projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document) with
| Some options ->
let! sourceText = document.GetTextAsync(cancellationToken)
let! textVersion = document.GetTextVersionAsync(cancellationToken)
let! _parseResults, checkResultsAnswer = checkerProvider.Checker.ParseAndCheckFileInProject(document.FilePath, textVersion.GetHashCode(), sourceText.ToString(), options)

let extraColorizationData =
match checkResultsAnswer with
| FSharpCheckFileAnswer.Aborted -> [| |]
| FSharpCheckFileAnswer.Succeeded(results) ->
[| for (range, tokenColorKind) in results.GetExtraColorizationsAlternate() do
let span = CommonHelpers.fixupSpan(sourceText, CommonRoslynHelpers.FSharpRangeToTextSpan(sourceText, range))
if textSpan.Contains(span.Start) || textSpan.Contains(span.End - 1) || span.Contains(textSpan) then
yield ClassifiedSpan(span, CommonHelpers.compilerTokenToRoslynToken(tokenColorKind)) |]
asyncMaybe {
let! options = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document)
let! sourceText = document.GetTextAsync(cancellationToken)
let! _, checkResults = checkerProvider.Checker.ParseAndCheckDocument(document, options, sourceText)

result.AddRange(extraColorizationData)
| None -> ()
} |> CommonRoslynHelpers.StartAsyncUnitAsTask cancellationToken
for (range, tokenColorKind) in checkResults.GetExtraColorizationsAlternate() do
let span = CommonHelpers.fixupSpan(sourceText, CommonRoslynHelpers.FSharpRangeToTextSpan(sourceText, range))
if textSpan.Contains(span.Start) || textSpan.Contains(span.End - 1) || span.Contains(textSpan) then
result.Add(ClassifiedSpan(span, CommonHelpers.compilerTokenToRoslynToken(tokenColorKind)))
} |> Async.Ignore |> CommonRoslynHelpers.StartAsyncUnitAsTask cancellationToken

// Do not perform classification if we don't have project options (#defines matter)
member this.AdjustStaleClassification(_: SourceText, classifiedSpan: ClassifiedSpan) : ClassifiedSpan = classifiedSpan
Expand Down
118 changes: 44 additions & 74 deletions vsintegration/src/FSharp.Editor/CodeFix/AddOpenCodeFixProvider.fs
Original file line number Diff line number Diff line change
Expand Up @@ -4,44 +4,21 @@ namespace rec Microsoft.VisualStudio.FSharp.Editor

open System
open System.Composition
open System.Collections.Concurrent
open System.Collections.Generic
open System.Collections.Immutable
open System.Threading
open System.Threading.Tasks
open System.Runtime.CompilerServices
open System.Windows
open System.Windows.Controls
open System.Windows.Media

open Microsoft.CodeAnalysis
open Microsoft.CodeAnalysis.Completion
open Microsoft.CodeAnalysis.Classification
open Microsoft.CodeAnalysis.Editor
open Microsoft.CodeAnalysis.Editor.Shared.Utilities
open Microsoft.CodeAnalysis.Formatting
open Microsoft.CodeAnalysis.Host
open Microsoft.CodeAnalysis.Host.Mef
open Microsoft.CodeAnalysis.Options
open Microsoft.CodeAnalysis.Text
open Microsoft.CodeAnalysis.CodeFixes
open Microsoft.CodeAnalysis.CodeActions

open Microsoft.VisualStudio.FSharp.LanguageService
open Microsoft.VisualStudio.Text
open Microsoft.VisualStudio.Text.Classification
open Microsoft.VisualStudio.Text.Tagging
open Microsoft.VisualStudio.Text.Formatting
open Microsoft.VisualStudio.Shell.Interop

open Microsoft.FSharp.Compiler
open Microsoft.FSharp.Compiler.Parser
open Microsoft.FSharp.Compiler.Range
open Microsoft.FSharp.Compiler.SourceCodeServices

open System.Windows.Documents
open Microsoft.VisualStudio.FSharp.Editor.Structure

[<CompilationRepresentation (CompilationRepresentationFlags.ModuleSuffix)>]
module internal InsertContext =
/// Corrects insertion line number based on kind of scope and text surrounding the insertion point.
Expand Down Expand Up @@ -168,55 +145,48 @@ type internal FSharpAddOpenCodeFixProvider
override __.FixableDiagnosticIds = fixableDiagnosticIds.ToImmutableArray()

override __.RegisterCodeFixesAsync context : Task =
async {
match projectInfoManager.TryGetOptionsForEditingDocumentOrProject context.Document with
| Some options ->
let! sourceText = context.Document.GetTextAsync(context.CancellationToken)
let! textVersion = context.Document.GetTextVersionAsync(context.CancellationToken)
let! parseResults, checkFileAnswer = checker.ParseAndCheckFileInProject(context.Document.FilePath, textVersion.GetHashCode(), sourceText.ToString(), options)
match parseResults.ParseTree, checkFileAnswer with
| None, _
| _, FSharpCheckFileAnswer.Aborted -> ()
| Some parsedInput, FSharpCheckFileAnswer.Succeeded checkFileResults ->
let unresolvedIdentRange =
let startLinePos = sourceText.Lines.GetLinePosition context.Span.Start
let startPos = Pos.fromZ startLinePos.Line startLinePos.Character
let endLinePos = sourceText.Lines.GetLinePosition context.Span.End
let endPos = Pos.fromZ endLinePos.Line endLinePos.Character
Range.mkRange context.Document.FilePath startPos endPos

let isAttribute = UntypedParseImpl.GetEntityKind(unresolvedIdentRange.Start, parsedInput) = Some EntityKind.Attribute

let entities =
assemblyContentProvider.GetAllEntitiesInProjectAndReferencedAssemblies checkFileResults
|> List.collect (fun e ->
[ yield e.TopRequireQualifiedAccessParent, e.AutoOpenParent, e.Namespace, e.CleanedIdents
if isAttribute then
let lastIdent = e.CleanedIdents.[e.CleanedIdents.Length - 1]
if lastIdent.EndsWith "Attribute" && e.Kind LookupType.Precise = EntityKind.Attribute then
yield
e.TopRequireQualifiedAccessParent,
e.AutoOpenParent,
e.Namespace,
e.CleanedIdents
|> Array.replace (e.CleanedIdents.Length - 1) (lastIdent.Substring(0, lastIdent.Length - 9)) ])

let longIdent = ParsedInput.getLongIdentAt parsedInput unresolvedIdentRange.End

let maybeUnresolvedIdents =
longIdent
|> Option.map (fun longIdent ->
longIdent
|> List.map (fun ident ->
{ Ident = ident.idText
Resolved = not (ident.idRange = unresolvedIdentRange) })
|> List.toArray)

match maybeUnresolvedIdents with
| Some maybeUnresolvedIdents ->
let createEntity = ParsedInput.tryFindInsertionContext unresolvedIdentRange.StartLine parsedInput maybeUnresolvedIdents
return entities |> Seq.map createEntity |> Seq.concat |> Seq.toList |> getSuggestions context
| None -> ()
| None -> ()
} |> CommonRoslynHelpers.StartAsyncUnitAsTask(context.CancellationToken)
asyncMaybe {
let! options = projectInfoManager.TryGetOptionsForEditingDocumentOrProject context.Document
let! sourceText = context.Document.GetTextAsync(context.CancellationToken)
let! parsedInput, checkResults = checker.ParseAndCheckDocument(context.Document, options, sourceText)

let unresolvedIdentRange =
let startLinePos = sourceText.Lines.GetLinePosition context.Span.Start
let startPos = Pos.fromZ startLinePos.Line startLinePos.Character
let endLinePos = sourceText.Lines.GetLinePosition context.Span.End
let endPos = Pos.fromZ endLinePos.Line endLinePos.Character
Range.mkRange context.Document.FilePath startPos endPos

let isAttribute = UntypedParseImpl.GetEntityKind(unresolvedIdentRange.Start, parsedInput) = Some EntityKind.Attribute

let entities =
assemblyContentProvider.GetAllEntitiesInProjectAndReferencedAssemblies checkResults
|> List.collect (fun e ->
[ yield e.TopRequireQualifiedAccessParent, e.AutoOpenParent, e.Namespace, e.CleanedIdents
if isAttribute then
let lastIdent = e.CleanedIdents.[e.CleanedIdents.Length - 1]
if lastIdent.EndsWith "Attribute" && e.Kind LookupType.Precise = EntityKind.Attribute then
yield
e.TopRequireQualifiedAccessParent,
e.AutoOpenParent,
e.Namespace,
e.CleanedIdents
|> Array.replace (e.CleanedIdents.Length - 1) (lastIdent.Substring(0, lastIdent.Length - 9)) ])

let longIdent = ParsedInput.getLongIdentAt parsedInput unresolvedIdentRange.End

let! maybeUnresolvedIdents =
longIdent
|> Option.map (fun longIdent ->
longIdent
|> List.map (fun ident ->
{ Ident = ident.idText
Resolved = not (ident.idRange = unresolvedIdentRange) })
|> List.toArray)

let createEntity = ParsedInput.tryFindInsertionContext unresolvedIdentRange.StartLine parsedInput maybeUnresolvedIdents
return entities |> Seq.map createEntity |> Seq.concat |> Seq.toList |> getSuggestions context
}
|> Async.Ignore
|> CommonRoslynHelpers.StartAsyncUnitAsTask(context.CancellationToken)

Loading