Skip to content
Closed
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 @@ -17,7 +17,6 @@ open Microsoft.VisualStudio.Text.Classification
open Microsoft.VisualStudio.Utilities
open Microsoft.CodeAnalysis.Classification

open FSharp.Compiler.CodeAnalysis
open FSharp.Compiler.EditorServices

[<RequireQualifiedAccess>]
Expand Down Expand Up @@ -88,8 +87,7 @@ module internal ClassificationDefinitions =
type internal ThemeColors [<ImportingConstructor>]
(
classificationformatMapService: IClassificationFormatMapService,
classificationTypeRegistry: IClassificationTypeRegistryService,
[<Import(typeof<SVsServiceProvider>)>] serviceProvider: IServiceProvider
classificationTypeRegistry: IClassificationTypeRegistryService
) =

let (|LightTheme|DarkTheme|UnknownTheme|) id =
Expand All @@ -106,7 +104,7 @@ module internal ClassificationDefinitions =

let getCurrentThemeId () =
let themeService =
serviceProvider.GetService(typeof<SVsColorThemeService>) :?> IVsColorThemeService
ServiceProvider.GlobalProvider.GetService<SVsColorThemeService, IVsColorThemeService>()

themeService.CurrentTheme.ThemeId

Expand Down Expand Up @@ -146,10 +144,10 @@ module internal ClassificationDefinitions =

let setColors _ =
let fontAndColorStorage =
serviceProvider.GetService(typeof<SVsFontAndColorStorage>) :?> IVsFontAndColorStorage
ServiceProvider.GlobalProvider.GetService<SVsFontAndColorStorage, IVsFontAndColorStorage>()

let fontAndColorCacheManager =
serviceProvider.GetService(typeof<SVsFontAndColorCacheManager>) :?> IVsFontAndColorCacheManager
ServiceProvider.GlobalProvider.GetService<SVsFontAndColorCacheManager, IVsFontAndColorCacheManager>()

fontAndColorCacheManager.CheckCache(ref DefGuidList.guidTextEditorFontCategory)
|> ignore
Expand Down
15 changes: 4 additions & 11 deletions vsintegration/src/FSharp.Editor/Common/Logging.fs
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,10 @@ module Config =
open Config

[<Export>]
type Logger [<ImportingConstructor>] ([<Import(typeof<SVsServiceProvider>)>] serviceProvider: IServiceProvider) =
type Logger() =
let outputWindow =
serviceProvider.GetService<SVsOutputWindow, IVsOutputWindow>() |> Option.ofObj
ServiceProvider.GlobalProvider.GetService<SVsOutputWindow, IVsOutputWindow>()
|> Option.ofObj

let createPane () =
outputWindow
Expand All @@ -49,14 +50,6 @@ type Logger [<ImportingConstructor>] ([<Import(typeof<SVsServiceProvider>)>] ser
Some pane
| _ -> None

static let mutable globalServiceProvider: IServiceProvider option = None

static member GlobalServiceProvider
with get () =
globalServiceProvider
|> Option.defaultValue (ServiceProvider.GlobalProvider :> IServiceProvider)
and set v = globalServiceProvider <- Some v

member _.FSharpLoggingPane =
getPane ()
|> function
Expand Down Expand Up @@ -92,7 +85,7 @@ module Logging =

let inline debug msg = Printf.kprintf Debug.WriteLine msg

let private logger = lazy Logger(Logger.GlobalServiceProvider)
let private logger = lazy Logger()
let private log logType msg = logger.Value.Log(logType, msg)

let logMsg msg = log LogType.Message msg
Expand Down
32 changes: 30 additions & 2 deletions vsintegration/src/FSharp.Editor/Common/Vs.fs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ open System
open System.Runtime.InteropServices
open Microsoft.VisualStudio
open Microsoft.VisualStudio.Editor
open Microsoft.VisualStudio.Shell
open Microsoft.VisualStudio.Shell.Interop
open Microsoft.VisualStudio.TextManager.Interop

Expand Down Expand Up @@ -91,9 +92,36 @@ module internal VsRunningDocumentTable =

[<AutoOpen>]
module internal ServiceProviderExtensions =
type internal System.IServiceProvider with
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So once again, what's the need for this change? I'm not against it, just a bit paranoid and trying to better understand all this magic

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No immediate need. Although I just found a use for GetServiceAsync in another branch.

This is pretty much copied from Roslyn repo.
The problem is when coding VSIX stuff in C# you'll get warnings from analyzers when doing unsafe things like calling GetService from background thread, we don't have that.
This is not immediately a problem because we have all the related bugs Ironed out over the years, it's more so we don't run into problems in the future.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe leave the old overload as is, and name the new one GetServiceOnMainThread? What do you think @psfinaki ?

type internal IAsyncServiceProvider with

member sp.GetService<'S, 'T>() = sp.GetService(typeof<'S>) :?> 'T
member sp.GetServiceAsync<'TService, 'TInterface>() =
backgroundTask {
match sp with
| :? IAsyncServiceProvider2 as sp2 ->
let! service = sp2.GetServiceAsync(typeof<'TService>, swallowExceptions = false)
return service :?> 'TInterface
| _ ->
let! service = sp.GetServiceAsync(typeof<'TService>)

if service = null then
raise (ServiceUnavailableException(typeof<'TService>))

return service :?> 'TInterface
}

type internal IServiceProvider with

member sp.GetService<'TService, 'TInterface>() =
ThreadHelper.JoinableTaskFactory.Run(fun () ->
task {
do! ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync()
let service = sp.GetService(typeof<'TService>)

if service = null then
raise (ServiceUnavailableException(typeof<'TService>))

return service :?> 'TInterface
})

member sp.TextManager = sp.GetService<SVsTextManager, IVsTextManager>()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,10 @@
namespace Microsoft.VisualStudio.FSharp.Editor

open System
open System.Collections.Immutable
open System.Runtime.CompilerServices
open System.Text.RegularExpressions
open Microsoft.VisualStudio.Shell
open Microsoft.VisualStudio.Shell.Interop
open FSharp.Compiler.CodeAnalysis
open FSharp.Compiler.EditorServices
open FSharp.Compiler.Symbols
open FSharp.Compiler.Syntax
Expand Down
2 changes: 1 addition & 1 deletion vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,11 @@
<Compile Include="Common\Constants.fs" />
<Compile Include="Common\Extensions.fs" />
<Compile Include="Common\Error.fs" />
<Compile Include="Common\Vs.fs" />
<Compile Include="Common\Logging.fs" />
<Compile Include="Common\RoslynHelpers.fs" />
<Compile Include="Common\FSharpCodeAnalysisExtensions.fs" />
<Compile Include="Common\CodeAnalysisExtensions.fs" />
<Compile Include="Common\Vs.fs" />
<Compile Include="Options\SettingsStore.fs" />
<Compile Include="Options\UIHelpers.fs" />
<Compile Include="Options\EditorOptions.fs" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,22 +10,15 @@ open FSharp.Compiler.Text.Range
open Microsoft.CodeAnalysis
open Microsoft.CodeAnalysis.ExternalAccess.FSharp.GoToDefinition

open Microsoft.VisualStudio.Shell
open Microsoft.VisualStudio.Shell.Interop
open System.Collections.Immutable
open System.Threading.Tasks

[<Export(typeof<IFSharpFindDefinitionService>)>]
[<Export(typeof<FSharpFindDefinitionService>)>]
type internal FSharpFindDefinitionService [<ImportingConstructor>] (metadataAsSource: FSharpMetadataAsSourceService) =

let statusBar =
StatusBar(ServiceProvider.GlobalProvider.GetService<SVsStatusbar, IVsStatusbar>())

interface IFSharpFindDefinitionService with
member _.FindDefinitionsAsync(document: Document, position: int, cancellationToken: CancellationToken) =
let navigation =
FSharpNavigation(statusBar, metadataAsSource, document, rangeStartup)
let navigation = FSharpNavigation(metadataAsSource, document, rangeStartup)

let definitions = navigation.FindDefinitions(position, cancellationToken)
ImmutableArray.CreateRange(definitions) |> Task.FromResult
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@ open Microsoft.CodeAnalysis.ExternalAccess.FSharp
open Microsoft.CodeAnalysis.ExternalAccess.FSharp.FindUsages
open Microsoft.CodeAnalysis.ExternalAccess.FSharp.Editor.FindUsages

open FSharp.Compiler
open FSharp.Compiler.CodeAnalysis
open FSharp.Compiler.EditorServices
open FSharp.Compiler.Text
open Microsoft.CodeAnalysis.Text
Expand Down
51 changes: 20 additions & 31 deletions vsintegration/src/FSharp.Editor/Navigation/GoToDefinition.fs
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,10 @@ module private ExternalSymbol =
| _ -> []

// TODO: Uncomment code when VS has a fix for updating the status bar.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BTW do you think this is still relevant? :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

😀 I bet VS statusbar works fine. Just not in our code. We should really stand of the shoulders of experts and either copy what VSIX Community Toolkit does or even just install their nuget.

type StatusBar(statusBar: IVsStatusbar) =
type StatusBar() =
let statusBar =
ServiceProvider.GlobalProvider.GetService<SVsStatusbar, IVsStatusbar>()

let mutable _searchIcon =
int16 Microsoft.VisualStudio.Shell.Interop.Constants.SBAI_Find :> obj

Expand Down Expand Up @@ -394,7 +397,6 @@ type internal GoToDefinition(metadataAsSource: FSharpMetadataAsSourceService) =
(
document: Document,
textSpan: Microsoft.CodeAnalysis.Text.TextSpan,
statusBar: StatusBar,
cancellationToken: CancellationToken
) =
let navigableItem = FSharpGoToDefinitionNavigableItem(document, textSpan)
Expand All @@ -407,9 +409,10 @@ type internal GoToDefinition(metadataAsSource: FSharpMetadataAsSourceService) =
navigationService.TryNavigateToSpan(workspace, navigableItem.Document.Id, navigableItem.SourceSpan, cancellationToken)

if not navigationSucceeded then
statusBar.TempMessage(SR.CannotNavigateUnknown())
StatusBar().TempMessage(SR.CannotNavigateUnknown())

member _.NavigateToItem(navigableItem: FSharpNavigableItem, statusBar: StatusBar, cancellationToken: CancellationToken) =
member _.NavigateToItem(navigableItem: FSharpNavigableItem, cancellationToken: CancellationToken) =
let statusBar = StatusBar()
use __ = statusBar.Animate()

statusBar.Message(SR.NavigatingTo())
Expand All @@ -434,12 +437,11 @@ type internal GoToDefinition(metadataAsSource: FSharpMetadataAsSourceService) =
targetDocument: Document,
targetSourceText: SourceText,
symbolRange: range,
statusBar: StatusBar,
cancellationToken: CancellationToken
) =
asyncMaybe {
let! item = this.FindDeclarationOfSymbolAtRange(targetDocument, symbolRange, targetSourceText)
return this.NavigateToItem(item, statusBar, cancellationToken)
return this.NavigateToItem(item, cancellationToken)
}

/// Find the definition location (implementation file/.fs) of the target symbol
Expand All @@ -448,12 +450,11 @@ type internal GoToDefinition(metadataAsSource: FSharpMetadataAsSourceService) =
targetDocument: Document,
targetSourceText: SourceText,
symbolRange: range,
statusBar: StatusBar,
cancellationToken: CancellationToken
) =
asyncMaybe {
let! item = this.FindDefinitionOfSymbolAtRange(targetDocument, symbolRange, targetSourceText)
return this.NavigateToItem(item, statusBar, cancellationToken)
return this.NavigateToItem(item, cancellationToken)
}

member this.NavigateToExternalDeclaration
Expand Down Expand Up @@ -546,7 +547,7 @@ type internal GoToDefinition(metadataAsSource: FSharpMetadataAsSourceService) =
| _ -> TextSpan()

let navItem = FSharpGoToDefinitionNavigableItem(tmpShownDoc, span)
this.NavigateToItem(navItem, statusBar, cancellationToken)
this.NavigateToItem(navItem, cancellationToken)
true
| _ -> false
| _ -> false
Expand Down Expand Up @@ -744,13 +745,7 @@ module internal FSharpQuickInfo =
return result |> Option.defaultValue (symbolUse.Range, None, Some targetQuickInfo)
}

type internal FSharpNavigation
(
statusBar: StatusBar,
metadataAsSource: FSharpMetadataAsSourceService,
initialDoc: Document,
thisSymbolUseRange: range
) =
type internal FSharpNavigation(metadataAsSource: FSharpMetadataAsSourceService, initialDoc: Document, thisSymbolUseRange: range) =

let workspace = initialDoc.Project.Solution.Workspace
let solution = workspace.CurrentSolution
Expand Down Expand Up @@ -791,15 +786,13 @@ type internal FSharpNavigation

match initialDoc.FilePath, targetPath with
| Signature, Signature
| Implementation, Implementation -> return gtd.TryNavigateToTextSpan(targetDoc, targetTextSpan, statusBar, cancellationToken)
| Implementation, Implementation -> return gtd.TryNavigateToTextSpan(targetDoc, targetTextSpan, cancellationToken)

// Adjust the target from signature to implementation.
| Implementation, Signature ->
return! gtd.NavigateToSymbolDefinitionAsync(targetDoc, targetSource, range, statusBar, cancellationToken)
| Implementation, Signature -> return! gtd.NavigateToSymbolDefinitionAsync(targetDoc, targetSource, range, cancellationToken)

// Adjust the target from implmentation to signature.
| Signature, Implementation ->
return! gtd.NavigateToSymbolDeclarationAsync(targetDoc, targetSource, range, statusBar, cancellationToken)
| Signature, Implementation -> return! gtd.NavigateToSymbolDeclarationAsync(targetDoc, targetSource, range, cancellationToken)
}
|> Async.Ignore
|> Async.StartImmediate
Expand All @@ -818,6 +811,7 @@ type internal FSharpNavigation

member _.TryGoToDefinition(position, cancellationToken) =
let gtd = GoToDefinition(metadataAsSource)
let statusBar = StatusBar()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, here (and elsewhere) - are you sure creating a status bar from scratch is equivalent to passing around the thing that flows in?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking again at this, IMV we should just yeet all the statusbar code. It does nothing anyway.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like it was just a clunky wrapper around SVsStatusbar service, when it worked, pretty much stateless on its own, so creating it ad hoc is ok. Removing this completely looks like serious work, this file is 1000+ freaking lines🙃

let gtdTask = gtd.FindDefinitionTask(initialDoc, position, cancellationToken)

// Wrap this in a try/with as if the user clicks "Cancel" on the thread dialog, we'll be cancelled.
Expand All @@ -829,7 +823,7 @@ type internal FSharpNavigation
if gtdTask.Status = TaskStatus.RanToCompletion && gtdTask.Result.IsSome then
match gtdTask.Result.Value with
| FSharpGoToDefinitionResult.NavigableItem (navItem), _ ->
gtd.NavigateToItem(navItem, statusBar, cancellationToken)
gtd.NavigateToItem(navItem, cancellationToken)
// 'true' means do it, like Sheev Palpatine would want us to.
true
| FSharpGoToDefinitionResult.ExternalAssembly (targetSymbolUse, metadataReferences), _ ->
Expand Down Expand Up @@ -876,7 +870,7 @@ type internal DocCommentId =
| Type of EntityPath: string list
| None

type FSharpNavigableLocation(statusBar: StatusBar, metadataAsSource: FSharpMetadataAsSourceService, symbolRange: range, project: Project) =
type FSharpNavigableLocation(metadataAsSource: FSharpMetadataAsSourceService, symbolRange: range, project: Project) =
interface IFSharpNavigableLocation with
member _.NavigateToAsync(_options: FSharpNavigationOptions2, cancellationToken: CancellationToken) : Task<bool> =
asyncMaybe {
Expand All @@ -892,10 +886,8 @@ type FSharpNavigableLocation(statusBar: StatusBar, metadataAsSource: FSharpMetad
Implementation

match targetPath with
| Signature ->
return! gtd.NavigateToSymbolDefinitionAsync(targetDoc, targetSource, symbolRange, statusBar, cancellationToken)
| Implementation ->
return! gtd.NavigateToSymbolDeclarationAsync(targetDoc, targetSource, symbolRange, statusBar, cancellationToken)
| Signature -> return! gtd.NavigateToSymbolDefinitionAsync(targetDoc, targetSource, symbolRange, cancellationToken)
| Implementation -> return! gtd.NavigateToSymbolDeclarationAsync(targetDoc, targetSource, symbolRange, cancellationToken)
}
|> Async.map (fun a -> a.IsSome)
|> RoslynHelpers.StartAsyncAsTask cancellationToken
Expand All @@ -908,9 +900,6 @@ type FSharpCrossLanguageSymbolNavigationService() =

let workspace = componentModel.GetService<VisualStudioWorkspace>()

let statusBar =
StatusBar(ServiceProvider.GlobalProvider.GetService<SVsStatusbar, IVsStatusbar>())

let metadataAsSource =
componentModel
.DefaultExportProvider
Expand Down Expand Up @@ -1141,7 +1130,7 @@ type FSharpCrossLanguageSymbolNavigationService() =
// More results can theoretically be returned in case of method overloads, or when we have both signature and implementation files.
if locations.Count() >= 1 then
let (location, project) = locations.First()
return FSharpNavigableLocation(statusBar, metadataAsSource, location, project) :> IFSharpNavigableLocation
return FSharpNavigableLocation(metadataAsSource, location, project) :> IFSharpNavigableLocation
else
return Unchecked.defaultof<_> // returning null here, so Roslyn can fallback to default source-as-metadata implementation.
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

namespace Microsoft.VisualStudio.FSharp.Editor

open System
open System.Composition
open System.Threading
open System.Threading.Tasks
Expand All @@ -12,31 +11,24 @@ open FSharp.Compiler.Text.Range
open Microsoft.CodeAnalysis
open Microsoft.CodeAnalysis.ExternalAccess.FSharp.Editor

open Microsoft.VisualStudio.Shell
open Microsoft.VisualStudio.Shell.Interop

[<Export(typeof<IFSharpGoToDefinitionService>)>]
[<Export(typeof<FSharpGoToDefinitionService>)>]
type internal FSharpGoToDefinitionService [<ImportingConstructor>] (metadataAsSource: FSharpMetadataAsSourceService) =

let statusBar =
StatusBar(ServiceProvider.GlobalProvider.GetService<SVsStatusbar, IVsStatusbar>())

interface IFSharpGoToDefinitionService with
/// Invoked with Peek Definition.
member _.FindDefinitionsAsync(document: Document, position: int, cancellationToken: CancellationToken) =
let navigation =
FSharpNavigation(statusBar, metadataAsSource, document, rangeStartup)
let navigation = FSharpNavigation(metadataAsSource, document, rangeStartup)

navigation.FindDefinitions(position, cancellationToken) |> Task.FromResult

/// Invoked with Go to Definition.
/// Try to navigate to the definiton of the symbol at the symbolRange in the originDocument
member _.TryGoToDefinition(document: Document, position: int, cancellationToken: CancellationToken) =
let statusBar = StatusBar()
statusBar.Message(SR.LocatingSymbol())
use __ = statusBar.Animate()

let navigation =
FSharpNavigation(statusBar, metadataAsSource, document, rangeStartup)
let navigation = FSharpNavigation(metadataAsSource, document, rangeStartup)

navigation.TryGoToDefinition(position, cancellationToken)
Loading