-
Notifications
You must be signed in to change notification settings - Fork 840
[WIP and Blocked] Inline hints for F# #10295
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
Closed
Changes from 1 commit
Commits
Show all changes
26 commits
Select commit
Hold shift + click to select a range
3567144
Initial skeleton + dependencies updates
cartermp 8b4b8cb
Initial proof of concept
cartermp 6b36be5
Cleanup, tag interfaces correctly, surface area
cartermp b67ebdb
Basic, buggy support for parameter names
cartermp 7f09a76
Preliminary support for not adding hints to already-annotated values
cartermp e129f58
don't show for typed value decls
cartermp fcc4be6
No sig files, handle more typed cases
cartermp 626f7ff
Be precise about type annotations when looking for them in the syntax…
cartermp 1c9afe6
More annotations fixity
cartermp 57f8246
Hints show only the return type for functions
cartermp 7dfc1b8
Cleanup and surface tests
cartermp 47ed27a
Match names
cartermp 51dcd6f
Basic tests for arg names
cartermp d2502db
Fix issues with nested functions + more tests
cartermp a964414
More testing and fix a bug with annotating return types for methods
cartermp 3169656
Add failing test for infix exprs
cartermp b565539
Tests and fixes for exprs in infix operators
cartermp a8e289b
QuickInfo is scoped out + surface area
cartermp 16c0b93
Add IsMethod and change parameter name hints to be more like names pa…
cartermp 7e9eded
Only show type hints for lambdas + tests + surface
cartermp 0ce8403
Preliminary support for labels for methods
cartermp 50e7d9d
Cleanup, handle method params properly, constructors
cartermp 258aa23
Feedback
cartermp 86c25b9
Param names
cartermp 2fef548
Update with latest
cartermp feaacf7
Update src/fsharp/symbols/Symbols.fsi
cartermp File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Initial proof of concept
- Loading branch information
commit 8b4b8cb392046b07fba3459de13759c23eb8f0d1
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
118 changes: 94 additions & 24 deletions
118
vsintegration/src/FSharp.Editor/InlineHints/InlineHints.fs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,47 +1,117 @@ | ||
| // Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. | ||
cartermp marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| namespace Microsoft.VisualStudio.FSharp.Editor | ||
|
|
||
| open System.Composition | ||
| open Microsoft.VisualStudio.Shell | ||
|
|
||
| open System | ||
| open System.Collections.Immutable | ||
| open System.Threading | ||
| open System.ComponentModel.Composition | ||
|
|
||
| open Microsoft.CodeAnalysis | ||
| open Microsoft.CodeAnalysis.Text | ||
| open Microsoft.CodeAnalysis.ExternalAccess.FSharp.InlineHints | ||
|
|
||
| open FSharp.Compiler | ||
| open FSharp.Compiler.Range | ||
| open FSharp.Compiler.SourceCodeServices | ||
| open FSharp.Compiler.SyntaxTree | ||
|
|
||
| [<Export(typeof<IFSharpInlineHintsService>)>] | ||
| type internal FSharpInlineHintsService [<ImportingConstructor>] (checkerProvider: FSharpCheckerProvider, projectInfoManager: FSharpProjectOptionsManager) = | ||
| type internal FSharpInlineHintsService | ||
| [<ImportingConstructor>] | ||
| ( | ||
| checkerProvider: FSharpCheckerProvider, | ||
| [<Import(typeof<SVsServiceProvider>)>] serviceProvider: IServiceProvider, | ||
| projectInfoManager: FSharpProjectOptionsManager | ||
| ) = | ||
|
|
||
| static let userOpName = "FSharpInlineHints" | ||
|
|
||
| interface IFSharpInlineHintsService with | ||
| member _.GetInlineHintsAsync(document: Document, _textSpan: TextSpan, cancellationToken: CancellationToken) = | ||
| member _.GetInlineHintsAsync(document: Document, textSpan: TextSpan, cancellationToken: CancellationToken) = | ||
| asyncMaybe { | ||
| let! _parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, cancellationToken, userOpName) | ||
| let! textVersion = document.GetTextVersionAsync(cancellationToken) | ||
| let! parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, cancellationToken, userOpName) | ||
| let! sourceText = document.GetTextAsync(cancellationToken) | ||
| //let defines = CompilerEnvironment.GetCompilationDefinesForEditing parsingOptions | ||
| //let _textLine = sourceText.Lines.GetLineFromPosition(textSpan.Start) | ||
| //let _textLinePos = sourceText.Lines.GetLinePosition(textSpan.Start) | ||
| //let _fcsTextLineNumber = Line.fromZ textLinePos.Line | ||
| //let! _symbol = Tokenizer.getSymbolAtPosition(document.Id, sourceText, textSpan.Start, document.FilePath, defines, SymbolLookupKind.Greedy, false, false) | ||
| let! _parseFileResults, _, checkFileResults = checkerProvider.Checker.ParseAndCheckDocument(document, projectOptions, userOpName) | ||
| let! symbols = checkFileResults.GetAllUsesOfAllSymbolsInFile() |> liftAsync | ||
| //let! symbolUse = checkFileResults.GetSymbolUseAtLocation(fcsTextLineNumber, symbol.Ident.idRange.EndColumn, textLine.Text.ToString(), symbol.FullIsland, userOpName=userOpName) | ||
|
|
||
| let hints = | ||
| [| | ||
| for symbol in symbols do | ||
| // let givenRange = RoslynHelpers.TextSpanToFSharpRange | ||
| let symbolSpan = RoslynHelpers.FSharpRangeToTextSpan(sourceText, symbol.RangeAlternate) | ||
| FSharpInlineHint(TextSpan(symbolSpan.Start, 0), ImmutableArray.Create(TaggedText(TextTags.Text, symbol.Symbol.DisplayName + ":"))) | ||
| |] | ||
|
|
||
| return hints.ToImmutableArray() | ||
| let range = RoslynHelpers.TextSpanToFSharpRange(document.FilePath, textSpan, sourceText) | ||
| let! symbolUses = checkFileResults.GetAllUsesOfAllSymbolsInFileWithinRange(range) |> liftAsync | ||
|
|
||
| let typeHints = ImmutableArray.CreateBuilder() | ||
|
|
||
| // todo - get these at some point I guess | ||
| // most likely need to work with the parse tree API | ||
| // since there is no good way to tell if a symbol is a parameter (declared or used) | ||
| let _parameterHints = ImmutableArray.CreateBuilder() | ||
|
|
||
| for symbolUse in symbolUses do | ||
| if symbolUse.IsFromDefinition then | ||
| match symbolUse.Symbol with | ||
| | :? FSharpMemberOrFunctionOrValue as x when x.IsValue && not x.IsMemberThisValue && not x.IsConstructorThisValue -> | ||
| let symbolSpan = RoslynHelpers.FSharpRangeToTextSpan(sourceText, symbolUse.RangeAlternate) | ||
|
|
||
| // TODO: look for if 'x' is SynExpr.Typed perhaps? | ||
|
|
||
| // This does not correctly "classify" non-F# types | ||
| // TODO deal with that, probably via a new API? | ||
| let typeLayout = x.FormatLayout symbolUse.DisplayContext | ||
|
|
||
| let taggedText = ResizeArray() | ||
|
|
||
| Layout.renderL (Layout.taggedTextListR taggedText.Add) typeLayout |> ignore | ||
|
|
||
| let displayParts = ImmutableArray.CreateBuilder() | ||
| displayParts.Add(TaggedText(TextTags.Text, ": ")) | ||
|
|
||
| taggedText | ||
| |> Seq.map (fun tt -> RoslynHelpers.roslynTag tt.Tag, tt.Text) | ||
| |> Seq.map (fun (tag, text) -> TaggedText(tag, text)) | ||
| |> Seq.iter (fun tt -> displayParts.Add(tt)) | ||
|
|
||
| // TODO - this is not actually correct | ||
| // We need to get QuickInfo for the actual type we pull out, not the value | ||
| // This code is correct for parameter name hints though, if that gets done! | ||
| let callBack position = | ||
| fun _ _ -> | ||
| asyncMaybe { | ||
| let! quickInfo = | ||
| FSharpAsyncQuickInfoSource.ProvideQuickInfo( | ||
| checkerProvider.Checker, | ||
| document.Id, | ||
| sourceText, | ||
| document.FilePath, | ||
| position, | ||
| parsingOptions, | ||
| projectOptions, | ||
| textVersion.GetHashCode(), | ||
| document.FSharpOptions.LanguageServicePerformance) | ||
|
|
||
| let documentationBuilder = XmlDocumentation.CreateDocumentationBuilder(serviceProvider.XMLMemberIndexService) | ||
| let mainDesc, docs = FSharpAsyncQuickInfoSource.BuildSingleQuickInfoItem documentationBuilder quickInfo | ||
|
|
||
| let descriptionParts = ImmutableArray.CreateBuilder() | ||
|
|
||
| mainDesc | ||
| |> Seq.map (fun tt -> RoslynHelpers.roslynTag tt.Tag, tt.Text) | ||
| |> Seq.map (fun (tag, text) -> TaggedText(tag, text)) | ||
| |> Seq.iter (fun tt -> descriptionParts.Add(tt)) | ||
|
|
||
| docs | ||
| |> Seq.map (fun tt -> RoslynHelpers.roslynTag tt.Tag, tt.Text) | ||
| |> Seq.map (fun (tag, text) -> TaggedText(tag, text)) | ||
| |> Seq.iter (fun tt -> descriptionParts.Add(tt)) | ||
|
|
||
| return (descriptionParts.ToImmutableArray()) | ||
| } | ||
| |> Async.map (Option.defaultValue ImmutableArray<_>.Empty) | ||
| |> RoslynHelpers.StartAsyncAsTask(cancellationToken) | ||
|
|
||
| let getDescriptionAsync position = Func<Document, CancellationToken, _>(callBack position) | ||
|
|
||
| let hint = FSharpInlineHint(TextSpan(symbolSpan.End, 0), displayParts.ToImmutableArray(), getDescriptionAsync symbolSpan.Start) | ||
| typeHints.Add(hint) | ||
| | _ -> () | ||
|
|
||
| return typeHints.ToImmutableArray() | ||
| } | ||
| |> Async.map (Option.defaultValue ImmutableArray<_>.Empty) | ||
| |> RoslynHelpers.StartAsyncAsTask(cancellationToken) | ||
| |> RoslynHelpers.StartAsyncAsTask(cancellationToken) | ||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.