Multi-Platform Package Manager for Stable Diffusion
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

153 lines
4.0 KiB

using System;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using Avalonia.Controls;
using Avalonia.Controls.Documents;
using Avalonia.Media;
using AvaloniaEdit.Document;
using AvaloniaEdit.Editing;
using StabilityMatrix.Avalonia.Models;
using StabilityMatrix.Avalonia.Styles;
using StabilityMatrix.Core.Extensions;
namespace StabilityMatrix.Avalonia.Controls.CodeCompletion;
/// <summary>
/// Provides entries in AvaloniaEdit completion window.
/// </summary>
public class CompletionData : ICompletionData
{
/// <inheritdoc />
public string Text { get; }
/// <inheritdoc />
public string? Description { get; init; }
/// <inheritdoc />
public ImageSource? ImageSource { get; set; }
/// <summary>
/// Title of the image.
/// </summary>
public string? ImageTitle { get; set; }
/// <summary>
/// Subtitle of the image.
/// </summary>
public string? ImageSubtitle { get; set; }
/// <inheritdoc />
public IconData? Icon { get; init; }
private InlineCollection? _textInlines;
/// <summary>
/// Get the current inlines
/// </summary>
public InlineCollection TextInlines => _textInlines ??= CreateInlines();
/// <inheritdoc />
public double Priority { get; init; }
public CompletionData(string text)
{
Text = text;
}
/// <summary>
/// Create text block inline runs from text.
/// </summary>
private InlineCollection CreateInlines()
{
// Create a span for each character in the text.
var chars = Text.ToCharArray();
var inlines = new InlineCollection();
foreach (var c in chars)
{
var run = new Run(c.ToString());
inlines.Add(run);
}
return inlines;
}
/// <inheritdoc />
public void Complete(
TextArea textArea,
ISegment completionSegment,
InsertionRequestEventArgs eventArgs,
Func<ICompletionData, string>? prepareText = null
)
{
var text = Text;
if (prepareText is not null)
{
text = prepareText(this);
}
// Capture initial offset before replacing text, since it will change
var initialOffset = completionSegment.Offset;
// Replace text
textArea.Document.Replace(completionSegment, text);
// Append text if requested
if (eventArgs.AppendText is { } appendText && !string.IsNullOrEmpty(appendText))
{
var end = initialOffset + text.Length;
textArea.Document.Insert(end, appendText);
textArea.Caret.Offset = end + appendText.Length;
}
}
/// <inheritdoc />
public void UpdateCharHighlighting(string searchText)
{
if (TextInlines is null)
{
throw new NullReferenceException("TextContent is null");
}
var defaultColor = ThemeColors.CompletionForegroundBrush;
var highlightColor = ThemeColors.CompletionSelectionForegroundBrush;
// Match characters in the text with the search text from the start
foreach (var (i, currentChar) in Text.Enumerate())
{
var inline = TextInlines[i];
// If longer than text, set to default color
if (i >= searchText.Length)
{
inline.Foreground = defaultColor;
continue;
}
// If char matches, highlight it
if (currentChar == searchText[i])
{
inline.Foreground = highlightColor;
}
// For mismatch, set to default color
else
{
inline.Foreground = defaultColor;
}
}
}
/// <inheritdoc />
public void ResetCharHighlighting()
{
// TODO: handle light theme foreground variant
var defaultColor = ThemeColors.CompletionForegroundBrush;
foreach (var inline in TextInlines)
{
inline.Foreground = defaultColor;
}
}
}