From 6330cbd7871787e6f982362fb16be323d03e6f66 Mon Sep 17 00:00:00 2001 From: Vasily Kirichenko Date: Tue, 22 Mar 2016 23:17:08 +0300 Subject: [PATCH 1/2] start to work on the feature --- .../GoToDefinitionFilter.fs | 21 +++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/src/FSharpVSPowerTools.Logic/GoToDefinitionFilter.fs b/src/FSharpVSPowerTools.Logic/GoToDefinitionFilter.fs index 040a49f3..a1a151a5 100644 --- a/src/FSharpVSPowerTools.Logic/GoToDefinitionFilter.fs +++ b/src/FSharpVSPowerTools.Logic/GoToDefinitionFilter.fs @@ -411,7 +411,25 @@ type GoToDefinitionFilter async { let! symbolResult = getDocumentState() match symbolResult with - | Some (_, _, _, _, FSharpFindDeclResult.DeclFound _) + | Some (project, _, _, _, FSharpFindDeclResult.DeclFound _) -> + return! + asyncMaybe { + let! symbolUses = + vsLanguageService.GetAllUsesOfAllSymbolsInFile( + textDocument.TextBuffer.CurrentSnapshot, textDocument.FilePath, project, AllowStaleResults.No, false) + + let definitions = symbolUses |> Array.filter (fun x -> x.SymbolUse.IsFromDefinition) + let definition = + match definitions |> Array.tryFind (fun x -> x.SymbolUse.FileName.EndsWith ".fsi") with + | Some def -> Some def + | None -> definitions |> Array.tryHead + + match definition with + | Some def -> + let r = def.SymbolUse.RangeAlternate + serviceProvider.NavigateTo(def.SymbolUse.FileName, r.StartLine, r.StartColumn, r.EndLine, r.EndColumn) + | None -> () + } |> Async.Ignore | None -> // no FSharpSymbol found, here we look at #load directive let! directive = @@ -426,7 +444,6 @@ type GoToDefinitionFilter | None -> // Run the operation on UI thread since continueCommandChain may access UI components. do! Async.SwitchToContext uiContext - // Declaration location might exist so let Visual F# Tools handle it. return continueCommandChain() | Some (project, parseTree, span, fsSymbolUse, FSharpFindDeclResult.DeclNotFound _) -> match navigationPreference with From e56ccb49f68906e89aad6fcf9a0dad55e5c8e2d7 Mon Sep 17 00:00:00 2001 From: Vasily Kirichenko Date: Wed, 23 Mar 2016 13:17:49 +0300 Subject: [PATCH 2/2] use FSharpSymbol.ImplementationLocation (does not work due to FCS bug) --- .../GoToDefinitionFilter.fs | 58 +++++++++++++------ 1 file changed, 39 insertions(+), 19 deletions(-) diff --git a/src/FSharpVSPowerTools.Logic/GoToDefinitionFilter.fs b/src/FSharpVSPowerTools.Logic/GoToDefinitionFilter.fs index a1a151a5..ee82e5b3 100644 --- a/src/FSharpVSPowerTools.Logic/GoToDefinitionFilter.fs +++ b/src/FSharpVSPowerTools.Logic/GoToDefinitionFilter.fs @@ -22,6 +22,7 @@ open System.Diagnostics open System.Text.RegularExpressions open Microsoft.Win32 open System.Text +open FSharpVSPowerTools.AsyncMaybe [] type NavigationPreference = @@ -33,6 +34,17 @@ type internal UrlChangeEventArgs(url: string) = inherit EventArgs() member __.Url = url +type private FileType = + | Signature + | Code + +type private SymbolLocation = + { FileName: FilePath + StartLine: int + StartCol: int + EndLine: int + EndCol: int } + type GoToDefinitionFilter ( textDocument: ITextDocument, @@ -398,6 +410,30 @@ type GoToDefinitionFilter return! None } + let getFileType (file: FilePath) = + match Path.GetExtension(file).ToLower() with + | ".fsi" -> Some Signature + | ".fs" | ".fsx" -> Some Code + | _ -> None + + let (|Definition|Usage|) (symbolUse: FSharpSymbolUse) = + if symbolUse.IsFromDefinition then Definition else Usage + + let gotoSourceCodeDefinition (symbol: FSharpSymbolUse) = + asyncMaybe { + let! currentFileType = getFileType textDocument.FilePath + + let! loc = + match symbol, currentFileType with + | Definition, Code + | Usage, Signature -> + symbol.Symbol.DeclarationLocation |> Option.orElse symbol.Symbol.ImplementationLocation + | _ -> + symbol.Symbol.ImplementationLocation |> Option.orElse symbol.Symbol.DeclarationLocation + + serviceProvider.NavigateTo(loc.FileName, loc.StartLine - 1, loc.StartColumn, loc.EndLine - 1, loc.EndColumn) + } |> Async.Ignore + let cancellationToken = Atom None let gotoDefinition continueCommandChain = @@ -411,25 +447,9 @@ type GoToDefinitionFilter async { let! symbolResult = getDocumentState() match symbolResult with - | Some (project, _, _, _, FSharpFindDeclResult.DeclFound _) -> - return! - asyncMaybe { - let! symbolUses = - vsLanguageService.GetAllUsesOfAllSymbolsInFile( - textDocument.TextBuffer.CurrentSnapshot, textDocument.FilePath, project, AllowStaleResults.No, false) - - let definitions = symbolUses |> Array.filter (fun x -> x.SymbolUse.IsFromDefinition) - let definition = - match definitions |> Array.tryFind (fun x -> x.SymbolUse.FileName.EndsWith ".fsi") with - | Some def -> Some def - | None -> definitions |> Array.tryHead - - match definition with - | Some def -> - let r = def.SymbolUse.RangeAlternate - serviceProvider.NavigateTo(def.SymbolUse.FileName, r.StartLine, r.StartColumn, r.EndLine, r.EndColumn) - | None -> () - } |> Async.Ignore + | Some (_, _, _, fsSymbolUse, FSharpFindDeclResult.DeclFound _) -> + do! Async.SwitchToContext uiContext + return! gotoSourceCodeDefinition fsSymbolUse | None -> // no FSharpSymbol found, here we look at #load directive let! directive =