Skip to content

Commit 36f571b

Browse files
committed
fix: return string Content from FmScriptCompletionData
The cached TextBlock introduced in f37e5a5 violates Avalonia's single-parent rule when AvaloniaEdit's CompletionList reuses the item across multiple ContentPresenter instances — produced an InvalidOperationException ('already has a visual parent ContentPresenter') the moment the completion window opened. Return the bare Text string instead. ContentPresenter wraps it in its own TextBlock automatically and owns that wrapper exclusively, so reuse across virtualised rows is safe. Drops one allocation per Content access compared to the original 'new TextBlock { Text = .. }' factory pattern.
1 parent adbd7aa commit 36f571b

1 file changed

Lines changed: 5 additions & 10 deletions

File tree

src/SharpFM/Scripting/Editor/FmScriptCompletionData.cs

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
using System;
22
using System.Diagnostics.CodeAnalysis;
33
using System.Text.RegularExpressions;
4-
using Avalonia.Controls;
54
using Avalonia.Media;
65
using AvaloniaEdit.CodeCompletion;
76
using AvaloniaEdit.Document;
@@ -17,7 +16,6 @@ public class FmScriptCompletionData : ICompletionData
1716
new(@"\$\{(\d+):([^}]*)\}|\$0", RegexOptions.Compiled);
1817

1918
private readonly string? _snippet;
20-
private readonly TextBlock _content;
2119

2220
public FmScriptCompletionData(string text, string? description = null,
2321
double priority = 0, string? snippet = null)
@@ -26,18 +24,15 @@ public FmScriptCompletionData(string text, string? description = null,
2624
Description = description ?? text;
2725
Priority = priority;
2826
_snippet = snippet;
29-
30-
// Cache the Content control instead of allocating a fresh TextBlock
31-
// on every property access. AvaloniaEdit's CompletionList may
32-
// re-read Content during virtualization / filter narrowing, and
33-
// each completion item is owned by a single ContentPresenter so
34-
// sharing a per-item TextBlock is safe.
35-
_content = new TextBlock { Text = text };
3627
}
3728

3829
public IImage? Image => null;
3930
public string Text { get; }
40-
public object Content => _content;
31+
// Return the bare string. ContentPresenter wraps it in a TextBlock
32+
// automatically and that wrapper is owned by exactly one parent, so
33+
// unlike a cached Control instance there's no "already has a visual
34+
// parent" failure when the completion window reopens or virtualises.
35+
public object Content => Text;
4136
public object Description { get; }
4237
public double Priority { get; }
4338

0 commit comments

Comments
 (0)