diff options
author | Mike Krüger <mkrueger@xamarin.com> | 2017-08-08 16:00:39 +0300 |
---|---|---|
committer | Mike Krüger <mkrueger@xamarin.com> | 2017-08-08 16:00:39 +0300 |
commit | d4d90f0f327092511d885ea80c66be92be92f950 (patch) | |
tree | cfeeff941d6c4645e59f0e4cde0b572bc1cbc32f /main/src/core/MonoDevelop.Ide | |
parent | 0748166561d4eca6d80ab5d7d24f5566c6ab5aea (diff) |
[TextEditor] Implemented code lens subsystem & show references lenses.master-codelens
It's the rosyln code lens service driving the first code lens.
Diffstat (limited to 'main/src/core/MonoDevelop.Ide')
5 files changed, 219 insertions, 0 deletions
diff --git a/main/src/core/MonoDevelop.Ide/ExtensionModel/MonoDevelop.Ide.addin.xml b/main/src/core/MonoDevelop.Ide/ExtensionModel/MonoDevelop.Ide.addin.xml index b716716444..617f97a492 100644 --- a/main/src/core/MonoDevelop.Ide/ExtensionModel/MonoDevelop.Ide.addin.xml +++ b/main/src/core/MonoDevelop.Ide/ExtensionModel/MonoDevelop.Ide.addin.xml @@ -238,6 +238,10 @@ <ExtensionNode name = "Assembly" type = "MonoDevelop.Core.AddIns.AssemblyExtensionNode" /> </ExtensionPoint> + <ExtensionPoint path = "/MonoDevelop/Ide/CodeLensProvider" name = "Code lens provider"> + <Description>Algorithm for providing code lenses in a file.</Description> + <ExtensionNode name="CodeLens" type="MonoDevelop.Ide.Extensions.MimeTypeExtensionNode"/> + </ExtensionPoint> <!-- Extensions --> <Extension path = "/MonoDevelop/Core/Applications"> @@ -320,6 +324,7 @@ <Class class = "MonoDevelop.Ide.Editor.TextMate.TextMateFoldingTextEditorExtension" /> <Class class = "MonoDevelop.Ide.Editor.TextMate.TextMateIndentationTextEditorExtension" /> <Class class = "MonoDevelop.Ide.Editor.TextMate.TextMateCompletionTextEditorExtension" /> + <Class class = "MonoDevelop.Ide.Editor.Extension.CodeLensTextEditorExtension" /> <Class id="FinalStep" class = "MonoDevelop.Ide.Editor.Extension.TextEditorExtensionMarker" /> </Extension> diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor.Extension/CodeLensTextEditorExtension.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor.Extension/CodeLensTextEditorExtension.cs new file mode 100644 index 0000000000..113071f296 --- /dev/null +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor.Extension/CodeLensTextEditorExtension.cs @@ -0,0 +1,204 @@ +// +// AbstractCodeLensExtension.cs +// +// Author: +// Mike Krüger <mikkrg@microsoft.com> +// +// Copyright (c) 2017 Microsoft Corporation +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +using System; +using MonoDevelop.Ide.Gui.Content; +using System.Collections.Generic; +using System.Linq; +using MonoDevelop.Ide.FindInFiles; +using System.Threading; +using System.Threading.Tasks; +using MonoDevelop.Core; +using System.Diagnostics.CodeAnalysis; +using MonoDevelop.Ide.Editor; +using MonoDevelop.Core.Text; +using System.Collections.Immutable; +using Mono.Addins; +using MonoDevelop.Ide.Extensions; +using MonoDevelop.Ide.TypeSystem; +using Cairo; + +namespace MonoDevelop.Ide.Editor.Extension +{ + public sealed class GtkCodeLansDrawingParameters : CodeLansDrawingParameters + { + public Pango.Layout Layout { get; private set; } + public Context Context { get; private set; } + + public GtkCodeLansDrawingParameters (TextEditor editor, int lineNr, Xwt.Rectangle lineArea, double x, double y, Pango.Layout layout, Context context) : base (editor, lineNr, lineArea, x, y) + { + Layout = layout; + Context = context; + } + } + + public abstract class CodeLansDrawingParameters + { + public TextEditor Editor { get; private set; } + public int LineNr { get; private set; } + public Xwt.Rectangle LineArea { get; private set; } + + public double X { get; private set; } + public double Y { get; private set; } + + public CodeLansDrawingParameters (TextEditor editor, int lineNr, Xwt.Rectangle lineArea, double x, double y) + { + Editor = editor; + LineNr = lineNr; + LineArea = lineArea; + X = x; + Y = y; + } + } + + public abstract class CodeLens + { + public abstract TextSegment CodeLensSpan { get; } + + public abstract void Draw (CodeLansDrawingParameters drawingParameters); + + public abstract Xwt.Size Size { get; } + } + + public abstract class CodeLensProvider + { + internal string MimeType { get; set; } + + public abstract Task<IEnumerable<CodeLens>> GetLenses (TextEditor editor, DocumentContext ctx, CancellationToken token); + } + + class CodeLensTextEditorExtension : TextEditorExtension + { + CancellationTokenSource src = new CancellationTokenSource (); + bool isDisposed; + static List<CodeLensProvider> codeLensProviders = new List<CodeLensProvider> (); + + static CodeLensTextEditorExtension () + { + AddinManager.AddExtensionNodeHandler ("/MonoDevelop/Ide/CodeLensProvider", delegate (object sender, ExtensionNodeEventArgs args) { + var node = (MimeTypeExtensionNode)args.ExtensionNode; + switch (args.Change) { + case ExtensionChange.Add: + var matcher = (CodeLensProvider)node.CreateInstance (); + matcher.MimeType = node.MimeType; + codeLensProviders.Add (matcher); + break; + case ExtensionChange.Remove: + var toRemove = codeLensProviders.FirstOrDefault (m => m.MimeType == node.MimeType); + if (toRemove != null) + codeLensProviders.Remove (toRemove); + break; + } + }); + } + + protected override void Initialize () + { + DocumentContext.DocumentParsed += DocumentContext_DocumentParsed; + } + + public override void Dispose () + { + if (isDisposed) + return; + isDisposed = true; + CancelDocumentParsedUpdate (); + DocumentContext.DocumentParsed -= DocumentContext_DocumentParsed; + base.Dispose (); + } + + void CancelDocumentParsedUpdate () + { + src.Cancel (); + src = new CancellationTokenSource (); + } + + void DocumentContext_DocumentParsed (object sender, EventArgs e) + { + CancelDocumentParsedUpdate (); + var token = src.Token; + var parsedDocument = DocumentContext.ParsedDocument; + if (!isDisposed) + UpdateLenses (token); + } + + List<ICodeLensMarker> codeLensMarkers = new List<ICodeLensMarker> (); + struct CodeLensCacheItem + { + public ICodeLensMarker Marker { get; set; } + public CodeLens Lens { get; set; } + + public CodeLensCacheItem (ICodeLensMarker marker, CodeLens lens) + { + Marker = marker; + Lens = lens; + } + } + + Dictionary<CodeLensProvider, List<CodeLensCacheItem>> lensCache = new Dictionary<CodeLensProvider, List<CodeLensCacheItem>> (); + + async void UpdateLenses (CancellationToken token = default (CancellationToken)) + { + foreach (var provider in codeLensProviders) { + var lenses = await provider.GetLenses (Editor, DocumentContext, token).ConfigureAwait (false); + await Runtime.RunInMainThread (delegate { + if (lensCache.TryGetValue (provider, out List<CodeLensCacheItem> cache)) { + lensCache.Remove (provider); + foreach (var item in cache) + item.Marker.RemoveLens (item.Lens); + } + + var newCache = new List<CodeLensCacheItem> (); + foreach (var lens in lenses) { + var line = Editor.GetLineByOffset (lens.CodeLensSpan.Offset); + var codeLensMarker = Editor.GetLineMarkers (line).OfType<ICodeLensMarker> ().FirstOrDefault (); + if (codeLensMarker == null) { + codeLensMarker = Editor.TextMarkerFactory.CreateCodeLensMarker (Editor); + Editor.AddMarker (line, codeLensMarker); + codeLensMarkers.Add (codeLensMarker); + } + codeLensMarker.AddLens (lens); + newCache.Add (new CodeLensCacheItem (codeLensMarker, lens)); + } + lensCache.Add (provider, newCache); + }); + } + + await Runtime.RunInMainThread (delegate { + RemoveUnusedCodeLensMarkers (); + }); + } + + void RemoveUnusedCodeLensMarkers () + { + foreach (var marker in codeLensMarkers.ToArray ()) { + if (marker.CodeLensCount == 0) { + Editor.RemoveMarker (marker); + codeLensMarkers.Remove (marker); + } + } + } + } +}
\ No newline at end of file diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor/ITextLineMarker.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor/ITextLineMarker.cs index 982033e951..34a51d5efe 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor/ITextLineMarker.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor/ITextLineMarker.cs @@ -77,4 +77,12 @@ namespace MonoDevelop.Ide.Editor void AddTask (MonoDevelop.Ide.Tasks.TaskListEntry task); } + + public interface ICodeLensMarker : ITextLineMarker + { + int CodeLensCount { get; } + + void AddLens (MonoDevelop.Ide.Editor.Extension.CodeLens lens); + void RemoveLens (MonoDevelop.Ide.Editor.Extension.CodeLens lens); + } }
\ No newline at end of file diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor/InternalExtensionAPI/ITextMarkerFactory.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor/InternalExtensionAPI/ITextMarkerFactory.cs index 95900bc1d4..1581b639a4 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor/InternalExtensionAPI/ITextMarkerFactory.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Editor/InternalExtensionAPI/ITextMarkerFactory.cs @@ -44,6 +44,7 @@ namespace MonoDevelop.Ide.Editor ITextLineMarker CreateAsmLineMarker (TextEditor editor); IUnitTestMarker CreateUnitTestMarker (TextEditor editor, UnitTestMarkerHost host, UnitTestLocation unitTestLocation); IMessageBubbleLineMarker CreateMessageBubbleLineMarker (TextEditor editor); + ICodeLensMarker CreateCodeLensMarker (TextEditor editor); #endregion #region Segment marker diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.csproj b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.csproj index 9a8a810544..a7e558474b 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.csproj +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.csproj @@ -9460,6 +9460,7 @@ <Compile Include="MonoDevelop.Ide.Projects\LanguageCellRenderer.cs" /> <Compile Include="MonoDevelop.Components\RestartPanel.cs" /> <Compile Include="MonoDevelop.Ide.Gui.OptionPanels\DotNetCompileTargetSelector.cs" /> + <Compile Include="MonoDevelop.Ide.Editor.Extension\CodeLensTextEditorExtension.cs" /> </ItemGroup> <ItemGroup> <None Include="Makefile.am" /> |