Skip to content
This repository was archived by the owner on Oct 4, 2021. It is now read-only.

Commit 6dd0f2c

Browse files
Merge pull request #9307 from mono/pr-kirillo-fix-gotodef-for-real-this-time
Implement Go To Definition for Razor
2 parents 839784d + 3cd4a99 commit 6dd0f2c

File tree

3 files changed

+68
-15
lines changed

3 files changed

+68
-15
lines changed

main/src/addins/CSharpBinding/MonoDevelop.Ide.Completion.Presentation/MonoDevelopContainedDocument.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@ public class MonoDevelopContainedDocument : IMonoDevelopHostDocument
5454
public IMonoDevelopContainedLanguageHost ContainedLanguageHost { get; private set; }
5555
private readonly HostType _hostType;
5656

57+
public IProjectionBuffer TopBuffer => DataBuffer;
58+
5759
// _workspace will only be set once the Workspace is available
5860
private Workspace _workspace;
5961

main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.RoslynServices/MonoDevelopDocumentNavigationService.cs

Lines changed: 62 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
using System;
22
using System.Composition;
3+
using System.Linq;
34
using System.Threading;
4-
using System.Threading.Tasks;
55
using Microsoft.CodeAnalysis;
66
using Microsoft.CodeAnalysis.Host;
77
using Microsoft.CodeAnalysis.Host.Mef;
88
using Microsoft.CodeAnalysis.Navigation;
99
using Microsoft.CodeAnalysis.Options;
1010
using Microsoft.CodeAnalysis.Text;
1111
using Microsoft.VisualStudio.Text;
12+
using Microsoft.VisualStudio.Text.Projection;
1213
using MonoDevelop.Core;
1314
using MonoDevelop.Ide.TypeSystem;
1415

@@ -19,11 +20,14 @@ internal sealed class VisualStudioDocumentNavigationServiceFactory : IWorkspaceS
1920
{
2021
private readonly IDocumentNavigationService _singleton;
2122

23+
[Import]
24+
public IBufferGraphFactoryService BufferGraphFactoryService { get; set; }
25+
2226
[ImportingConstructor]
2327
[Obsolete (MefConstruction.ImportingConstructorMessage, error: true)]
2428
private VisualStudioDocumentNavigationServiceFactory ()
2529
{
26-
_singleton = new MonoDevelopDocumentNavigationService ();
30+
_singleton = new MonoDevelopDocumentNavigationService (this);
2731
}
2832

2933
public IWorkspaceService CreateService (HostWorkspaceServices workspaceServices)
@@ -34,6 +38,13 @@ public IWorkspaceService CreateService (HostWorkspaceServices workspaceServices)
3438

3539
class MonoDevelopDocumentNavigationService : IDocumentNavigationService
3640
{
41+
private VisualStudioDocumentNavigationServiceFactory factory;
42+
43+
public MonoDevelopDocumentNavigationService (VisualStudioDocumentNavigationServiceFactory visualStudioDocumentNavigationServiceFactory)
44+
{
45+
this.factory = visualStudioDocumentNavigationServiceFactory;
46+
}
47+
3748
public bool CanNavigateToSpan (Workspace workspace, DocumentId documentId, TextSpan textSpan)
3849
{
3950
// Navigation should not change the context of linked files and Shared Projects.
@@ -99,13 +110,12 @@ public bool TryNavigateToSpan (Workspace workspace, DocumentId documentId, TextS
99110

100111
Runtime.AssertMainThread ();
101112

102-
var document = OpenDocument (workspace, documentId, options);
113+
var document = workspace.CurrentSolution.GetDocument (documentId);
103114
if (document == null) {
104115
return false;
105116
}
106117

107118
var text = document.GetTextSynchronously (CancellationToken.None);
108-
var textBuffer = text.Container.GetTextBuffer ();
109119

110120
var boundedTextSpan = GetSpanWithinDocumentBounds (textSpan, text.Length);
111121
if (boundedTextSpan != textSpan) {
@@ -127,7 +137,7 @@ public bool TryNavigateToLineAndOffset (Workspace workspace, DocumentId document
127137

128138
Runtime.AssertMainThread ();
129139

130-
var document = OpenDocument (workspace, documentId, options);
140+
var document = workspace.CurrentSolution.GetDocument (documentId);
131141
if (document == null) {
132142
return false;
133143
}
@@ -149,7 +159,7 @@ public bool TryNavigateToPosition (Workspace workspace, DocumentId documentId, i
149159

150160
Runtime.AssertMainThread ();
151161

152-
var document = OpenDocument (workspace, documentId, options);
162+
var document = workspace.CurrentSolution.GetDocument (documentId);
153163
if (document == null) {
154164
return false;
155165
}
@@ -222,13 +232,41 @@ private static Document OpenDocument (Workspace workspace, DocumentId documentId
222232

223233
private bool NavigateTo (Document document, TextSpan span)
224234
{
235+
string filePath = document.FilePath;
236+
filePath = GetActualFilePathToOpen (filePath);
225237
var proj = (document.Project.Solution.Workspace as MonoDevelopWorkspace)?.GetMonoProject (document.Project);
226-
var task = IdeApp.Workbench.OpenDocument (new Gui.FileOpenInformation (document.FilePath, proj) {
238+
var task = IdeApp.Workbench.OpenDocument (new Gui.FileOpenInformation (filePath, proj) {
227239
Offset = span.Start
228240
});
229241
return true;
230242
}
231243

244+
/// <summary>
245+
/// Razor: Strip the .g.cs since we want to open the corresponding .cshtml or .razor document.
246+
///
247+
/// In Visual Studio for Windows the underlying C# buffer is added to the workspace with the
248+
/// .cshtml or .razor extension (without the .g.cs) part, so they don't have to worry about
249+
/// this. In our case we have an assumption somewhere that all C# documents in the workspace
250+
/// have the .cs extension, so we're adding the .g.cs part that we need to strip here.
251+
///
252+
/// This is not great to hardcode application-specific logic here, but we don't anticipate
253+
/// more scenarios where we want to open a different file than requested, so it doesn't
254+
/// warrant an extension point at this time.
255+
/// </summary>
256+
string GetActualFilePathToOpen (string filePath)
257+
{
258+
if (filePath == null) {
259+
return null;
260+
}
261+
262+
if (filePath.EndsWith (".cshtml.g.cs", StringComparison.OrdinalIgnoreCase) ||
263+
filePath.EndsWith (".razor.g.cs", StringComparison.OrdinalIgnoreCase)) {
264+
filePath = filePath.Substring (0, filePath.Length - ".g.cs".Length);
265+
}
266+
267+
return filePath;
268+
}
269+
232270
private bool IsSecondaryBuffer (Workspace workspace, Document document)
233271
{
234272
var containedDocument = MonoDevelopHostDocumentRegistration.FromDocument (document);
@@ -239,23 +277,33 @@ private bool IsSecondaryBuffer (Workspace workspace, Document document)
239277
return true;
240278
}
241279

242-
public static bool TryMapSpanFromSecondaryBufferToPrimaryBuffer (TextSpan spanInSecondaryBuffer, Microsoft.CodeAnalysis.Workspace workspace, Document document, out TextSpan spanInPrimaryBuffer)
280+
public bool TryMapSpanFromSecondaryBufferToPrimaryBuffer (TextSpan spanInSecondaryBuffer, Microsoft.CodeAnalysis.Workspace workspace, Document document, out TextSpan spanInPrimaryBuffer)
243281
{
244282
spanInPrimaryBuffer = default;
245283

246284
var containedDocument = MonoDevelopHostDocumentRegistration.FromDocument (document);
247285
if (containedDocument == null) {
248286
return false;
249287
}
250-
throw new NotImplementedException ();
251-
//var bufferCoordinator = containedDocument.BufferCoordinator;
252288

253-
//var primary = new VsTextSpan [1];
254-
//var hresult = bufferCoordinator.MapSecondaryToPrimarySpan (spanInSecondaryBuffer, primary);
289+
var projectionBuffer = containedDocument.TopBuffer;
290+
291+
var bufferGraph = factory.BufferGraphFactoryService.CreateBufferGraph (projectionBuffer);
255292

256-
//spanInPrimaryBuffer = primary [0];
293+
if (document.TryGetText(out var sourceText) && sourceText.Container.TryGetTextBuffer() is ITextBuffer languageBuffer) {
294+
var secondarySnapshot = languageBuffer.CurrentSnapshot;
295+
var snapshotSpanInSecondaryBuffer = new SnapshotSpan (secondarySnapshot, new Span (spanInSecondaryBuffer.Start, spanInSecondaryBuffer.Length));
296+
var topBufferSnapshotSpan = bufferGraph.MapUpToSnapshot (
297+
snapshotSpanInSecondaryBuffer,
298+
SpanTrackingMode.EdgeExclusive,
299+
projectionBuffer.CurrentSnapshot).FirstOrDefault();
300+
if (topBufferSnapshotSpan != default) {
301+
spanInPrimaryBuffer = new TextSpan (topBufferSnapshotSpan.Start, topBufferSnapshotSpan.Length);
302+
return true;
303+
}
304+
}
257305

258-
//return ErrorHandler.Succeeded (hresult);
306+
return false;
259307
}
260308

261309
private bool CanMapFromSecondaryBufferToPrimaryBuffer (Workspace workspace, Document document, TextSpan spanInSecondaryBuffer)

main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/IMonoDevelopHostDocument.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@
66
using Microsoft.CodeAnalysis;
77
using Microsoft.CodeAnalysis.Text;
88
using Microsoft.VisualStudio.Text;
9-
9+
using Microsoft.VisualStudio.Text.Projection;
10+
1011
namespace MonoDevelop.Ide.TypeSystem
1112
{
1213
interface IMonoDevelopHostDocument
@@ -15,6 +16,8 @@ interface IMonoDevelopHostDocument
1516
/// Updates the text of the document.
1617
/// </summary>
1718
void UpdateText (SourceText newText);
19+
20+
IProjectionBuffer TopBuffer { get; }
1821
}
1922

2023
static class MonoDevelopHostDocumentRegistration

0 commit comments

Comments
 (0)