diff --git a/src/OneWare.Essentials/EditorExtensions/ExtendedTextEditor.cs b/src/OneWare.Essentials/EditorExtensions/ExtendedTextEditor.cs
index ec23a89..8c59cc1 100644
--- a/src/OneWare.Essentials/EditorExtensions/ExtendedTextEditor.cs
+++ b/src/OneWare.Essentials/EditorExtensions/ExtendedTextEditor.cs
@@ -22,9 +22,11 @@ public class ExtendedTextEditor : TextEditor
public TextMarkerService MarkerService { get; }
public TextModificationService ModificationService { get; }
- private ElementGenerator ElementGenerator { get; }
+ // private ElementGenerator ElementGenerator { get; }
public FoldingManager? FoldingManager { get; private set; }
+ public InlayHintRenderer InlayHintRenderer { get; }
+
public ExtendedTextEditor()
{
// //Avoid Styles to improve performance
@@ -42,13 +44,14 @@ public ExtendedTextEditor()
TextArea.TextView.LinkTextUnderline = true;
TextArea.RightClickMovesCaret = true;
- ElementGenerator = new ElementGenerator();
BracketRenderer = new BracketHighlightRenderer(TextArea.TextView);
LineRenderer = new LineHighlightRenderer(this);
+ //ElementGenerator = new ElementGenerator();
//MergeService = new MergeService(this, ElementGenerator);
WordRenderer = new WordHighlightRenderer(TextArea.TextView);
MarkerService = new TextMarkerService(Document);
ModificationService = new TextModificationService(TextArea.TextView);
+ InlayHintRenderer = new InlayHintRenderer(this);
TextArea.TextView.BackgroundRenderers.Add(BracketRenderer);
TextArea.TextView.BackgroundRenderers.Add(LineRenderer);
@@ -57,7 +60,8 @@ public ExtendedTextEditor()
TextArea.TextView.BackgroundRenderers.Add(MarkerService);
TextArea.TextView.LineTransformers.Add(ModificationService);
- TextArea.TextView.ElementGenerators.Add(ElementGenerator);
+ //TextArea.TextView.ElementGenerators.Add(ElementGenerator);
+ TextArea.TextView.ElementGenerators.Add(InlayHintRenderer);
}
protected override void OnDocumentChanged(DocumentChangedEventArgs e)
diff --git a/src/OneWare.Essentials/EditorExtensions/InlayHintLineText.cs b/src/OneWare.Essentials/EditorExtensions/InlayHintLineText.cs
new file mode 100644
index 0000000..91211b0
--- /dev/null
+++ b/src/OneWare.Essentials/EditorExtensions/InlayHintLineText.cs
@@ -0,0 +1,30 @@
+using System.Diagnostics;
+using Avalonia.Media;
+using Avalonia.Media.TextFormatting;
+using AvaloniaEdit.Rendering;
+
+namespace OneWare.Essentials.EditorExtensions;
+
+public class InlayHintLineText : VisualLineText
+{
+ ///
+ /// Creates a visual line text element with the specified length.
+ /// It uses the and its
+ /// to find the actual text string.
+ ///
+ public InlayHintLineText(VisualLine parentVisualLine, int length) : base(parentVisualLine, length)
+ {
+
+ }
+
+ ///
+ public override TextRun CreateTextRun(int startVisualColumn, ITextRunConstructionContext context)
+ {
+ this.TextRunProperties.SetForegroundBrush(context.TextView.LinkTextForegroundBrush);
+ this.TextRunProperties.SetBackgroundBrush(context.TextView.LinkTextBackgroundBrush);
+
+ if (context.TextView.LinkTextUnderline)
+ this.TextRunProperties.SetTextDecorations(TextDecorations.Underline);
+ return base.CreateTextRun(startVisualColumn, context);
+ }
+}
\ No newline at end of file
diff --git a/src/OneWare.Essentials/EditorExtensions/InlayHintRenderer.cs b/src/OneWare.Essentials/EditorExtensions/InlayHintRenderer.cs
new file mode 100644
index 0000000..c6c2836
--- /dev/null
+++ b/src/OneWare.Essentials/EditorExtensions/InlayHintRenderer.cs
@@ -0,0 +1,118 @@
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Layout;
+using Avalonia.Media;
+using AvaloniaEdit;
+using AvaloniaEdit.Document;
+using AvaloniaEdit.Rendering;
+using DynamicData;
+
+namespace OneWare.Essentials.EditorExtensions;
+
+public class InlayHint
+{
+ public TextLocation Location { get; init; }
+
+ //Will be used internally
+ public int Offset { get; set; } = -1;
+
+ public string Text { get; init; } = string.Empty;
+}
+
+public class InlayHintRenderer : VisualLineElementGenerator
+{
+ private readonly TextEditor _editor;
+ private readonly List _hints = [];
+ private readonly List _hintControls = [];
+
+ public InlayHintRenderer(TextEditor editor)
+ {
+ _editor = editor;
+ }
+
+ public void SetInlineHints(IEnumerable hints)
+ {
+ _hints.Clear();
+ _hintControls.Clear();
+
+ _hints.AddRange(hints);
+
+ var foreground = Application.Current!.FindResource(Application.Current!.RequestedThemeVariant, "ThemeForegroundLowBrush") as IBrush;
+ var background = Application.Current!.FindResource(Application.Current!.RequestedThemeVariant, "ThemeBackgroundBrush") as IBrush;
+
+ foreach (var hint in _hints)
+ {
+ _hintControls.Add(new Border()
+ {
+ Margin = new Thickness(1, 0, 5, 0),
+ Background = background,
+ CornerRadius = new CornerRadius(3),
+ VerticalAlignment = VerticalAlignment.Center,
+ Child = new TextBlock()
+ {
+ Text = hint.Text,
+ Foreground = foreground,
+ Margin = new Thickness(2,0),
+ VerticalAlignment = VerticalAlignment.Center
+ }
+ });
+ }
+
+ _editor.TextArea.TextView.Redraw();
+ }
+
+ public void ClearInlineHints()
+ {
+ _hints.Clear();
+ _editor.TextArea.TextView.Redraw();
+ }
+
+ private static InlayHint? FindNextPosition(List positions, TextLocation startPosition)
+ {
+ int left = 0;
+ int right = positions.Count - 1;
+
+ while (left <= right)
+ {
+ int mid = left + (right - left) / 2;
+ int comparison = positions[mid].Location.CompareTo(startPosition);
+
+ if (comparison >= 0)
+ {
+ if (mid == 0 || positions[mid - 1].Location.CompareTo(startPosition) < 0)
+ {
+ return positions[mid];
+ }
+ right = mid - 1;
+ }
+ else
+ {
+ left = mid + 1;
+ }
+ }
+
+ return null;
+ }
+
+ public override int GetFirstInterestedOffset(int startOffset)
+ {
+ var position = _editor.Document.GetLocation(startOffset);
+ var next = FindNextPosition(_hints, position);
+
+ if(next == null)
+ return -1;
+
+ next.Offset = _editor.Document.GetOffset(next.Location);
+ return next.Offset;
+ }
+
+ public override VisualLineElement? ConstructElement(int offset)
+ {
+ var index = _hints.FindIndex(hint => hint.Offset == offset);
+
+ if (index < 0) return null;
+
+ var control = _hintControls[index];
+ return new InlineObjectElement(0, control);
+ }
+}
\ No newline at end of file
diff --git a/src/OneWare.Essentials/LanguageService/ILanguageService.cs b/src/OneWare.Essentials/LanguageService/ILanguageService.cs
index aaef372..ac52665 100644
--- a/src/OneWare.Essentials/LanguageService/ILanguageService.cs
+++ b/src/OneWare.Essentials/LanguageService/ILanguageService.cs
@@ -56,6 +56,7 @@ public interface ILanguageService
public Task RequestSymbolsAsync(string fullPath);
public Task?> RequestDocumentColorAsync(string fullPath);
public Task?> RequestSemanticTokensFullAsync(string fullPath);
+ public Task RequestInlayHintsAsync(string fullPath, Range range);
public Task RequestFormattingAsync(string fullPath);
public Task RequestRangeFormattingAsync(string fullPath, Range range);
public Task ExecuteCommandAsync(Command cmd);
diff --git a/src/OneWare.Essentials/LanguageService/LanguageServiceBase.cs b/src/OneWare.Essentials/LanguageService/LanguageServiceBase.cs
index a1ea250..ba1137f 100644
--- a/src/OneWare.Essentials/LanguageService/LanguageServiceBase.cs
+++ b/src/OneWare.Essentials/LanguageService/LanguageServiceBase.cs
@@ -162,6 +162,11 @@ public virtual void RefreshTextDocument(string fullPath, string newText)
return Task.FromResult?>(null);
}
+ public virtual Task RequestInlayHintsAsync(string fullPath, Range range)
+ {
+ return Task.FromResult(null);
+ }
+
public virtual Task RequestFormattingAsync(string fullPath)
{
return Task.FromResult(null);
diff --git a/src/OneWare.Essentials/LanguageService/LanguageServiceLsp.cs b/src/OneWare.Essentials/LanguageService/LanguageServiceLsp.cs
index 30a1a0c..430d277 100644
--- a/src/OneWare.Essentials/LanguageService/LanguageServiceLsp.cs
+++ b/src/OneWare.Essentials/LanguageService/LanguageServiceLsp.cs
@@ -496,6 +496,29 @@ public override Task ExecuteCommandAsync(Command cmd)
return null;
}
+ public override async Task RequestInlayHintsAsync(string fullPath, Range range)
+ {
+ if (Client?.ServerSettings.Capabilities.InlayHintProvider == null) return null;
+ try
+ {
+ var inlayHintContainer = await Client.RequestInlayHints(new InlayHintParams
+ {
+ TextDocument = new TextDocumentIdentifier
+ {
+ Uri = fullPath
+ },
+ Range = range
+ });
+ return inlayHintContainer;
+ }
+ catch (Exception e)
+ {
+ ContainerLocator.Container.Resolve()?.Error(e.Message, e);
+ }
+
+ return null;
+ }
+
public override async Task RequestCompletionAsync(string fullPath, Position pos, CompletionTriggerKind triggerKind, string? triggerChar)
{
var cts = new CancellationTokenSource();
diff --git a/src/OneWare.Essentials/LanguageService/TypeAssistanceLanguageService.cs b/src/OneWare.Essentials/LanguageService/TypeAssistanceLanguageService.cs
index b494c45..620148f 100644
--- a/src/OneWare.Essentials/LanguageService/TypeAssistanceLanguageService.cs
+++ b/src/OneWare.Essentials/LanguageService/TypeAssistanceLanguageService.cs
@@ -24,6 +24,7 @@
using Prism.Ioc;
using CompletionList = OmniSharp.Extensions.LanguageServer.Protocol.Models.CompletionList;
using IFile = OneWare.Essentials.Models.IFile;
+using InlayHint = OneWare.Essentials.EditorExtensions.InlayHint;
using Location = OmniSharp.Extensions.LanguageServer.Protocol.Models.Location;
using Range = OmniSharp.Extensions.LanguageServer.Protocol.Models.Range;
@@ -108,6 +109,7 @@ protected virtual void Timer_Tick(object? sender, EventArgs e)
//Execute slower actions after the caret was not changed for 100ms
_ = GetDocumentHighlightAsync();
+ _ = UpdateInlayHintsAsync();
}
if (_lastCompletionItemChangedTime > _lastCompletionItemResolveTime &&
@@ -144,6 +146,7 @@ protected override void OnAssistanceActivated()
Service.DidOpenTextDocument(CurrentFile.FullPath, Editor.CurrentDocument.Text);
_ = UpdateSemanticTokensAsync();
+ _ = UpdateInlayHintsAsync();
}
protected override void OnAssistanceDeactivated()
@@ -152,6 +155,7 @@ protected override void OnAssistanceDeactivated()
base.OnAssistanceDeactivated();
Editor.Editor.ModificationService.ClearModification("caretHighlight");
Editor.Editor.ModificationService.ClearModification("semanticTokens");
+ Editor.Editor.InlayHintRenderer.ClearInlineHints();
}
protected virtual void DocumentChanged(object? sender, DocumentChangeEventArgs e)
@@ -586,41 +590,24 @@ protected virtual async Task UpdateSemanticTokensAsync()
{
Editor.Editor.ModificationService.ClearModification("semanticTokens");
}
+ }
+
+ protected virtual async Task UpdateInlayHintsAsync()
+ {
+ var inlayHintContainer = await Service.RequestInlayHintsAsync(CurrentFile.FullPath, new Range(0,0, CodeBox.Document.LineCount, 0));
- // LastDocumentSymbols = await Service.RequestSymbolsAsync(CurrentFile.FullPath);
- //
- // var languageManager = ContainerLocator.Container.Resolve();
- //
- // if (LastDocumentSymbols is not null)
- // {
- // var segments = LastDocumentSymbols
- // .Where(x => x.IsDocumentSymbolInformation && x.SymbolInformation != null)
- // .Select(x =>
- // {
- // if (x.IsDocumentSymbol && x.DocumentSymbol != null)
- // {
- // if (!languageManager.CurrentEditorThemeColors.TryGetValue(x.DocumentSymbol.Kind,
- // out var brush)) return null;
- // return x.DocumentSymbol.Range.GenerateTextModification(Editor.CurrentDocument, brush);
- // }
- // if (x.IsDocumentSymbolInformation && x.SymbolInformation != null)
- // {
- // if (!languageManager.CurrentEditorThemeColors.TryGetValue(x.SymbolInformation.Kind, out var brush)) return null;
- // if (!x.SymbolInformation.Location.Uri.GetFileSystemPath().EqualPaths(CurrentFile.FullPath)) return null;
- // return x.SymbolInformation.Location.Range.GenerateTextModification(Editor.CurrentDocument, brush);
- // }
- // return null;
- // })
- // .Where(x => x is not null)
- // .Cast()
- // .ToArray();
- //
- // Editor.Editor.ModificationService.SetModification("symbols", segments);
- // }
- // else
- // {
- // Editor.Editor.ModificationService.ClearModification("symbols");
- // }
+ if (inlayHintContainer is not null)
+ {
+ Editor.Editor.InlayHintRenderer.SetInlineHints(inlayHintContainer.Select(x => new InlayHint()
+ {
+ Location = new TextLocation(x.Position.Line + 1, x.Position.Character + 1),
+ Text = x.Label.ToString()
+ }));
+ }
+ else
+ {
+ Editor.Editor.InlayHintRenderer.ClearInlineHints();
+ }
}
protected virtual async Task ShowSignatureHelpAsync(SignatureHelpTriggerKind triggerKind, string? triggerChar,