diff --git a/FSharp.Directory.Build.props b/FSharp.Directory.Build.props index 92682e7e502..ea314206014 100644 --- a/FSharp.Directory.Build.props +++ b/FSharp.Directory.Build.props @@ -46,7 +46,7 @@ - full + portable fs false true diff --git a/FSharp.Directory.Build.targets b/FSharp.Directory.Build.targets index 455bba26554..923863bb205 100644 --- a/FSharp.Directory.Build.targets +++ b/FSharp.Directory.Build.targets @@ -34,6 +34,7 @@ + diff --git a/NuGet.Config b/NuGet.Config index b362163ba9f..d7b373fc4c6 100644 --- a/NuGet.Config +++ b/NuGet.Config @@ -17,6 +17,7 @@ + diff --git a/build/targets/ConvertPortablePdbs.targets b/build/targets/ConvertPortablePdbs.targets new file mode 100644 index 00000000000..0965566db0c --- /dev/null +++ b/build/targets/ConvertPortablePdbs.targets @@ -0,0 +1,20 @@ + + + + + + + + + $(FinalOutputPath)\ConvertedPdbs + $(NuGetPackageRoot)Microsoft.DiaSymReader.Pdb2Pdb\$(MicrosoftDiaSymReaderPdb2PdbPackageVersion)\tools\Pdb2Pdb.exe + "$(TargetPath)" /out "$(ConvertedPdbsDirectory)\$(TargetName).pdb" /verbose /srcsvrvar SRC_INDEX=public + + + + + + + diff --git a/build/targets/PackageVersions.props b/build/targets/PackageVersions.props index 889b7a80006..b9848069837 100644 --- a/build/targets/PackageVersions.props +++ b/build/targets/PackageVersions.props @@ -48,6 +48,7 @@ 1.0.30 + 1.1.0-roslyn-62714-01 8.0.0-alpha 1.0.1 9.0.1 diff --git a/src/absil/ilwritepdb.fs b/src/absil/ilwritepdb.fs index f8baa3aea4c..760ac9e428a 100644 --- a/src/absil/ilwritepdb.fs +++ b/src/absil/ilwritepdb.fs @@ -423,22 +423,15 @@ let generatePortablePdb (embedAllSource:bool) (embedSourceList:string list) (sou list.ToArray() |> Array.sortWith scopeSorter collectScopes scope |> Seq.iter(fun s -> - if s.Children.Length = 0 then - metadata.AddLocalScope(MetadataTokens.MethodDefinitionHandle(minfo.MethToken), - Unchecked.defaultof, - nextHandle lastLocalVariableHandle, - Unchecked.defaultof, - 0, s.EndOffset - s.StartOffset ) |>ignore - else - metadata.AddLocalScope(MetadataTokens.MethodDefinitionHandle(minfo.MethToken), - Unchecked.defaultof, - nextHandle lastLocalVariableHandle, - Unchecked.defaultof, - s.StartOffset, s.EndOffset - s.StartOffset) |>ignore - - for localVariable in s.Locals do - lastLocalVariableHandle <- metadata.AddLocalVariable(LocalVariableAttributes.None, localVariable.Index, metadata.GetOrAddString(localVariable.Name)) - ) + metadata.AddLocalScope(MetadataTokens.MethodDefinitionHandle(minfo.MethToken), + Unchecked.defaultof, + nextHandle lastLocalVariableHandle, + Unchecked.defaultof, + s.StartOffset, s.EndOffset - s.StartOffset ) |>ignore + + for localVariable in s.Locals do + lastLocalVariableHandle <- metadata.AddLocalVariable(LocalVariableAttributes.None, localVariable.Index, metadata.GetOrAddString(localVariable.Name)) + ) match minfo.RootScope with | None -> () diff --git a/src/fsharp/NicePrint.fs b/src/fsharp/NicePrint.fs index d3116650608..195c373f732 100755 --- a/src/fsharp/NicePrint.fs +++ b/src/fsharp/NicePrint.fs @@ -1970,6 +1970,7 @@ let isGeneratedExceptionField pos f = TastDefinitionPrinting.isGeneratedExce let stringOfTyparConstraint denv tpc = stringOfTyparConstraints denv [tpc] let stringOfTy denv x = x |> PrintTypes.layoutType denv |> showL let prettyLayoutOfType denv x = x |> PrintTypes.prettyLayoutOfType denv +let prettyLayoutOfTypeNoCx denv x = x |> PrintTypes.prettyLayoutOfTypeNoConstraints denv let prettyStringOfTy denv x = x |> PrintTypes.prettyLayoutOfType denv |> showL let prettyStringOfTyNoCx denv x = x |> PrintTypes.prettyLayoutOfTypeNoConstraints denv |> showL let stringOfRecdField denv x = x |> TastDefinitionPrinting.layoutRecdField false denv |> showL diff --git a/src/fsharp/service/service.fs b/src/fsharp/service/service.fs index 38e95e816d1..3ed5f832a0e 100644 --- a/src/fsharp/service/service.fs +++ b/src/fsharp/service/service.fs @@ -908,6 +908,9 @@ type TypeCheckInfo match item with | Item.Types _ | Item.ModuleOrNamespaces _ -> true | _ -> false + + /// Find the most precise display context for the given line and column. + member __.GetBestDisplayEnvForPos cursorPos = GetBestEnvForPos cursorPos member __.GetVisibleNamespacesAndModulesAtPosition(cursorPos: pos) : ModuleOrNamespaceRef list = let (nenv, ad), m = GetBestEnvForPos cursorPos @@ -1982,6 +1985,7 @@ type FSharpCheckFileResults(filename: string, errors: FSharpErrorInfo[], scopeOp | _ -> async.Return dflt + member info.GetToolTipText(line, colAtEndOfNames, lineStr, names, tokenTag, userOpName) = info.GetStructuredToolTipText(line, colAtEndOfNames, lineStr, names, tokenTag, ?userOpName=userOpName) |> Tooltips.Map Tooltips.ToFSharpToolTipText @@ -2093,6 +2097,13 @@ type FSharpCheckFileResults(filename: string, errors: FSharpErrorInfo[], scopeOp RequireCompilationThread ctok scope.IsRelativeNameResolvableFromSymbol(pos, plid, symbol)) + member info.GetDisplayEnvForPos(pos: pos) : Async = + let userOpName = "CodeLens" + reactorOp userOpName "GetDisplayContextAtPos" None (fun ctok scope -> + DoesNotRequireCompilerThreadTokenAndCouldPossiblyBeMadeConcurrent ctok + let (nenv, _), _ = scope.GetBestDisplayEnvForPos pos + Some nenv.DisplayEnv) + member info.ImplementationFiles = if not keepAssemblyContents then invalidOp "The 'keepAssemblyContents' flag must be set to true on the FSharpChecker in order to access the checked contents of assemblies" scopeOptX diff --git a/src/fsharp/service/service.fsi b/src/fsharp/service/service.fsi index 82a1a563ea8..df75679414d 100755 --- a/src/fsharp/service/service.fsi +++ b/src/fsharp/service/service.fsi @@ -242,6 +242,9 @@ type public FSharpCheckFileResults = member internal GetVisibleNamespacesAndModulesAtPoint : pos -> Async + /// Find the most precise display environment for the given line and column. + member internal GetDisplayEnvForPos : pos : pos -> Async + /// Determines if a long ident is resolvable at a specific point. /// An optional string used for tracing compiler operations associated with this request. member internal IsRelativeNameResolvable: cursorPos : pos * plid : string list * item: Item * ?userOpName: string -> Async diff --git a/src/fsharp/symbols/Symbols.fs b/src/fsharp/symbols/Symbols.fs index 74aa51c9e20..944c4d8b694 100644 --- a/src/fsharp/symbols/Symbols.fs +++ b/src/fsharp/symbols/Symbols.fs @@ -1844,6 +1844,23 @@ and FSharpMemberOrFunctionOrValue(cenv, d:FSharpMemberOrValData, item) = prefix + x.LogicalName with _ -> "??" + member x.FormatLayout (denv:FSharpDisplayContext) = + match x.IsMember, d with + | true, V v -> + NicePrint.prettyLayoutOfValOrMemberNoInst { (denv.Contents cenv.g) with showMemberContainers=true } v.Deref + | _,_ -> + checkIsResolved() + let ty = + match d with + | E e -> e.GetDelegateType(cenv.amap, range0) + | P p -> p.GetPropertyType(cenv.amap, range0) + | M m | C m -> + let rty = m.GetFSharpReturnTy(cenv.amap, range0, m.FormalMethodInst) + let argtysl = m.GetParamTypes(cenv.amap, range0, m.FormalMethodInst) + mkIteratedFunTy (List.map (mkRefTupledTy cenv.g) argtysl) rty + | V v -> v.TauType + NicePrint.prettyLayoutOfTypeNoCx (denv.Contents cenv.g) ty + and FSharpType(cenv, typ:TType) = @@ -1989,7 +2006,11 @@ and FSharpType(cenv, typ:TType) = member x.Format(denv: FSharpDisplayContext) = protect <| fun () -> - NicePrint.prettyStringOfTyNoCx (denv.Contents cenv.g) typ + NicePrint.prettyStringOfTyNoCx (denv.Contents cenv.g) typ + + member x.FormatLayout(denv: FSharpDisplayContext) = + protect <| fun () -> + NicePrint.prettyLayoutOfTypeNoCx (denv.Contents cenv.g) typ override x.ToString() = protect <| fun () -> diff --git a/src/fsharp/symbols/Symbols.fsi b/src/fsharp/symbols/Symbols.fsi index 55c1a6fbb2b..34b3e156108 100644 --- a/src/fsharp/symbols/Symbols.fsi +++ b/src/fsharp/symbols/Symbols.fsi @@ -819,6 +819,9 @@ and [] public FSharpMemberOrFunctionOrValue = /// Indicates if this is a constructor. member IsConstructor : bool + + /// Format the type using the rules of the given display context + member FormatLayout : context: FSharpDisplayContext -> Layout /// A subtype of FSharpSymbol that represents a parameter @@ -931,6 +934,9 @@ and [] public FSharpType = /// Format the type using the rules of the given display context member Format : context: FSharpDisplayContext -> string + /// Format the type using the rules of the given display context + member FormatLayout : context: FSharpDisplayContext -> Layout + /// Instantiate generic type parameters in a type member Instantiate : (FSharpGenericParameter * FSharpType) list -> FSharpType diff --git a/tests/FSharp.Compiler.UnitTests/FSharp.Compiler.Unittests.fsproj b/tests/FSharp.Compiler.UnitTests/FSharp.Compiler.Unittests.fsproj index 4bd20fd6b20..5357d4ffad6 100644 --- a/tests/FSharp.Compiler.UnitTests/FSharp.Compiler.Unittests.fsproj +++ b/tests/FSharp.Compiler.UnitTests/FSharp.Compiler.Unittests.fsproj @@ -60,10 +60,9 @@ FSharp.Compiler.Private {2e4d67b4-522d-4cf7-97e4-ba940f0b18f3} - + + {DED3BBD7-53F4-428A-8C9F-27968E768605} FSharp.Core - {ded3bbd7-53f4-428a-8c9f-27968e768605} - True diff --git a/vsintegration/src/FSharp.Editor/CodeLens/AbstractCodeLensDisplayService.fs b/vsintegration/src/FSharp.Editor/CodeLens/AbstractCodeLensDisplayService.fs new file mode 100644 index 00000000000..df364bb8769 --- /dev/null +++ b/vsintegration/src/FSharp.Editor/CodeLens/AbstractCodeLensDisplayService.fs @@ -0,0 +1,273 @@ +// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. + +namespace rec Microsoft.VisualStudio.FSharp.Editor + +open System +open System.Windows.Controls +open Microsoft.VisualStudio.Text +open Microsoft.VisualStudio.Text.Editor +open Microsoft.VisualStudio.Text.Formatting +open System.Threading +open System.Windows +open System.Collections.Generic + +open Microsoft.VisualStudio.FSharp.Editor.Logging + +[] +type CodeLensDisplayService (view : IWpfTextView, buffer : ITextBuffer, layerName) as self = + + // Add buffer changed event handler + do ( + buffer.Changed.Add self.handleBufferChanged + view.LayoutChanged.Add self.handleLayoutChanged + ) + + /// + /// Enqueing an unit signals to the tagger that all visible line lens must be layouted again, + /// to respect single line changes. + /// + member val RelayoutRequested : Queue<_> = Queue() with get + + member val WpfView = view + + member val TextBuffer = buffer + + /// Saves the ui context to switch context for ui related work. + member val uiContext = SynchronizationContext.Current + + // Tracks the created ui elements per TrackingSpan + member val uiElements = Dictionary<_,Grid>() + + member val trackingSpanUiParent = HashSet() + + member val uiElementNeighbour = Dictionary() + + /// Caches the current used trackingSpans per line. One line can contain multiple trackingSpans + member val trackingSpans = Dictionary>() + /// Text view for accessing the adornment layer. + member val view: IWpfTextView = view + /// The code lens layer for adding and removing adornments. + member val codeLensLayer = view.GetAdornmentLayer layerName + /// Tracks the recent first + last visible line numbers for adornment layout logic. + member val recentFirstVsblLineNmbr = 0 with get, set + + member val recentLastVsblLineNmbr = 0 with get, set + /// Tracks the adornments on the layer. + member val addedAdornments = HashSet() + /// Cancellation token source for the layout changed event. Needed to abort previous async-work. + member val layoutChangedCts = new CancellationTokenSource() with get, set + + /// Tracks the last used buffer snapshot, should be preferred used in combination with mutex. + member val currentBufferSnapshot = null with get, set + + /// Helper method which returns the start line number of a tracking span + member __.getTrackingSpanStartLine (snapshot:ITextSnapshot) (trackingSpan:ITrackingSpan) = + snapshot.GetLineNumberFromPosition(trackingSpan.GetStartPoint(snapshot).Position) + + /// Helper method which returns the start line number of a tracking span + member __.tryGetTSpanStartLine (snapshot:ITextSnapshot) (trackingSpan:ITrackingSpan) = + let pos = trackingSpan.GetStartPoint(snapshot).Position + if snapshot.Length - 1 < pos then None + else pos |> snapshot.GetLineNumberFromPosition |> Some + + member self.updateTrackingSpansFast (snapshot:ITextSnapshot) lineNumber = + if lineNumber |> self.trackingSpans.ContainsKey then + let currentTrackingSpans = self.trackingSpans.[lineNumber] |> ResizeArray // We need a copy because we modify the list. + for trackingSpan in currentTrackingSpans do + let newLineOption = self.tryGetTSpanStartLine snapshot trackingSpan + match newLineOption with + | None -> () + | Some newLine -> + if newLine <> lineNumber then + // We're on a new line and need to check whether we're currently in another grid + // (because somehow there were multiple trackingSpans per line). + if self.trackingSpanUiParent.Contains trackingSpan then + self.trackingSpanUiParent.Remove trackingSpan |> ignore + self.uiElementNeighbour.Remove self.uiElements.[trackingSpan] |> ignore + // remove our entry in the line cache dictionary + self.trackingSpans.[lineNumber].Remove(trackingSpan) |> ignore + // if the cache entry for the old line is now empty remove it completely + if self.trackingSpans.[lineNumber].Count = 0 then + self.trackingSpans.Remove lineNumber |> ignore + // now re-register our tracking span in the cache dict. + // Check whether the new line has no existing entry to add a fresh one. + // If there is already one we put our grid into the grid of the first entry of the line. + if newLine |> self.trackingSpans.ContainsKey |> not then + self.trackingSpans.[newLine] <- ResizeArray() + else + let neighbour = + self.uiElements.[self.trackingSpans.[newLine] |> Seq.last] // This fails if a tracking span has no ui element! + self.uiElementNeighbour.[self.uiElements.[trackingSpan]] <- neighbour + self.trackingSpanUiParent.Add trackingSpan |> ignore + // And finally add us to the cache again. + self.trackingSpans.[newLine].Add(trackingSpan) + // Be sure that the uiElement of the trackingSpan is visible if the new line is in the visible line space. + if newLine < self.recentFirstVsblLineNmbr || newLine > self.recentLastVsblLineNmbr then + if self.uiElements.ContainsKey trackingSpan then + let mutable element = self.uiElements.[trackingSpan] + element.Visibility <- Visibility.Hidden + + member __.createDefaultStackPanel () = + let grid = Grid(Visibility = Visibility.Hidden) + Canvas.SetLeft(grid, 0.) + Canvas.SetTop(grid, 0.) + grid + + /// Helper methods which invokes every action which is needed for new trackingSpans + member self.addTrackingSpan (trackingSpan:ITrackingSpan)= + let snapshot = buffer.CurrentSnapshot + let startLineNumber = snapshot.GetLineNumberFromPosition(trackingSpan.GetStartPoint(snapshot).Position) + let uiElement = + if self.uiElements.ContainsKey trackingSpan then + logErrorf "Added a tracking span twice, this is not allowed and will result in invalid values! %A" (trackingSpan.GetText snapshot) + self.uiElements.[trackingSpan] + else + let defaultStackPanel = self.createDefaultStackPanel() + self.uiElements.[trackingSpan] <- defaultStackPanel + defaultStackPanel + if self.trackingSpans.ContainsKey startLineNumber then + self.trackingSpans.[startLineNumber].Add trackingSpan + let neighbour = + self.uiElements.[self.trackingSpans.[startLineNumber] |> Seq.last] // This fails if a tracking span has no ui element! + self.uiElementNeighbour.[uiElement] <- neighbour + self.trackingSpanUiParent.Add trackingSpan |> ignore + else + self.trackingSpans.[startLineNumber] <- ResizeArray() + self.trackingSpans.[startLineNumber].Add trackingSpan + uiElement + + + member self.handleBufferChanged(e:TextContentChangedEventArgs) = + try + let oldSnapshot = e.Before + let snapshot = e.After + self.currentBufferSnapshot <- snapshot + for line in oldSnapshot.Lines do + let lineNumber = line.LineNumber + self.updateTrackingSpansFast snapshot lineNumber + let firstLine = view.TextViewLines.FirstVisibleLine + view.DisplayTextLineContainingBufferPosition (firstLine.Start, 0., ViewRelativePosition.Top) + self.RelayoutRequested.Enqueue(()) + with e -> logErrorf "Error in line lens provider: %A" e + + /// Public non-thread-safe method to add line lens for a given tracking span. + /// Returns an UIElement which can be used to add Ui elements and to remove the line lens later. + + member self.AddCodeLens (trackingSpan:ITrackingSpan) = + if trackingSpan.TextBuffer <> buffer then failwith "TrackingSpan text buffer does not equal with CodeLens text buffer" + let Grid = self.addTrackingSpan trackingSpan + self.RelayoutRequested.Enqueue(()) + Grid :> UIElement + + /// Public non-thread-safe method to remove line lens for a given tracking span. + member self.RemoveCodeLens (trackingSpan:ITrackingSpan) = + if self.uiElements.ContainsKey trackingSpan then + let Grid = self.uiElements.[trackingSpan] + Grid.Children.Clear() + self.uiElements.Remove trackingSpan |> ignore + try + self.codeLensLayer.RemoveAdornment(Grid) + with e -> + logExceptionWithContext(e, "Removing line lens") + else + logWarningf "No ui element is attached to this tracking span!" + let lineNumber = + (trackingSpan.GetStartPoint self.currentBufferSnapshot).Position + |> self.currentBufferSnapshot.GetLineNumberFromPosition + if self.trackingSpans.ContainsKey lineNumber then + if self.trackingSpans.[lineNumber].Remove trackingSpan |> not then + logWarningf "No tracking span is accociated with this line number %d!" lineNumber + if self.trackingSpans.[lineNumber].Count = 0 then + self.trackingSpans.Remove lineNumber |> ignore + else + logWarningf "No tracking span is accociated with this line number %d!" lineNumber + + abstract member AddUiElementToCodeLens : ITrackingSpan * UIElement -> unit + default self.AddUiElementToCodeLens (trackingSpan:ITrackingSpan, uiElement:UIElement) = + let Grid = self.uiElements.[trackingSpan] + Grid.Children.Add uiElement |> ignore + + abstract member AddUiElementToCodeLensOnce : ITrackingSpan * UIElement -> unit + default self.AddUiElementToCodeLensOnce (trackingSpan:ITrackingSpan, uiElement:UIElement)= + let Grid = self.uiElements.[trackingSpan] + if uiElement |> Grid.Children.Contains |> not then + self.AddUiElementToCodeLens (trackingSpan, uiElement) + + abstract member RemoveUiElementFromCodeLens : ITrackingSpan * UIElement -> unit + default self.RemoveUiElementFromCodeLens (trackingSpan:ITrackingSpan, uiElement:UIElement) = + let Grid = self.uiElements.[trackingSpan] + Grid.Children.Remove(uiElement) |> ignore + + member self.handleLayoutChanged (e:TextViewLayoutChangedEventArgs) = + try + let buffer = e.NewSnapshot + let recentVisibleLineNumbers = Set [self.recentFirstVsblLineNmbr .. self.recentLastVsblLineNmbr] + let firstVisibleLineNumber, lastVisibleLineNumber = + let first, last = + view.TextViewLines.FirstVisibleLine, + view.TextViewLines.LastVisibleLine + buffer.GetLineNumberFromPosition(first.Start.Position), + buffer.GetLineNumberFromPosition(last.Start.Position) + let visibleLineNumbers = Set [firstVisibleLineNumber .. lastVisibleLineNumber] + let nonVisibleLineNumbers = Set.difference recentVisibleLineNumbers visibleLineNumbers + let newVisibleLineNumbers = Set.difference visibleLineNumbers recentVisibleLineNumbers + + let applyFuncOnLineStackPanels (line:IWpfTextViewLine) (func:Grid -> unit) = + let lineNumber = line.Snapshot.GetLineNumberFromPosition(line.Start.Position) + if (self.trackingSpans.ContainsKey lineNumber) && (self.trackingSpans.[lineNumber]) |> (Seq.isEmpty >> not) then + for trackingSpan in self.trackingSpans.[lineNumber] do + let success, ui = self.uiElements.TryGetValue trackingSpan + if success then + func ui + + if nonVisibleLineNumbers.Count > 0 || newVisibleLineNumbers.Count > 0 then + for lineNumber in nonVisibleLineNumbers do + if lineNumber > 0 && lineNumber < buffer.LineCount then + try + let line = + (buffer.GetLineFromLineNumber lineNumber).Start + |> view.GetTextViewLineContainingBufferPosition + applyFuncOnLineStackPanels line (fun ui -> + ui.Visibility <- Visibility.Hidden + ) + with e -> logErrorf "Error in non visible lines iteration %A" e + for lineNumber in newVisibleLineNumbers do + try + let line = + (buffer.GetLineFromLineNumber lineNumber).Start + |> view.GetTextViewLineContainingBufferPosition + applyFuncOnLineStackPanels line (fun ui -> + ui.Visibility <- Visibility.Visible + self.layoutUIElementOnLine view line ui + ) + with e -> logErrorf "Error in new visible lines iteration %A" e + if not e.VerticalTranslation && e.NewViewState.ViewportHeight <> e.OldViewState.ViewportHeight then + self.RelayoutRequested.Enqueue() // Unfortunately zooming requires a relayout too, to ensure that no weird layout happens due to unkown reasons. + if self.RelayoutRequested.Count > 0 then + self.RelayoutRequested.Dequeue() |> ignore + for lineNumber in visibleLineNumbers do + let line = + (buffer.GetLineFromLineNumber lineNumber).Start + |> view.GetTextViewLineContainingBufferPosition + applyFuncOnLineStackPanels line (fun ui -> + ui.Visibility <- Visibility.Visible + self.layoutUIElementOnLine view line ui + ) + // Save the new first and last visible lines for tracking + self.recentFirstVsblLineNmbr <- firstVisibleLineNumber + self.recentLastVsblLineNmbr <- lastVisibleLineNumber + // We can cancel existing stuff because the algorithm supports abortion without any data loss + self.layoutChangedCts.Cancel() + self.layoutChangedCts.Dispose() + self.layoutChangedCts <- new CancellationTokenSource() + + self.asyncCustomLayoutOperation visibleLineNumbers buffer + |> RoslynHelpers.StartAsyncSafe self.layoutChangedCts.Token + with e -> logExceptionWithContext (e, "Layout changed") + + abstract layoutUIElementOnLine : IWpfTextView -> ITextViewLine -> Grid -> unit + + abstract asyncCustomLayoutOperation : int Set -> ITextSnapshot -> unit Async + + + diff --git a/vsintegration/src/FSharp.Editor/CodeLens/CodeLensGeneralTagger.fs b/vsintegration/src/FSharp.Editor/CodeLens/CodeLensGeneralTagger.fs new file mode 100644 index 00000000000..3d3a2a61f50 --- /dev/null +++ b/vsintegration/src/FSharp.Editor/CodeLens/CodeLensGeneralTagger.fs @@ -0,0 +1,153 @@ +// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. + +namespace rec Microsoft.VisualStudio.FSharp.Editor + +open System +open System.Windows.Controls +open Microsoft.VisualStudio.Text +open Microsoft.VisualStudio.Text.Editor +open Microsoft.VisualStudio.Text.Formatting +open System.Windows +open System.Collections.Generic +open Microsoft.VisualStudio.Text.Tagging + +open Microsoft.VisualStudio.FSharp.Editor.Logging + +type CodeLensGeneralTag(width, topSpace, baseline, textHeight, bottomSpace, affinity, tag:obj, providerTag:obj) = + inherit SpaceNegotiatingAdornmentTag(width, topSpace, baseline, textHeight, bottomSpace, affinity, tag, providerTag) + +/// Class which provides support for general code lens +/// Use the methods AddCodeLens and RemoveCodeLens +type CodeLensGeneralTagger (view, buffer) as self = + inherit CodeLensDisplayService(view, buffer, "CodeLens") + + /// The tags changed event to notify if the data for the tags has changed. + let tagsChangedEvent = new Event,SnapshotSpanEventArgs>() + + /// Layouts all stack panels on the line + override self.layoutUIElementOnLine (view:IWpfTextView) (line:ITextViewLine) (ui:Grid) = + let left, top = + match self.uiElementNeighbour.TryGetValue ui with + | true, parent -> + let left = Canvas.GetLeft parent + let top = Canvas.GetTop parent + let width = parent.ActualWidth + logInfof "Width of parent: %.4f" width + left + width, top + | _ -> + try + // Get the real offset so that the code lens are placed respectively to their content + let offset = + [0..line.Length - 1] |> Seq.tryFind (fun i -> not (Char.IsWhiteSpace (line.Start.Add(i).GetChar()))) + |> Option.defaultValue 0 + + let realStart = line.Start.Add(offset) + let g = view.TextViewLines.GetCharacterBounds(realStart) + // WORKAROUND VS BUG, left cannot be zero if the offset is creater than zero! + // Calling the method twice fixes this bug and ensures that all values are correct. + // Okay not really :( Must be replaced later with an own calculation depending on editor font settings! + if 7 * offset > int g.Left then + logErrorf "Incorrect return from geometry measure" + Canvas.GetLeft ui, g.Top + else + g.Left, g.Top + with e -> + logExceptionWithContext (e, "Error in layout ui element on line") + Canvas.GetLeft ui, Canvas.GetTop ui + Canvas.SetLeft(ui, left) + Canvas.SetTop(ui, top) + + override self.asyncCustomLayoutOperation _ _ = + asyncMaybe { + // Suspend 16 ms, instantly applying the layout to the adornment elements isn't needed + // and would consume too much performance + do! Async.Sleep(16) |> liftAsync // Skip at least one frames + do! Async.SwitchToContext self.uiContext |> liftAsync + let layer = self.codeLensLayer + + do! Async.Sleep(495) |> liftAsync + + // WORKAROUND FOR VS BUG + // The layout changed event may not provide us all real changed lines so + // we take care of this on our own. + let visibleSpan = + let first, last = + view.TextViewLines.FirstVisibleLine, + view.TextViewLines.LastVisibleLine + SnapshotSpan(first.Start, last.End) + let customVisibleLines = view.TextViewLines.GetTextViewLinesIntersectingSpan visibleSpan + let isLineVisible (line:ITextViewLine) = line.IsValid + let linesToProcess = customVisibleLines |> Seq.filter isLineVisible + + for line in linesToProcess do + try + match line.GetAdornmentTags self |> Seq.tryHead with + | Some (:? seq as stackPanels) -> + for stackPanel in stackPanels do + if stackPanel |> self.addedAdornments.Contains |> not then + layer.AddAdornment(AdornmentPositioningBehavior.OwnerControlled, Nullable(), + self, stackPanel, AdornmentRemovedCallback(fun _ _ -> ())) |> ignore + self.addedAdornments.Add stackPanel |> ignore + | _ -> () + with e -> logExceptionWithContext (e, "LayoutChanged, processing new visible lines") + } |> Async.Ignore + + override self.AddUiElementToCodeLens (trackingSpan:ITrackingSpan, uiElement:UIElement)= + base.AddUiElementToCodeLens (trackingSpan, uiElement) // We do the same as the base call execpt that we need to notify that the tag needs to be refreshed. + tagsChangedEvent.Trigger(self, SnapshotSpanEventArgs(trackingSpan.GetSpan(buffer.CurrentSnapshot))) + + override self.RemoveUiElementFromCodeLens (trackingSpan:ITrackingSpan, uiElement:UIElement) = + base.RemoveUiElementFromCodeLens (trackingSpan, uiElement) + tagsChangedEvent.Trigger(self, SnapshotSpanEventArgs(trackingSpan.GetSpan(buffer.CurrentSnapshot))) // Need to refresh the tag. + + interface ITagger with + [] + override __.TagsChanged = tagsChangedEvent.Publish + + /// Returns the tags which reserve the correct space for adornments + /// Notice, it's asumed that the data in the collection is valid. + override __.GetTags spans = + try + seq { + for span in spans do + let snapshot = span.Snapshot + let lineNumber = + try + snapshot.GetLineNumberFromPosition(span.Start.Position) + with e -> logExceptionWithContext (e, "line number tagging"); 0 + if self.trackingSpans.ContainsKey(lineNumber) && self.trackingSpans.[lineNumber] |> Seq.isEmpty |> not then + + let tagSpan = snapshot.GetLineFromLineNumber(lineNumber).Extent + let stackPanels = + self.trackingSpans.[lineNumber] + |> Seq.map (fun trackingSpan -> + let success, res = self.uiElements.TryGetValue trackingSpan + if success then res else null + ) + |> Seq.filter (isNull >> not) + let span = + try + tagSpan.TranslateTo(span.Snapshot, SpanTrackingMode.EdgeExclusive) + with e -> logExceptionWithContext (e, "tag span translation"); tagSpan + let sizes = + try + stackPanels |> Seq.map (fun ui -> + ui.Measure(Size(10000., 10000.)) + ui.DesiredSize ) + with e -> logExceptionWithContext (e, "internal tagging"); Seq.empty + let height = + try + sizes + |> Seq.map (fun size -> size.Height) + |> Seq.sortDescending + |> Seq.tryHead + |> Option.defaultValue 0. + with e -> logExceptionWithContext (e, "height tagging"); 0. + + yield TagSpan(span, CodeLensGeneralTag(0., height, 0., 0., 0., PositionAffinity.Predecessor, stackPanels, self)) :> ITagSpan + } + with e -> + logErrorf "Error in code lens get tags %A" e + Seq.empty + + diff --git a/vsintegration/src/FSharp.Editor/CodeLens/CodeLensProvider.fs b/vsintegration/src/FSharp.Editor/CodeLens/CodeLensProvider.fs new file mode 100644 index 00000000000..b5092b32cd7 --- /dev/null +++ b/vsintegration/src/FSharp.Editor/CodeLens/CodeLensProvider.fs @@ -0,0 +1,109 @@ +// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. + +namespace rec Microsoft.VisualStudio.FSharp.Editor + + +open System +open Microsoft.VisualStudio.Text +open Microsoft.VisualStudio.Text.Editor +open System.ComponentModel.Composition +open Microsoft.VisualStudio.Utilities +open Microsoft.CodeAnalysis +open Microsoft.VisualStudio.Shell +open Microsoft.VisualStudio +open Microsoft.VisualStudio.LanguageServices +open System.Collections.Generic +open Microsoft.CodeAnalysis.Editor.Shared.Utilities +open Microsoft.VisualStudio.Text.Tagging +open Microsoft.VisualStudio.Text.Classification +open Microsoft.VisualStudio.ComponentModelHost +open System.Threading +open Microsoft.VisualStudio.FSharp.Editor.Logging + +[)>] +[)>] +[)>] +[] +[] +type internal CodeLensProvider + [] + ( + textDocumentFactory: ITextDocumentFactoryService, + checkerProvider: FSharpCheckerProvider, + projectInfoManager: FSharpProjectOptionsManager, + typeMap : ClassificationTypeMap Lazy, + gotoDefinitionService: FSharpGoToDefinitionService + ) = + + let lineLensProvider = ResizeArray() + let taggers = ResizeArray() + let componentModel = Package.GetGlobalService(typeof) :?> ComponentModelHost.IComponentModel + let workspace = componentModel.GetService() + + /// Returns an provider for the textView if already one has been created. Else create one. + let addCodeLensProviderOnce wpfView buffer = + let res = taggers |> Seq.tryFind(fun (view, _) -> view = wpfView) + match res with + | Some (_, (tagger, _)) -> tagger + | None -> + let documentId = + lazy ( + match textDocumentFactory.TryGetTextDocument(buffer) with + | true, textDocument -> + Seq.tryHead (workspace.CurrentSolution.GetDocumentIdsWithFilePath(textDocument.FilePath)) + | _ -> None + |> Option.get + ) + + let tagger = CodeLensGeneralTagger(wpfView, buffer) + let service = FSharpCodeLensService(workspace, documentId, buffer, checkerProvider.Checker, projectInfoManager, componentModel.GetService(), typeMap, gotoDefinitionService, tagger) + let provider = (wpfView, (tagger, service)) + wpfView.Closed.Add (fun _ -> taggers.Remove provider |> ignore) + taggers.Add((wpfView, (tagger, service))) + tagger + + /// Returns an provider for the textView if already one has been created. Else create one. + let addLineLensProviderOnce wpfView buffer = + let res = lineLensProvider |> Seq.tryFind(fun (view, _) -> view = wpfView) + match res with + | None -> + let documentId = + lazy ( + match textDocumentFactory.TryGetTextDocument(buffer) with + | true, textDocument -> + Seq.tryHead (workspace.CurrentSolution.GetDocumentIdsWithFilePath(textDocument.FilePath)) + | _ -> None + |> Option.get + ) + let service = FSharpCodeLensService(workspace, documentId, buffer, checkerProvider.Checker, projectInfoManager, componentModel.GetService(), typeMap, gotoDefinitionService, LineLensDisplayService(wpfView, buffer)) + let provider = (wpfView, service) + wpfView.Closed.Add (fun _ -> lineLensProvider.Remove provider |> ignore) + lineLensProvider.Add(provider) + | _ -> () + + [); Name("CodeLens"); + Order(Before = PredefinedAdornmentLayers.Text); + TextViewRole(PredefinedTextViewRoles.Document)>] + member val CodeLensAdornmentLayerDefinition : AdornmentLayerDefinition = null with get, set + + [); Name("LineLens"); + Order(Before = PredefinedAdornmentLayers.Text); + TextViewRole(PredefinedTextViewRoles.Document)>] + member val LineLensAdornmentLayerDefinition : AdornmentLayerDefinition = null with get, set + + interface IViewTaggerProvider with + override __.CreateTagger(view, buffer) = + if Settings.CodeLens.Enabled && not Settings.CodeLens.ReplaceWithLineLens then + let wpfView = + match view with + | :? IWpfTextView as view -> view + | _ -> failwith "error" + + box(addCodeLensProviderOnce wpfView buffer) :?> _ + else + null + + interface IWpfTextViewCreationListener with + override __.TextViewCreated view = + if Settings.CodeLens.Enabled && Settings.CodeLens.ReplaceWithLineLens then + addLineLensProviderOnce view (view.TextBuffer) |> ignore diff --git a/vsintegration/src/FSharp.Editor/CodeLens/FSharpCodeLensService.fs b/vsintegration/src/FSharp.Editor/CodeLens/FSharpCodeLensService.fs new file mode 100644 index 00000000000..9be718fed98 --- /dev/null +++ b/vsintegration/src/FSharp.Editor/CodeLens/FSharpCodeLensService.fs @@ -0,0 +1,385 @@ +// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. + +namespace rec Microsoft.VisualStudio.FSharp.Editor + + +open System +open System.Windows.Controls +open System.Windows.Media +open Microsoft.VisualStudio.Text +open Microsoft.VisualStudio.Text.Formatting +open Microsoft.CodeAnalysis +open System.Threading +open Microsoft.FSharp.Compiler.SourceCodeServices +open System.Windows +open System.Collections.Generic +open Microsoft.FSharp.Compiler.Range +open Microsoft.FSharp.Compiler +open Microsoft.FSharp.Compiler.Ast +open Microsoft.CodeAnalysis.Editor.Shared.Extensions +open Microsoft.CodeAnalysis.Editor.Shared.Utilities +open Microsoft.CodeAnalysis.Classification +open Internal.Utilities.StructuredFormat +open System.Windows.Media.Animation + +open Microsoft.VisualStudio.FSharp.Editor.Logging +open Microsoft.VisualStudio.Text.Classification + +type internal CodeLens(taggedText, computed, fullTypeSignature, uiElement) = + member val TaggedText: Async<(ResizeArray * QuickInfoNavigation) option> = taggedText + member val Computed: bool = computed with get, set + member val FullTypeSignature: string = fullTypeSignature + member val UiElement: UIElement = uiElement with get, set + +type internal FSharpCodeLensService + ( + workspace: Workspace, + documentId: Lazy, + buffer: ITextBuffer, + checker: FSharpChecker, + projectInfoManager: FSharpProjectOptionsManager, + classificationFormatMapService: IClassificationFormatMapService, + typeMap: Lazy, + gotoDefinitionService: FSharpGoToDefinitionService, + codeLens : CodeLensDisplayService + ) as self = + + let lineLens = codeLens + + let visit pos parseTree = + AstTraversal.Traverse(pos, parseTree, { new AstTraversal.AstVisitorBase<_>() with + member __.VisitExpr(_path, traverseSynExpr, defaultTraverse, expr) = + defaultTraverse(expr) + + override __.VisitInheritSynMemberDefn (_, _, _, _, range) = Some range + + override __.VisitTypeAbbrev( _, range) = Some range + + override __.VisitLetOrUse(binding, range) = Some range + + override __.VisitBinding (fn, binding) = + Some binding.RangeOfBindingAndRhs + }) + + let formatMap = lazy classificationFormatMapService.GetClassificationFormatMap "tooltip" + + let mutable lastResults = Dictionary() + let mutable firstTimeChecked = false + let mutable bufferChangedCts = new CancellationTokenSource() + let uiContext = SynchronizationContext.Current + + let layoutTagToFormatting (layoutTag: LayoutTag) = + layoutTag + |> RoslynHelpers.roslynTag + |> ClassificationTags.GetClassificationTypeName + |> typeMap.Value.GetClassificationType + |> formatMap.Value.GetTextProperties + + let createTextBox (lens:CodeLens) = + async { + do! Async.SwitchToContext uiContext + let! res = lens.TaggedText + match res with + | Some (taggedText, navigation) -> + logInfof "Tagged text %A" taggedText + let textBlock = new TextBlock(Background = Brushes.AliceBlue, Opacity = 0.0, TextTrimming = TextTrimming.None) + DependencyObjectExtensions.SetDefaultTextProperties(textBlock, formatMap.Value) + + let prefix = Documents.Run Settings.CodeLens.Prefix + prefix.Foreground <- SolidColorBrush(Color.FromRgb(153uy, 153uy, 153uy)) + textBlock.Inlines.Add prefix + + for text in taggedText do + + let coloredProperties = layoutTagToFormatting text.Tag + let actualProperties = + if Settings.CodeLens.UseColors + then + // If color is gray (R=G=B), change to correct gray color. + // Otherwise, use the provided color. + match coloredProperties.ForegroundBrush with + | :? SolidColorBrush as b -> + let c = b.Color + if c.R = c.G && c.R = c.B + then coloredProperties.SetForeground(Color.FromRgb(153uy, 153uy, 153uy)) + else coloredProperties + | _ -> coloredProperties + else + coloredProperties.SetForeground(Color.FromRgb(153uy, 153uy, 153uy)) + + let run = Documents.Run text.Text + DependencyObjectExtensions.SetTextProperties (run, actualProperties) + + let inl = + match text with + | :? Layout.NavigableTaggedText as nav when navigation.IsTargetValid nav.Range -> + let h = Documents.Hyperlink(run, ToolTip = nav.Range.FileName) + h.Click.Add (fun _ -> + navigation.NavigateTo nav.Range) + h :> Documents.Inline + | _ -> run :> _ + DependencyObjectExtensions.SetTextProperties (inl, actualProperties) + textBlock.Inlines.Add inl + + + textBlock.Measure(Size(Double.PositiveInfinity, Double.PositiveInfinity)) + lens.Computed <- true + lens.UiElement <- textBlock + return true + | _ -> + return false + } + + let StartAsyncSafe cancellationToken context computation = + let computation = + async { + try + return! computation + with e -> + logExceptionWithContext(e, context) + return Unchecked.defaultof<_> + } + Async.Start (computation, cancellationToken) + + let executeCodeLenseAsync () = + asyncMaybe { + do! Async.Sleep 800 |> liftAsync + logInfof "Rechecking code due to buffer edit!" + let! document = workspace.CurrentSolution.GetDocument(documentId.Value) |> Option.ofObj + let! _, options = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document) + let! _, parsedInput, checkFileResults = checker.ParseAndCheckDocument(document, options, true, "LineLens") + logInfof "Getting uses of all symbols!" + let! symbolUses = checkFileResults.GetAllUsesOfAllSymbolsInFile() |> liftAsync + let textSnapshot = buffer.CurrentSnapshot + logInfof "Updating due to buffer edit!" + + // Clear existing data and cache flags + // The results which are left. + let oldResults = Dictionary(lastResults) + + let newResults = Dictionary() + // Symbols which cache wasn't found yet + let unattachedSymbols = ResizeArray() + // Tags which are new or need to be updated due to changes. + let tagsToUpdate = Dictionary() + let codeLensToAdd = ResizeArray() + + let useResults (displayContext: FSharpDisplayContext, func: FSharpMemberOrFunctionOrValue, realPosition: range) = + async { + try + let textSnapshot = buffer.CurrentSnapshot + let lineNumber = Line.toZ func.DeclarationLocation.StartLine + if (lineNumber >= 0 || lineNumber < textSnapshot.LineCount) then + match func.FullTypeSafe with + | Some ty -> + let! displayEnv = checkFileResults.GetDisplayEnvForPos func.DeclarationLocation.Start + + let displayContext = + match displayEnv with + | Some denv -> FSharpDisplayContext(fun _ -> denv) + | None -> displayContext + + let typeLayout = func.FormatLayout displayContext + let taggedText = ResizeArray() + + Layout.renderL (Layout.taggedTextListR taggedText.Add) typeLayout |> ignore + let navigation = QuickInfoNavigation(gotoDefinitionService, document, realPosition) + // Because the data is available notify that this line should be updated, displaying the results + return Some (taggedText, navigation) + | None -> + logWarningf "Couldn't acquire CodeLens data for function %A" func + return None + else return None + with e -> + logErrorf "Error in lazy line lens computation. %A" e + return None + } + + let inline setNewResultsAndWarnIfOverriden fullDeclarationText value = + if newResults.ContainsKey fullDeclarationText then + logWarningf "New results already contains: %A" fullDeclarationText + newResults.[fullDeclarationText] <- value + + for symbolUse in symbolUses do + if symbolUse.IsFromDefinition then + match symbolUse.Symbol with + | :? FSharpMemberOrFunctionOrValue as func when func.IsModuleValueOrMember || func.IsProperty -> + let funcID = func.FullName + let fullDeclarationText = funcID + let fullTypeSignature = func.FullType.ToString() + // Try to re-use the last results + if lastResults.ContainsKey fullDeclarationText then + // Make sure that the results are usable + let inline setNewResultsAndWarnIfOverridenLocal value = setNewResultsAndWarnIfOverriden fullDeclarationText value + let lastTrackingSpan, codeLens as lastResult = lastResults.[fullDeclarationText] + if codeLens.FullTypeSignature = fullTypeSignature then + setNewResultsAndWarnIfOverridenLocal lastResult + oldResults.Remove fullDeclarationText |> ignore + else + let declarationLine, range = + match visit func.DeclarationLocation.Start parsedInput with + | Some range -> range.StartLine - 1, range + | _ -> func.DeclarationLocation.StartLine - 1, func.DeclarationLocation + // Track the old element for removal + let declarationSpan = + let line = textSnapshot.GetLineFromLineNumber declarationLine + let offset = line.GetText() |> Seq.findIndex (Char.IsWhiteSpace >> not) + SnapshotSpan(line.Start.Add offset, line.End).Span + let newTrackingSpan = + textSnapshot.CreateTrackingSpan(declarationSpan, SpanTrackingMode.EdgeExclusive) + // Push back the new results + let res = + CodeLens( Async.cache (useResults (symbolUse.DisplayContext, func, range)), + false, + fullTypeSignature, + null) + // The old results aren't computed at all, because the line might have changed create new results + tagsToUpdate.[lastTrackingSpan] <- (newTrackingSpan, fullDeclarationText, res) + setNewResultsAndWarnIfOverridenLocal (newTrackingSpan, res) + + oldResults.Remove fullDeclarationText |> ignore + else + // The symbol might be completely new or has slightly changed. + // We need to track this and iterate over the left entries to ensure that there isn't anything + unattachedSymbols.Add((symbolUse, func, fullDeclarationText, fullTypeSignature)) + | _ -> () + + // In best case this works quite `covfefe` fine because often enough we change only a small part of the file and not the complete. + for unattachedSymbol in unattachedSymbols do + let symbolUse, func, fullDeclarationText, fullTypeSignature = unattachedSymbol + let declarationLine, range = + match visit func.DeclarationLocation.Start parsedInput with + | Some range -> range.StartLine - 1, range + | _ -> func.DeclarationLocation.StartLine - 1, func.DeclarationLocation + + let test (v:KeyValuePair<_, _>) = + let _, (codeLens:CodeLens) = v.Value + codeLens.FullTypeSignature = fullTypeSignature + match oldResults |> Seq.tryFind test with + | Some res -> + let (trackingSpan : ITrackingSpan), (codeLens : CodeLens) = res.Value + let declarationSpan = + let line = textSnapshot.GetLineFromLineNumber declarationLine + let offset = line.GetText() |> Seq.findIndex (Char.IsWhiteSpace >> not) + SnapshotSpan(line.Start.Add offset, line.End).Span + let newTrackingSpan = + textSnapshot.CreateTrackingSpan(declarationSpan, SpanTrackingMode.EdgeExclusive) + if codeLens.Computed && (isNull codeLens.UiElement |> not) then + newResults.[fullDeclarationText] <- (newTrackingSpan, codeLens) + tagsToUpdate.[trackingSpan] <- (newTrackingSpan, fullDeclarationText, codeLens) + else + let res = + CodeLens( + Async.cache (useResults (symbolUse.DisplayContext, func, range)), + false, + fullTypeSignature, + null) + // The tag might be still valid but it hasn't been computed yet so create fresh results + tagsToUpdate.[trackingSpan] <- (newTrackingSpan, fullDeclarationText, res) + newResults.[fullDeclarationText] <- (newTrackingSpan, res) + let key = res.Key + oldResults.Remove key |> ignore // no need to check this entry again + | None -> + // This function hasn't got any cache and so it's completely new. + // So create completely new results + // And finally add a tag for this. + let res = + CodeLens( + Async.cache (useResults (symbolUse.DisplayContext, func, range)), + false, + fullTypeSignature, + null) + try + let declarationSpan = + let line = textSnapshot.GetLineFromLineNumber declarationLine + let offset = line.GetText() |> Seq.findIndex (Char.IsWhiteSpace >> not) + SnapshotSpan(line.Start.Add offset, line.End).Span + let trackingSpan = + textSnapshot.CreateTrackingSpan(declarationSpan, SpanTrackingMode.EdgeExclusive) + codeLensToAdd.Add (trackingSpan, res) + newResults.[fullDeclarationText] <- (trackingSpan, res) + with e -> logExceptionWithContext (e, "Line Lens tracking tag span creation") + () + lastResults <- newResults + do! Async.SwitchToContext uiContext |> liftAsync + let createCodeLensUIElement (codeLens:CodeLens) trackingSpan _ = + if codeLens.Computed |> not then + async { + let! res = createTextBox codeLens + if res then + do! Async.SwitchToContext uiContext + logInfof "Adding ui element for %A" (codeLens.TaggedText) + let uiElement = codeLens.UiElement + let animation = + DoubleAnimation( + To = Nullable 0.8, + Duration = (TimeSpan.FromMilliseconds 800. |> Duration.op_Implicit), + EasingFunction = QuadraticEase() + ) + let sb = Storyboard() + Storyboard.SetTarget(sb, uiElement) + Storyboard.SetTargetProperty(sb, PropertyPath Control.OpacityProperty) + sb.Children.Add animation + lineLens.AddUiElementToCodeLensOnce (trackingSpan, uiElement) + lineLens.RelayoutRequested.Enqueue () + sb.Begin() + else + logWarningf "Couldn't retrieve code lens information for %A" codeLens.FullTypeSignature + // logInfo "Adding text box!" + } |> StartAsyncSafe CancellationToken.None "UIElement creation" + + for value in tagsToUpdate do + let trackingSpan, (newTrackingSpan, _, codeLens) = value.Key, value.Value + // logInfof "Adding ui element for %A" (codeLens.TaggedText) + lineLens.RemoveCodeLens trackingSpan |> ignore + let Grid = lineLens.AddCodeLens newTrackingSpan + // logInfof "Trackingspan %A is being added." trackingSpan + if codeLens.Computed && (isNull codeLens.UiElement |> not) then + let uiElement = codeLens.UiElement + lineLens.AddUiElementToCodeLensOnce (newTrackingSpan, uiElement) + else + Grid.IsVisibleChanged + |> Event.filter (fun eventArgs -> eventArgs.NewValue :?> bool) + |> Event.add (createCodeLensUIElement codeLens newTrackingSpan) + + for value in codeLensToAdd do + let trackingSpan, codeLens = value + let Grid = lineLens.AddCodeLens trackingSpan + logInfof "Trackingspan %A is being added." trackingSpan + + Grid.IsVisibleChanged + |> Event.filter (fun eventArgs -> eventArgs.NewValue :?> bool) + |> Event.add (createCodeLensUIElement codeLens trackingSpan) + + for oldResult in oldResults do + let trackingSpan, _ = oldResult.Value + // logInfof "removing trackingSpan %A" trackingSpan + lineLens.RemoveCodeLens trackingSpan |> ignore + + logInfof "Finished updating line lens." + + if not firstTimeChecked then + firstTimeChecked <- true + } |> Async.Ignore + + do + begin + buffer.Changed.AddHandler(fun _ e -> (self.BufferChanged e)) + async { + let mutable numberOfFails = 0 + while not firstTimeChecked && numberOfFails < 10 do + try + do! executeCodeLenseAsync() + do! Async.Sleep(1000) + with + | e -> logErrorf "Line Lens startup failed with: %A" e + numberOfFails <- numberOfFails + 1 + } |> Async.Start + end + + member __.BufferChanged ___ = + bufferChangedCts.Cancel() // Stop all ongoing async workflow. + bufferChangedCts.Dispose() + bufferChangedCts <- new CancellationTokenSource() + executeCodeLenseAsync () |> Async.Ignore |> RoslynHelpers.StartAsyncSafe bufferChangedCts.Token + diff --git a/vsintegration/src/FSharp.Editor/CodeLens/LineLensDisplayService.fs b/vsintegration/src/FSharp.Editor/CodeLens/LineLensDisplayService.fs new file mode 100644 index 00000000000..be49b79d036 --- /dev/null +++ b/vsintegration/src/FSharp.Editor/CodeLens/LineLensDisplayService.fs @@ -0,0 +1,67 @@ +// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. + +namespace rec Microsoft.VisualStudio.FSharp.Editor + + +open System +open System.Windows.Controls +open Microsoft.VisualStudio.Text +open Microsoft.VisualStudio.Text.Editor +open Microsoft.VisualStudio.Text.Formatting +open System.Windows +open System.Collections.Generic + +open Microsoft.VisualStudio.FSharp.Editor.Logging + +type internal LineLensDisplayService (view, buffer) = + inherit CodeLensDisplayService(view, buffer, "LineLens") + + /// Layouts all stack panels on the line + override self.layoutUIElementOnLine _ (line:ITextViewLine) (ui:Grid) = + let left, top = + match self.uiElementNeighbour.TryGetValue ui with + | true, parent -> + let left = Canvas.GetLeft parent + let top = Canvas.GetTop parent + let width = parent.ActualWidth + left + width, top + | _ -> + try + let bounds = line.GetCharacterBounds(line.Start) + line.TextRight + 5.0, bounds.Top - 1. + with e -> + logExceptionWithContext (e, "Error in layout ui element on line") + Canvas.GetLeft ui, Canvas.GetTop ui + Canvas.SetLeft(ui, left) + Canvas.SetTop(ui, top) + + override self.asyncCustomLayoutOperation visibleLineNumbers buffer = + asyncMaybe { + // Suspend 5 ms, instantly applying the layout to the adornment elements isn't needed + // and would consume too much performance + do! Async.Sleep(5) |> liftAsync // Skip at least one frames + do! Async.SwitchToContext self.uiContext |> liftAsync + let layer = self.codeLensLayer + do! Async.Sleep(495) |> liftAsync + try + for visibleLineNumber in visibleLineNumbers do + if self.trackingSpans.ContainsKey visibleLineNumber then + self.trackingSpans.[visibleLineNumber] + |> Seq.map (fun trackingSpan -> + let success, res = self.uiElements.TryGetValue trackingSpan + if success then + res + else null + ) + |> Seq.filter (fun ui -> not(isNull ui) && not(self.addedAdornments.Contains ui)) + |> Seq.iter(fun grid -> + layer.AddAdornment(AdornmentPositioningBehavior.OwnerControlled, Nullable(), + self, grid, AdornmentRemovedCallback(fun _ _ -> self.addedAdornments.Remove grid |> ignore)) |> ignore + self.addedAdornments.Add grid |> ignore + let line = + let l = buffer.GetLineFromLineNumber visibleLineNumber + view.GetTextViewLineContainingBufferPosition l.Start + self.layoutUIElementOnLine view line grid + ) + with e -> logExceptionWithContext (e, "LayoutChanged, processing new visible lines") + } |> Async.Ignore \ No newline at end of file diff --git a/vsintegration/src/FSharp.Editor/Common/Constants.fs b/vsintegration/src/FSharp.Editor/Common/Constants.fs index ec876ff9d5e..bc9b33b50cf 100644 --- a/vsintegration/src/FSharp.Editor/Common/Constants.fs +++ b/vsintegration/src/FSharp.Editor/Common/Constants.fs @@ -64,6 +64,10 @@ module internal Guids = [] /// "9A66EB6A-DE52-4169-BC26-36FBD4312FD7" let codeFixesOptionPageIdString = "9A66EB6A-DE52-4169-BC26-36FBD4312FD7" + + [] + /// "00BE7FD9-8145-4A2E-A1BF-3BAF0F4F47DD" + let codeLensOptionPageIdString = "00BE7FD9-8145-4A2E-A1BF-3BAF0F4F47DD" [] /// "8FDA964A-263D-4B4E-9560-29897535217C" diff --git a/vsintegration/src/FSharp.Editor/Common/RoslynHelpers.fs b/vsintegration/src/FSharp.Editor/Common/RoslynHelpers.fs index feb1e89e57a..880d14362cf 100644 --- a/vsintegration/src/FSharp.Editor/Common/RoslynHelpers.fs +++ b/vsintegration/src/FSharp.Editor/Common/RoslynHelpers.fs @@ -159,6 +159,17 @@ module internal RoslynHelpers = let linePositionSpan = LinePositionSpan(LinePosition(Line.toZ r.StartLine, r.StartColumn), LinePosition(Line.toZ r.EndLine, r.EndColumn)) let textSpan = sourceText.Lines.GetTextSpan linePositionSpan Location.Create(filePath, textSpan, linePositionSpan) + + let StartAsyncSafe cancellationToken computation = + let computation = + async { + try + return! computation + with e -> + Assert.Exception(e) + return Unchecked.defaultof<_> + } + Async.Start (computation, cancellationToken) module internal OpenDeclarationHelper = diff --git a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj index 6d64030df35..eb2fb6ac565 100644 --- a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj +++ b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj @@ -90,6 +90,11 @@ + + + + + diff --git a/vsintegration/src/FSharp.Editor/LanguageService/LanguageService.fs b/vsintegration/src/FSharp.Editor/LanguageService/LanguageService.fs index 20bac47a9da..7bb4a6435eb 100644 --- a/vsintegration/src/FSharp.Editor/LanguageService/LanguageService.fs +++ b/vsintegration/src/FSharp.Editor/LanguageService/LanguageService.fs @@ -286,6 +286,7 @@ type [, "F#", null, "QuickInfo", "6009")>] [, "F#", null, "Code Fixes", "6010")>] [, "F#", null, "Performance", "6011")>] + [, "F#", null, "Code Lens", "6012")>] [, "F#", null, "Advanced", "6012")>] [] [, @@ -580,7 +581,8 @@ type let outliningManagerService = this.Package.ComponentModel.GetService() let wpfTextView = this.EditorAdaptersFactoryService.GetWpfTextView(textView) let outliningManager = outliningManagerService.GetOutliningManager(wpfTextView) - outliningManager.Enabled <- Settings.Advanced.IsOutliningEnabled + if not (isNull outliningManager) then + outliningManager.Enabled <- Settings.Advanced.IsOutliningEnabled match textView.GetBuffer() with | (VSConstants.S_OK, textLines) -> diff --git a/vsintegration/src/FSharp.Editor/Options/EditorOptions.fs b/vsintegration/src/FSharp.Editor/Options/EditorOptions.fs index 8444a3c1574..c157908fbaa 100644 --- a/vsintegration/src/FSharp.Editor/Options/EditorOptions.fs +++ b/vsintegration/src/FSharp.Editor/Options/EditorOptions.fs @@ -42,10 +42,15 @@ type LanguageServicePerformanceOptions = ProjectCheckCacheSize: int } [] +type CodeLensOptions = + { Enabled : bool + ReplaceWithLineLens: bool + UseColors: bool + Prefix : string } + type AdvancedOptions = { IsBlockStructureEnabled: bool IsOutliningEnabled: bool } - [)>] type internal Settings [](store: SettingsStore) = do // Initialize default settings @@ -75,12 +80,19 @@ type internal Settings [](store: SettingsStore) = { IsBlockStructureEnabled = true IsOutliningEnabled = true } + store.RegisterDefault + { Enabled = true + UseColors = false + ReplaceWithLineLens = true + Prefix = "// " } + interface ISettings static member IntelliSense : IntelliSenseOptions = getSettings() static member QuickInfo : QuickInfoOptions = getSettings() static member CodeFixes : CodeFixesOptions = getSettings() static member LanguageServicePerformance : LanguageServicePerformanceOptions = getSettings() + static member CodeLens : CodeLensOptions = getSettings() static member Advanced: AdvancedOptions = getSettings() module internal OptionsUI = @@ -116,9 +128,15 @@ module internal OptionsUI = inherit AbstractOptionPage() override this.CreateView() = upcast LanguageServicePerformanceOptionControl() + + [] + type internal CodeLensOptionPage() = + inherit AbstractOptionPage() + override this.CreateView() = + upcast CodeLensOptionControl() [] type internal AdvancedSettingsOptionPage() = inherit AbstractOptionPage() override __.CreateView() = - upcast AdvancedOptionsControl() \ No newline at end of file + upcast AdvancedOptionsControl() diff --git a/vsintegration/src/FSharp.Editor/Options/UIHelpers.fs b/vsintegration/src/FSharp.Editor/Options/UIHelpers.fs index 2fb2fe303fd..122fb5c51de 100644 --- a/vsintegration/src/FSharp.Editor/Options/UIHelpers.fs +++ b/vsintegration/src/FSharp.Editor/Options/UIHelpers.fs @@ -64,7 +64,7 @@ module internal OptionsUIHelpers = let bindCheckBox (checkBox: CheckBox) (path: string) = checkBox.SetBinding(CheckBox.IsCheckedProperty, path) |> ignore - + // some helpers to create option views in code instead of XAML let ( *** ) (control : #IAddChild) (children: UIElement list) = children |> List.iter control.AddChild diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.cs.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.cs.xlf index 4dbb91dd9b8..00a7f057973 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.cs.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.cs.xlf @@ -149,7 +149,7 @@ Advanced - Advanced + Upřesnit diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.de.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.de.xlf index 3ca77807389..da1e2d33989 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.de.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.de.xlf @@ -149,7 +149,7 @@ Advanced - Advanced + Erweitert diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.es.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.es.xlf index 85256352354..e9661c04897 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.es.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.es.xlf @@ -149,7 +149,7 @@ Advanced - Advanced + Avanzadas diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.fr.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.fr.xlf index 41681f342ed..2e41f543d26 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.fr.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.fr.xlf @@ -149,7 +149,7 @@ Advanced - Advanced + Avancé diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.it.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.it.xlf index 29050fd69f4..1becd43e91d 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.it.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.it.xlf @@ -149,7 +149,7 @@ Advanced - Advanced + Avanzate diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ja.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ja.xlf index 6c25156c901..1ea4b48b1f2 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ja.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ja.xlf @@ -149,7 +149,7 @@ Advanced - Advanced + 詳細 diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ko.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ko.xlf index bbcd41dd9ce..5c3177f7d9b 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ko.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ko.xlf @@ -149,7 +149,7 @@ Advanced - Advanced + 고급 diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pl.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pl.xlf index b9ce76f2196..50c16a27f01 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pl.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pl.xlf @@ -149,7 +149,7 @@ Advanced - Advanced + Zaawansowane diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pt-BR.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pt-BR.xlf index 8647936b11f..e4362c8c3f1 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pt-BR.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pt-BR.xlf @@ -149,7 +149,7 @@ Advanced - Advanced + Avançado diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ru.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ru.xlf index b448661df85..a31ffb183b2 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ru.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ru.xlf @@ -149,7 +149,7 @@ Advanced - Advanced + Дополнительно diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.tr.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.tr.xlf index dedf4799299..dee92da98ae 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.tr.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.tr.xlf @@ -149,7 +149,7 @@ Advanced - Advanced + Gelişmiş diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hans.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hans.xlf index a46a6866a43..3936d51f0d8 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hans.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hans.xlf @@ -149,7 +149,7 @@ Advanced - Advanced + 高级 diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hant.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hant.xlf index e220491faa8..4a8801714b6 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hant.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hant.xlf @@ -149,7 +149,7 @@ Advanced - Advanced + 進階 diff --git a/vsintegration/src/FSharp.UIResources/CodeLensOptionControl.xaml b/vsintegration/src/FSharp.UIResources/CodeLensOptionControl.xaml new file mode 100644 index 00000000000..955c105c7fc --- /dev/null +++ b/vsintegration/src/FSharp.UIResources/CodeLensOptionControl.xaml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vsintegration/src/FSharp.UIResources/CodeLensOptionControl.xaml.cs b/vsintegration/src/FSharp.UIResources/CodeLensOptionControl.xaml.cs new file mode 100644 index 00000000000..ad1a0ecf1a1 --- /dev/null +++ b/vsintegration/src/FSharp.UIResources/CodeLensOptionControl.xaml.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; + +namespace Microsoft.VisualStudio.FSharp.UIResources +{ + /// + /// Interaction logic for CodeLensOptionPage.xaml + /// + internal partial class CodeLensOptionControl : UserControl + { + public CodeLensOptionControl() + { + InitializeComponent(); + } + } +} diff --git a/vsintegration/src/FSharp.UIResources/FSharp.UIResources.csproj b/vsintegration/src/FSharp.UIResources/FSharp.UIResources.csproj index c511d7e926f..8419aff8015 100644 --- a/vsintegration/src/FSharp.UIResources/FSharp.UIResources.csproj +++ b/vsintegration/src/FSharp.UIResources/FSharp.UIResources.csproj @@ -46,7 +46,7 @@ $(VS150COMNTOOLS)\..\..\MSBuild\$(VisualStudioVersion)\Bin $(VSMSBuildBinDir)\Microsoft.CSharp.targets - + false diff --git a/vsintegration/src/FSharp.UIResources/Strings.Designer.cs b/vsintegration/src/FSharp.UIResources/Strings.Designer.cs index 75234c04d74..9ca24307b1d 100644 --- a/vsintegration/src/FSharp.UIResources/Strings.Designer.cs +++ b/vsintegration/src/FSharp.UIResources/Strings.Designer.cs @@ -87,6 +87,51 @@ public static string Code_Fixes { } } + /// + /// Looks up a localized string similar to CodeLens. + /// + public static string CodeLens { + get { + return ResourceManager.GetString("CodeLens", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Annotation prefix. + /// + public static string CodeLens_Prefix { + get { + return ResourceManager.GetString("CodeLens_Prefix", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Show annotations to the right instead of above the line. + /// + public static string CodeLens_Replace_LineLens { + get { + return ResourceManager.GetString("CodeLens_Replace_LineLens", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Show type signature annotations in the editor. + /// + public static string CodeLens_Switch { + get { + return ResourceManager.GetString("CodeLens_Switch", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Use colors in annotations. + /// + public static string CodeLens_UseColors { + get { + return ResourceManager.GetString("CodeLens_UseColors", resourceCulture); + } + } + /// /// Looks up a localized string similar to Completion Lists. /// diff --git a/vsintegration/src/FSharp.UIResources/Strings.resx b/vsintegration/src/FSharp.UIResources/Strings.resx index ebe45bf7321..721e028dba4 100644 --- a/vsintegration/src/FSharp.UIResources/Strings.resx +++ b/vsintegration/src/FSharp.UIResources/Strings.resx @@ -53,7 +53,6 @@ value : The object must be serialized with : System.Runtime.Serialization.Formatters.Soap.SoapFormatter : and then encoded with base64 encoding. - mimetype: application/x-microsoft.net.object.bytearray.base64 value : The object must be serialized into a byte array : using a System.ComponentModel.TypeConverter @@ -180,4 +179,19 @@ Show outlining and collapsable nodes for F# code + + CodeLens + + + Show annotations to the right instead of above the line + + + Show type signature annotations in the editor + + + Annotation prefix + + + Use colors in annotations + \ No newline at end of file diff --git a/vsintegration/src/FSharp.UIResources/xlf/Strings.cs.xlf b/vsintegration/src/FSharp.UIResources/xlf/Strings.cs.xlf index 0ff8ba88f51..23594aa2a05 100644 --- a/vsintegration/src/FSharp.UIResources/xlf/Strings.cs.xlf +++ b/vsintegration/src/FSharp.UIResources/xlf/Strings.cs.xlf @@ -89,22 +89,47 @@ Block Structure Guides - Block Structure Guides + Vodítka pro strukturu bloku Show structure guidelines for F# code - Show structure guidelines for F# code + Zobrazí pokyny pro strukturu kódu F#. Outlining - Outlining + Sbalení Show outlining and collapsable nodes for F# code - Show outlining and collapsable nodes for F# code + Zobrazí osnovu a sbalitelné uzly kódu F#. + + + + CodeLens + CodeLens + + + + Show annotations to the right instead of above the line + Show annotations to the right instead of above the line + + + + Show type signature annotations in the editor + Show type signature annotations in the editor + + + + Annotation prefix + Annotation prefix + + + + Use colors in annotations + Use colors in annotations diff --git a/vsintegration/src/FSharp.UIResources/xlf/Strings.de.xlf b/vsintegration/src/FSharp.UIResources/xlf/Strings.de.xlf index a1a39ef28f3..4a06b1b6f9e 100644 --- a/vsintegration/src/FSharp.UIResources/xlf/Strings.de.xlf +++ b/vsintegration/src/FSharp.UIResources/xlf/Strings.de.xlf @@ -89,22 +89,47 @@ Block Structure Guides - Block Structure Guides + Führungslinien für Blockstruktur Show structure guidelines for F# code - Show structure guidelines for F# code + Strukturführungslinien für F#-Code anzeigen Outlining - Outlining + Gliederung Show outlining and collapsable nodes for F# code - Show outlining and collapsable nodes for F# code + Gliederung und ausblendbare Knoten für F#-Code anzeigen + + + + CodeLens + CodeLens + + + + Show annotations to the right instead of above the line + Show annotations to the right instead of above the line + + + + Show type signature annotations in the editor + Show type signature annotations in the editor + + + + Annotation prefix + Annotation prefix + + + + Use colors in annotations + Use colors in annotations diff --git a/vsintegration/src/FSharp.UIResources/xlf/Strings.en.xlf b/vsintegration/src/FSharp.UIResources/xlf/Strings.en.xlf index a9f0ba0ac19..58e0be7f3e8 100644 --- a/vsintegration/src/FSharp.UIResources/xlf/Strings.en.xlf +++ b/vsintegration/src/FSharp.UIResources/xlf/Strings.en.xlf @@ -107,6 +107,31 @@ Show outlining and collapsable nodes for F# code + + CodeLens + CodeLens + + + + Show annotations to the right instead of above the line + Show annotations to the right instead of above the line + + + + Show type signature annotations in the editor + Show type signature annotations in the editor + + + + Annotation prefix + Annotation prefix + + + + Use colors in annotations + Use colors in annotations + + \ No newline at end of file diff --git a/vsintegration/src/FSharp.UIResources/xlf/Strings.es.xlf b/vsintegration/src/FSharp.UIResources/xlf/Strings.es.xlf index 2d1c825ffa7..e2c4d5b9116 100644 --- a/vsintegration/src/FSharp.UIResources/xlf/Strings.es.xlf +++ b/vsintegration/src/FSharp.UIResources/xlf/Strings.es.xlf @@ -89,22 +89,47 @@ Block Structure Guides - Block Structure Guides + Guías de estructura de bloque Show structure guidelines for F# code - Show structure guidelines for F# code + Mostrar las guías de la estructura del código F# Outlining - Outlining + Esquematización Show outlining and collapsable nodes for F# code - Show outlining and collapsable nodes for F# code + Mostrar los nodos de esquematización y contraíbles del código F# + + + + CodeLens + CodeLens + + + + Show annotations to the right instead of above the line + Show annotations to the right instead of above the line + + + + Show type signature annotations in the editor + Show type signature annotations in the editor + + + + Annotation prefix + Annotation prefix + + + + Use colors in annotations + Use colors in annotations diff --git a/vsintegration/src/FSharp.UIResources/xlf/Strings.fr.xlf b/vsintegration/src/FSharp.UIResources/xlf/Strings.fr.xlf index ab96737ba56..791db1628f5 100644 --- a/vsintegration/src/FSharp.UIResources/xlf/Strings.fr.xlf +++ b/vsintegration/src/FSharp.UIResources/xlf/Strings.fr.xlf @@ -89,22 +89,47 @@ Block Structure Guides - Block Structure Guides + Repères de structure de bloc Show structure guidelines for F# code - Show structure guidelines for F# code + Afficher les directives de structure pour le code F# Outlining - Outlining + Mode plan Show outlining and collapsable nodes for F# code - Show outlining and collapsable nodes for F# code + Afficher le mode plan et les nœuds réductibles pour le code F# + + + + CodeLens + CodeLens + + + + Show annotations to the right instead of above the line + Show annotations to the right instead of above the line + + + + Show type signature annotations in the editor + Show type signature annotations in the editor + + + + Annotation prefix + Annotation prefix + + + + Use colors in annotations + Use colors in annotations diff --git a/vsintegration/src/FSharp.UIResources/xlf/Strings.it.xlf b/vsintegration/src/FSharp.UIResources/xlf/Strings.it.xlf index 76a71c8f912..7ec6526107a 100644 --- a/vsintegration/src/FSharp.UIResources/xlf/Strings.it.xlf +++ b/vsintegration/src/FSharp.UIResources/xlf/Strings.it.xlf @@ -89,22 +89,47 @@ Block Structure Guides - Block Structure Guides + Guide per strutture a blocchi Show structure guidelines for F# code - Show structure guidelines for F# code + Mostra le linee guida della struttura per il codice F# Outlining - Outlining + Struttura Show outlining and collapsable nodes for F# code - Show outlining and collapsable nodes for F# code + Mostra i nodi struttura e comprimibili per il codice F# + + + + CodeLens + CodeLens + + + + Show annotations to the right instead of above the line + Show annotations to the right instead of above the line + + + + Show type signature annotations in the editor + Show type signature annotations in the editor + + + + Annotation prefix + Annotation prefix + + + + Use colors in annotations + Use colors in annotations diff --git a/vsintegration/src/FSharp.UIResources/xlf/Strings.ja.xlf b/vsintegration/src/FSharp.UIResources/xlf/Strings.ja.xlf index df5c9da7b35..983570100b3 100644 --- a/vsintegration/src/FSharp.UIResources/xlf/Strings.ja.xlf +++ b/vsintegration/src/FSharp.UIResources/xlf/Strings.ja.xlf @@ -89,22 +89,47 @@ Block Structure Guides - Block Structure Guides + ブロック構造のガイド Show structure guidelines for F# code - Show structure guidelines for F# code + F# コードの構造のガイドラインを表示する Outlining - Outlining + アウトライン Show outlining and collapsable nodes for F# code - Show outlining and collapsable nodes for F# code + F# コードのアウトラインおよび折りたたみ可能なノードを表示する + + + + CodeLens + CodeLens + + + + Show annotations to the right instead of above the line + Show annotations to the right instead of above the line + + + + Show type signature annotations in the editor + Show type signature annotations in the editor + + + + Annotation prefix + Annotation prefix + + + + Use colors in annotations + Use colors in annotations diff --git a/vsintegration/src/FSharp.UIResources/xlf/Strings.ko.xlf b/vsintegration/src/FSharp.UIResources/xlf/Strings.ko.xlf index 2dd3b97e0eb..37fe273cedd 100644 --- a/vsintegration/src/FSharp.UIResources/xlf/Strings.ko.xlf +++ b/vsintegration/src/FSharp.UIResources/xlf/Strings.ko.xlf @@ -89,22 +89,47 @@ Block Structure Guides - Block Structure Guides + 블록 구조 가이드 Show structure guidelines for F# code - Show structure guidelines for F# code + F# 코드에 대한 구조체 지침 표시 Outlining - Outlining + 개요 Show outlining and collapsable nodes for F# code - Show outlining and collapsable nodes for F# code + F# 코드에 대한 개요 및 축소 가능한 노드 표시 + + + + CodeLens + CodeLens + + + + Show annotations to the right instead of above the line + Show annotations to the right instead of above the line + + + + Show type signature annotations in the editor + Show type signature annotations in the editor + + + + Annotation prefix + Annotation prefix + + + + Use colors in annotations + Use colors in annotations diff --git a/vsintegration/src/FSharp.UIResources/xlf/Strings.pl.xlf b/vsintegration/src/FSharp.UIResources/xlf/Strings.pl.xlf index 44ceba824ae..fb7bcd1d168 100644 --- a/vsintegration/src/FSharp.UIResources/xlf/Strings.pl.xlf +++ b/vsintegration/src/FSharp.UIResources/xlf/Strings.pl.xlf @@ -89,22 +89,47 @@ Block Structure Guides - Block Structure Guides + Prowadnice struktury blokowej Show structure guidelines for F# code - Show structure guidelines for F# code + Pokaż wskazówki dotyczące struktury dla kodu języka F# Outlining - Outlining + Konspekt Show outlining and collapsable nodes for F# code - Show outlining and collapsable nodes for F# code + Pokaż konspekt i węzły z możliwością zwijania dla kodu języka F# + + + + CodeLens + CodeLens + + + + Show annotations to the right instead of above the line + Show annotations to the right instead of above the line + + + + Show type signature annotations in the editor + Show type signature annotations in the editor + + + + Annotation prefix + Annotation prefix + + + + Use colors in annotations + Use colors in annotations diff --git a/vsintegration/src/FSharp.UIResources/xlf/Strings.pt-BR.xlf b/vsintegration/src/FSharp.UIResources/xlf/Strings.pt-BR.xlf index 0b33aa390e4..e4cd1e6d2ef 100644 --- a/vsintegration/src/FSharp.UIResources/xlf/Strings.pt-BR.xlf +++ b/vsintegration/src/FSharp.UIResources/xlf/Strings.pt-BR.xlf @@ -89,22 +89,47 @@ Block Structure Guides - Block Structure Guides + Guias de Estrutura de Bloco Show structure guidelines for F# code - Show structure guidelines for F# code + Mostrar as diretrizes de estrutura para o código F# Outlining - Outlining + Estrutura de Tópicos Show outlining and collapsable nodes for F# code - Show outlining and collapsable nodes for F# code + Mostrar os nós de estrutura de tópicos e recolhíveis para o código F# + + + + CodeLens + CodeLens + + + + Show annotations to the right instead of above the line + Show annotations to the right instead of above the line + + + + Show type signature annotations in the editor + Show type signature annotations in the editor + + + + Annotation prefix + Annotation prefix + + + + Use colors in annotations + Use colors in annotations diff --git a/vsintegration/src/FSharp.UIResources/xlf/Strings.ru.xlf b/vsintegration/src/FSharp.UIResources/xlf/Strings.ru.xlf index 3b63e1caa65..f8a7046f4ce 100644 --- a/vsintegration/src/FSharp.UIResources/xlf/Strings.ru.xlf +++ b/vsintegration/src/FSharp.UIResources/xlf/Strings.ru.xlf @@ -89,22 +89,47 @@ Block Structure Guides - Block Structure Guides + Направляющие для структуры блоков Show structure guidelines for F# code - Show structure guidelines for F# code + Показать рекомендации по структуре для кода F# Outlining - Outlining + Структура Show outlining and collapsable nodes for F# code - Show outlining and collapsable nodes for F# code + Показать структурирование и сворачиваемые узлы для кода F# + + + + CodeLens + CodeLens + + + + Show annotations to the right instead of above the line + Show annotations to the right instead of above the line + + + + Show type signature annotations in the editor + Show type signature annotations in the editor + + + + Annotation prefix + Annotation prefix + + + + Use colors in annotations + Use colors in annotations diff --git a/vsintegration/src/FSharp.UIResources/xlf/Strings.tr.xlf b/vsintegration/src/FSharp.UIResources/xlf/Strings.tr.xlf index 5eb169a55bd..da4b3b409d2 100644 --- a/vsintegration/src/FSharp.UIResources/xlf/Strings.tr.xlf +++ b/vsintegration/src/FSharp.UIResources/xlf/Strings.tr.xlf @@ -89,22 +89,47 @@ Block Structure Guides - Block Structure Guides + Blok Yapısı Kılavuzları Show structure guidelines for F# code - Show structure guidelines for F# code + F# kodu için yapı yönergelerini göster Outlining - Outlining + Ana Hat Show outlining and collapsable nodes for F# code - Show outlining and collapsable nodes for F# code + F# kodu için ana hattı ve daraltılabilir düğümleri göster + + + + CodeLens + CodeLens + + + + Show annotations to the right instead of above the line + Show annotations to the right instead of above the line + + + + Show type signature annotations in the editor + Show type signature annotations in the editor + + + + Annotation prefix + Annotation prefix + + + + Use colors in annotations + Use colors in annotations diff --git a/vsintegration/src/FSharp.UIResources/xlf/Strings.zh-Hans.xlf b/vsintegration/src/FSharp.UIResources/xlf/Strings.zh-Hans.xlf index 1a47f8d75c9..0ac1cccdf34 100644 --- a/vsintegration/src/FSharp.UIResources/xlf/Strings.zh-Hans.xlf +++ b/vsintegration/src/FSharp.UIResources/xlf/Strings.zh-Hans.xlf @@ -89,22 +89,47 @@ Block Structure Guides - Block Structure Guides + 块结构指南 Show structure guidelines for F# code - Show structure guidelines for F# code + 显示 F# 代码的结构指南 Outlining - Outlining + 大纲 Show outlining and collapsable nodes for F# code - Show outlining and collapsable nodes for F# code + 显示 F# 代码的大纲和可折叠节点 + + + + CodeLens + CodeLens + + + + Show annotations to the right instead of above the line + Show annotations to the right instead of above the line + + + + Show type signature annotations in the editor + Show type signature annotations in the editor + + + + Annotation prefix + Annotation prefix + + + + Use colors in annotations + Use colors in annotations diff --git a/vsintegration/src/FSharp.UIResources/xlf/Strings.zh-Hant.xlf b/vsintegration/src/FSharp.UIResources/xlf/Strings.zh-Hant.xlf index 7fcb1a2d208..bf7a84dec56 100644 --- a/vsintegration/src/FSharp.UIResources/xlf/Strings.zh-Hant.xlf +++ b/vsintegration/src/FSharp.UIResources/xlf/Strings.zh-Hant.xlf @@ -89,22 +89,47 @@ Block Structure Guides - Block Structure Guides + 區塊結構輔助線 Show structure guidelines for F# code - Show structure guidelines for F# code + 顯示 F# 程式碼的結構方針 Outlining - Outlining + 大綱 Show outlining and collapsable nodes for F# code - Show outlining and collapsable nodes for F# code + 顯示 F# 程式碼的大綱與可折疊的節點 + + + + CodeLens + CodeLens + + + + Show annotations to the right instead of above the line + Show annotations to the right instead of above the line + + + + Show type signature annotations in the editor + Show type signature annotations in the editor + + + + Annotation prefix + Annotation prefix + + + + Use colors in annotations + Use colors in annotations diff --git a/vsintegration/tests/unittests/MockTypeProviders/DummyProviderForLanguageServiceTesting/DummyProviderForLanguageServiceTesting.fsproj b/vsintegration/tests/unittests/MockTypeProviders/DummyProviderForLanguageServiceTesting/DummyProviderForLanguageServiceTesting.fsproj index 6b201cb4193..5d5f306848a 100644 --- a/vsintegration/tests/unittests/MockTypeProviders/DummyProviderForLanguageServiceTesting/DummyProviderForLanguageServiceTesting.fsproj +++ b/vsintegration/tests/unittests/MockTypeProviders/DummyProviderForLanguageServiceTesting/DummyProviderForLanguageServiceTesting.fsproj @@ -38,5 +38,4 @@ - \ No newline at end of file diff --git a/vsintegration/tests/unittests/MockTypeProviders/EmptyAssembly/EmptyAssembly.fsproj b/vsintegration/tests/unittests/MockTypeProviders/EmptyAssembly/EmptyAssembly.fsproj index 439e8d6aa3f..6d4faa39924 100644 --- a/vsintegration/tests/unittests/MockTypeProviders/EmptyAssembly/EmptyAssembly.fsproj +++ b/vsintegration/tests/unittests/MockTypeProviders/EmptyAssembly/EmptyAssembly.fsproj @@ -35,5 +35,4 @@ - \ No newline at end of file diff --git a/vsintegration/vsintegration.targets b/vsintegration/vsintegration.targets deleted file mode 100644 index 1e5448c5e60..00000000000 --- a/vsintegration/vsintegration.targets +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - -