using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
namespace codelanguage
{
///
/// Interactive code completion dropdown UI with filtering, selection, and documentation preview.
/// Displays completion items with icons, types, and inline documentation.
///
public partial class CodeCompletionDropdown : UserControl
{
public ObservableCollection Items { get; } = new();
public event EventHandler ItemSelected;
public event EventHandler CompletionCancelled;
private CompletionItemUI _selectedItem;
private int _selectedIndex = -1;
public CodeCompletionDropdown()
{
InitializeComponent();
CompletionListBox.ItemsSource = Items;
CompletionListBox.SelectionChanged += CompletionListBox_SelectionChanged;
FilterTextBox.TextChanged += FilterTextBox_TextChanged;
PreviewKeyDown += CodeCompletionDropdown_PreviewKeyDown;
FilterTextBox.PreviewKeyDown += FilterTextBox_PreviewKeyDown;
FilterTextBox.Focus();
}
private void CodeCompletionDropdown_PreviewKeyDown(object sender, KeyEventArgs e)
{
HandlePreviewKey(e);
}
private void FilterTextBox_PreviewKeyDown(object sender, KeyEventArgs e)
{
HandlePreviewKey(e);
}
private void HandlePreviewKey(KeyEventArgs e)
{
switch (e.Key)
{
case Key.Up:
SelectItem(_selectedIndex - 1);
e.Handled = true;
break;
case Key.Down:
SelectItem(_selectedIndex + 1);
e.Handled = true;
break;
case Key.Enter:
case Key.Tab:
if (_selectedItem != null)
{
ItemSelected?.Invoke(this, _selectedItem);
Hide();
}
e.Handled = true;
break;
case Key.Escape:
Hide();
e.Handled = true;
break;
}
}
public void SelectNext() => SelectItem(_selectedIndex + 1);
public void SelectPrevious() => SelectItem(_selectedIndex - 1);
public void ShowCompletions(List items, int x, int y)
{
Items.Clear();
_selectedIndex = -1;
foreach (var item in items)
{
Items.Add(new CompletionItemUI(item));
}
// Position dropdown
if (Parent is Canvas canvas)
{
Canvas.SetLeft(this, x);
Canvas.SetTop(this, y);
}
Visibility = Visibility.Visible;
FilterTextBox.Clear();
FilterTextBox.Focus();
if (Items.Count > 0)
SelectItem(0);
}
public void Hide()
{
Visibility = Visibility.Collapsed;
CompletionCancelled?.Invoke(this, EventArgs.Empty);
}
private void SelectItem(int index)
{
if (index < 0 || index >= Items.Count)
return;
_selectedIndex = index;
CompletionListBox.SelectedIndex = index;
CompletionListBox.ScrollIntoView(Items[index]);
_selectedItem = Items[index];
UpdateDocumentation(_selectedItem);
}
private void UpdateDocumentation(CompletionItemUI item)
{
Documentation.Text = !string.IsNullOrEmpty(item.Documentation)
? item.Documentation
: $"Kind: {item.Kind}\nNo additional documentation available.";
}
private void CompletionListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (CompletionListBox.SelectedItem is CompletionItemUI item)
{
_selectedItem = item;
UpdateDocumentation(item);
}
}
private void CompletionListBox_KeyDown(object sender, KeyEventArgs e)
{
switch (e.Key)
{
case Key.Up:
SelectItem(_selectedIndex - 1);
e.Handled = true;
break;
case Key.Down:
SelectItem(_selectedIndex + 1);
e.Handled = true;
break;
case Key.Enter:
case Key.Tab:
if (_selectedItem != null)
{
ItemSelected?.Invoke(this, _selectedItem);
Hide();
}
e.Handled = true;
break;
case Key.Escape:
Hide();
e.Handled = true;
break;
}
}
private void FilterTextBox_TextChanged(object sender, TextChangedEventArgs e)
{
string filter = FilterTextBox.Text.ToLower();
// Filter items
if (string.IsNullOrEmpty(filter))
{
foreach (var item in Items)
item.IsVisible = true;
}
else
{
foreach (var item in Items)
{
item.IsVisible = item.Label.ToLower().Contains(filter) ||
item.Documentation?.ToLower().Contains(filter) == true;
}
}
// Re-select first visible
for (int i = 0; i < Items.Count; i++)
{
if (Items[i].IsVisible)
{
SelectItem(i);
return;
}
}
}
private void CompletionItem_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
if (sender is FrameworkElement elem && elem.DataContext is CompletionItemUI item)
{
ItemSelected?.Invoke(this, item);
Hide();
e.Handled = true;
}
}
public CompletionItemUI GetSelectedItem() => _selectedItem;
}
/// UI wrapper for CompletionItem with visual styling and filtering support
public class CompletionItemUI : CompletionItem
{
private bool _isVisible = true;
public CompletionItemUI(CompletionItem item)
: base(item.Label, item.InsertText, item.Documentation, item.Kind, item.SortOrder)
{
}
public bool IsVisible
{
get => _isVisible;
set => _isVisible = value;
}
public string IconChar => Kind switch
{
CompletionItemKind.Variable => "🔤",
CompletionItemKind.Procedure => "⚙",
CompletionItemKind.Type => "📦",
CompletionItemKind.Keyword => "🔑",
CompletionItemKind.BuiltinProc => "⭐",
CompletionItemKind.Field => "📝",
CompletionItemKind.Parameter => "📥",
CompletionItemKind.Snippet => "📋",
_ => "•"
};
public Brush ItemBackground
{
get
{
return Kind switch
{
CompletionItemKind.Keyword => VisualThemeManager.GetBrush("Keyword"),
CompletionItemKind.BuiltinProc => VisualThemeManager.GetBrush("BuiltinProc"),
CompletionItemKind.Type => VisualThemeManager.GetBrush("Type"),
_ => VisualThemeManager.GetBrush("SurfaceLight")
};
}
}
}
}