Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 68 additions & 0 deletions src/SharpFM/Editors/ScriptTextEditor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
using System;
using System.Diagnostics.CodeAnalysis;
using Avalonia;
using Avalonia.Controls;
using AvaloniaEdit;
using AvaloniaEdit.TextMate;
using SharpFM.Scripting;
using SharpFM.Scripting.Editor;
using SharpFM.ViewModels;
using TextMateSharp.Grammars;

namespace SharpFM.Editors;

/// <summary>
/// A specialized <see cref="TextEditor"/> for script clips. Owns its
/// TextMate installation and <see cref="ScriptEditorController"/> so it
/// can be dropped into a <c>DataTemplate</c> without any parent wiring —
/// each instance self-installs on construction and tears down on detach.
/// DataContext is expected to be a <see cref="ScriptClipEditor"/>.
/// </summary>
[ExcludeFromCodeCoverage]
public class ScriptTextEditor : TextEditor
{
// Avalonia 12 matches styles by exact type. Without this, a subclass of
// TextEditor gets no control template and renders blank — the editor's
// TextArea/TextView visual tree is never built.
protected override Type StyleKeyOverride => typeof(TextEditor);

private readonly TextMate.Installation _textMate;
private readonly ScriptEditorController _controller;

public ScriptTextEditor()
{
var registry = new RegistryOptions((ThemeName)(int)ThemeName.DarkPlus);
var fmScriptRegistry = new FmScriptRegistryOptions(registry);
_textMate = this.InstallTextMate(fmScriptRegistry);
_textMate.SetGrammar(FmScriptRegistryOptions.ScopeName);

_controller = new ScriptEditorController(this);
_controller.StatusMessageRaised += OnStatusMessageRaised;
}

protected override void OnDataContextChanged(EventArgs e)
{
base.OnDataContextChanged(e);

if (DataContext is not ScriptClipEditor clipEditor) return;

Document = clipEditor.Document;
_controller.AttachClipEditor(clipEditor);
}

protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e)
{
base.OnDetachedFromVisualTree(e);

_controller.StatusMessageRaised -= OnStatusMessageRaised;
_controller.Dispose();
_textMate.Dispose();
}

private void OnStatusMessageRaised(object? sender, StatusMessageEventArgs e)
{
var window = TopLevel.GetTopLevel(this) as Window;
if (window?.DataContext is MainWindowViewModel vm)
vm.ShowStatusMessage(e.Message, e.IsError);
}
}
56 changes: 32 additions & 24 deletions src/SharpFM/MainWindow.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vm="using:SharpFM.ViewModels"
xmlns:editors="using:SharpFM.Editors"
xmlns:schema="using:SharpFM.Schema.Editor"
Icon="/Assets/noun-sharp-teeth-monster-4226695.small.png"
Title="SharpFM"
Expand Down Expand Up @@ -206,33 +207,40 @@
<ColumnDefinition Width="0" />
</Grid.ColumnDefinitions>

<!-- Code editor with Fluent 2 surface treatment -->
<!-- Code editor with Fluent 2 surface treatment. The editor is
selected by the runtime type of ClipViewModel.Editor: no
binding resolves through a null SelectedClip, and no editor
instance exists when no clip is selected. -->
<Border
Grid.Column="0"
Classes="Fluent2SurfaceElevated">
<Grid x:DataType="vm:MainWindowViewModel">
<!-- Script editor for script clips -->
<AvaloniaEdit:TextEditor
x:Name="scriptEditor"
FontFamily="Cascadia Code,Consolas,Menlo,Monospace"
ShowLineNumbers="True"
WordWrap="False"
IsVisible="{Binding SelectedClip.IsScriptClip, FallbackValue=False}"
Document="{Binding SelectedClip.ScriptDocument}" />
<!-- Table editor for table/field clips -->
<Border IsVisible="{Binding SelectedClip.IsTableClip, FallbackValue=False}">
<schema:TableEditorControl DataContext="{Binding SelectedClip.TableEditor}" />
</Border>
<!-- Fallback XML editor for other clips -->
<AvaloniaEdit:TextEditor
x:Name="fallbackXmlEditor"
FontFamily="Cascadia Code,Consolas,Menlo,Monospace"
ShowLineNumbers="True"
SyntaxHighlighting="Xml"
WordWrap="False"
IsVisible="{Binding SelectedClip.IsFallbackClip, FallbackValue=False}"
Document="{Binding SelectedClip.XmlDocument}" />
</Grid>
<ContentControl Content="{Binding SelectedClip}">
<ContentControl.DataTemplates>
<DataTemplate DataType="vm:ClipViewModel">
<ContentControl Content="{Binding Editor}">
<ContentControl.DataTemplates>
<DataTemplate DataType="editors:ScriptClipEditor">
<editors:ScriptTextEditor
FontFamily="Cascadia Code,Consolas,Menlo,Monospace"
ShowLineNumbers="True"
WordWrap="False" />
</DataTemplate>
<DataTemplate DataType="editors:TableClipEditor">
<schema:TableEditorControl DataContext="{Binding ViewModel}" />
</DataTemplate>
<DataTemplate DataType="editors:FallbackXmlEditor">
<AvaloniaEdit:TextEditor
FontFamily="Cascadia Code,Consolas,Menlo,Monospace"
ShowLineNumbers="True"
SyntaxHighlighting="Xml"
WordWrap="False"
Document="{Binding Document}" />
</DataTemplate>
</ContentControl.DataTemplates>
</ContentControl>
</DataTemplate>
</ContentControl.DataTemplates>
</ContentControl>
</Border>

<!-- Plugin panel splitter -->
Expand Down
51 changes: 0 additions & 51 deletions src/SharpFM/MainWindow.axaml.cs
Original file line number Diff line number Diff line change
@@ -1,29 +1,21 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Input;
using AvaloniaEdit;
using AvaloniaEdit.TextMate;
using SharpFM.Diagnostics;
using SharpFM.Plugin;
using SharpFM.Plugin.UI;
using SharpFM.PluginManager;
using SharpFM.Scripting;
using SharpFM.Services;
using SharpFM.ViewModels;
using TextMateSharp.Grammars;

namespace SharpFM;

[ExcludeFromCodeCoverage]
public partial class MainWindow : Window
{
private readonly RegistryOptions _registryOptions;
private ScriptEditorController? _scriptController;
private TextMate.Installation? _scriptTextMateInstallation;
private PluginService? _pluginService;
private PluginUIHost? _pluginHost;
private PluginConfigService? _pluginConfigService;
Expand All @@ -32,19 +24,6 @@ public MainWindow()
{
InitializeComponent();

_registryOptions = new RegistryOptions((ThemeName)(int)ThemeName.DarkPlus);

// Script editor
var scriptEditor = this.FindControl<TextEditor>("scriptEditor");
if (scriptEditor != null)
{
var fmScriptRegistry = new FmScriptRegistryOptions(_registryOptions);
_scriptTextMateInstallation = scriptEditor.InstallTextMate(fmScriptRegistry);
_scriptTextMateInstallation.SetGrammar(FmScriptRegistryOptions.ScopeName);
_scriptController = new ScriptEditorController(scriptEditor);
_scriptController.StatusMessageRaised += OnScriptControllerStatusMessage;
}

// "Manage Plugins..." menu item
var managePlugins = this.FindControl<MenuItem>("managePluginsMenuItem");
if (managePlugins != null)
Expand All @@ -71,18 +50,11 @@ private void OnDataContextChanged(object? sender, EventArgs e)
if (DataContext is not MainWindowViewModel vm) return;

BuildPluginMenuItems(vm);
vm.PropertyChanged += OnViewModelPropertyChanged;

if (vm.PluginUI is { } pluginUI)
pluginUI.PropertyChanged += OnPluginUIPropertyChanged;
}

private void OnViewModelPropertyChanged(object? sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == nameof(MainWindowViewModel.SelectedClip))
AttachScriptClipEditorIfApplicable();
}

private void OnPluginUIPropertyChanged(object? sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == nameof(PluginUIHost.IsVisible))
Expand All @@ -91,22 +63,6 @@ private void OnPluginUIPropertyChanged(object? sender, PropertyChangedEventArgs
UpdatePluginPanelContent();
}

private void OnScriptControllerStatusMessage(object? sender, SharpFM.Scripting.Editor.StatusMessageEventArgs e)
{
if (DataContext is MainWindowViewModel vm)
vm.ShowStatusMessage(e.Message, e.IsError);
}

private void AttachScriptClipEditorIfApplicable()
{
if (_scriptController == null) return;
if (DataContext is not MainWindowViewModel vm) return;
if (vm.SelectedClip?.Editor is SharpFM.Editors.ScriptClipEditor clipEditor)
{
_scriptController.AttachClipEditor(clipEditor);
}
}

private void BuildPluginMenuItems(MainWindowViewModel vm)
{
var pluginsMenu = this.FindControl<MenuItem>("pluginsMenu");
Expand Down Expand Up @@ -238,11 +194,4 @@ private void ShowPluginManager()
window.Configure(_pluginService, _pluginHost, vm, _pluginConfigService);
window.ShowDialog(this);
}

protected override void OnClosed(EventArgs e)
{
base.OnClosed(e);
_scriptController?.Dispose();
_scriptTextMateInstallation?.Dispose();
}
}
Loading