From e42776cbc1fa24d8afca00d3a8e8b7e88751d3af Mon Sep 17 00:00:00 2001 From: Hendrik Mennen Date: Fri, 19 Jun 2026 11:10:07 +0200 Subject: [PATCH 1/2] markdown previewer --- OneWare.slnx | 2 +- .../MarkdownViewerModule.cs | 20 +++ .../OneWare.MarkdownViewer.csproj | 9 ++ .../ViewModels/MarkdownEditViewModel.cs | 128 ++++++++++++++++++ .../Views/MarkdownEditView.axaml | 58 ++++++++ .../Views/MarkdownEditView.axaml.cs | 12 ++ studio/OneWare.Studio/OneWare.Studio.csproj | 1 + studio/OneWare.Studio/StudioApp.cs | 2 + 8 files changed, 231 insertions(+), 1 deletion(-) create mode 100644 src/OneWare.MarkdownViewer/MarkdownViewerModule.cs create mode 100644 src/OneWare.MarkdownViewer/OneWare.MarkdownViewer.csproj create mode 100644 src/OneWare.MarkdownViewer/ViewModels/MarkdownEditViewModel.cs create mode 100644 src/OneWare.MarkdownViewer/Views/MarkdownEditView.axaml create mode 100644 src/OneWare.MarkdownViewer/Views/MarkdownEditView.axaml.cs diff --git a/OneWare.slnx b/OneWare.slnx index c86871a86..bdc8fde32 100644 --- a/OneWare.slnx +++ b/OneWare.slnx @@ -89,8 +89,8 @@ - + diff --git a/src/OneWare.MarkdownViewer/MarkdownViewerModule.cs b/src/OneWare.MarkdownViewer/MarkdownViewerModule.cs new file mode 100644 index 000000000..b43805598 --- /dev/null +++ b/src/OneWare.MarkdownViewer/MarkdownViewerModule.cs @@ -0,0 +1,20 @@ +using Microsoft.Extensions.DependencyInjection; +using OneWare.Essentials.Services; +using OneWare.MarkdownViewer.ViewModels; + +namespace OneWare.MarkdownViewer; + +public class MarkdownViewerModule : OneWareModuleBase +{ + public override void RegisterServices(IServiceCollection services) + { + services.AddTransient(); + } + + public override void Initialize(IServiceProvider serviceProvider) + { + serviceProvider.Resolve() + .RegisterDocumentView(".md", ".markdown"); + } +} + diff --git a/src/OneWare.MarkdownViewer/OneWare.MarkdownViewer.csproj b/src/OneWare.MarkdownViewer/OneWare.MarkdownViewer.csproj new file mode 100644 index 000000000..48b97a298 --- /dev/null +++ b/src/OneWare.MarkdownViewer/OneWare.MarkdownViewer.csproj @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/src/OneWare.MarkdownViewer/ViewModels/MarkdownEditViewModel.cs b/src/OneWare.MarkdownViewer/ViewModels/MarkdownEditViewModel.cs new file mode 100644 index 000000000..361b41d93 --- /dev/null +++ b/src/OneWare.MarkdownViewer/ViewModels/MarkdownEditViewModel.cs @@ -0,0 +1,128 @@ +using System.Reactive.Disposables; +using System.Reactive.Linq; +using Avalonia.Controls; +using Avalonia.Threading; +using CommunityToolkit.Mvvm.Input; +using Microsoft.Extensions.Logging; +using OneWare.Core.Services; +using OneWare.Core.ViewModels.DockViews; +using OneWare.Essentials.LanguageService; +using OneWare.Essentials.Models; +using OneWare.Essentials.Services; + +namespace OneWare.MarkdownViewer.ViewModels; + +/// +/// An for markdown files that adds a live preview pane. +/// The editor and the preview can be toggled independently to allow editor-only, +/// preview-only or split-screen layouts. +/// +public class MarkdownEditViewModel : EditViewModel +{ + private readonly CompositeDisposable _markdownComposite = new(); + + private bool _showEditor = true; + private bool _showPreview = true; + private string? _markdownText; + + public MarkdownEditViewModel(string fullPath, ILogger logger, IFileIconService fileIconService, + ISettingsService settingsService, IMainDockService mainDockService, ILanguageManager languageManager, + IWindowService windowService, IProjectExplorerService projectExplorerService, IErrorService errorService, + BackupService backupService) : base(fullPath, logger, fileIconService, settingsService, mainDockService, + languageManager, windowService, projectExplorerService, errorService, backupService) + { + ToggleEditorCommand = new RelayCommand(() => ShowEditor = !ShowEditor); + TogglePreviewCommand = new RelayCommand(() => ShowPreview = !ShowPreview); + + // Keep the preview in sync with the editor content. The document instance can be + // replaced when the file is (re)loaded, so we listen to both events. + Editor.DocumentChanged += OnEditorChanged; + + Observable.FromEventPattern( + h => Editor.TextChanged += h, + h => Editor.TextChanged -= h) + .Throttle(TimeSpan.FromMilliseconds(250)) + .Subscribe(_ => UpdateMarkdown()) + .DisposeWith(_markdownComposite); + } + + public RelayCommand ToggleEditorCommand { get; } + + public RelayCommand TogglePreviewCommand { get; } + + public string? MarkdownText + { + get => _markdownText; + private set => SetProperty(ref _markdownText, value); + } + + public bool ShowEditor + { + get => _showEditor; + set + { + // Always keep at least one pane visible. + if (!value && !ShowPreview) ShowPreview = true; + if (SetProperty(ref _showEditor, value)) + { + OnPropertyChanged(nameof(IsSplitterVisible)); + OnPropertyChanged(nameof(EditorColumnWidth)); + } + } + } + + public bool ShowPreview + { + get => _showPreview; + set + { + // Always keep at least one pane visible. + if (!value && !ShowEditor) ShowEditor = true; + if (SetProperty(ref _showPreview, value)) + { + OnPropertyChanged(nameof(IsSplitterVisible)); + OnPropertyChanged(nameof(PreviewColumnWidth)); + if (value) UpdateMarkdown(); + } + } + } + + public bool IsSplitterVisible => ShowEditor && ShowPreview; + + /// Star width when the editor is visible, collapsed otherwise. + public GridLength EditorColumnWidth => + ShowEditor ? new GridLength(1, GridUnitType.Star) : new GridLength(0, GridUnitType.Auto); + + /// Star width when the preview is visible, collapsed otherwise. + public GridLength PreviewColumnWidth => + ShowPreview ? new GridLength(1, GridUnitType.Star) : new GridLength(0, GridUnitType.Auto); + + private void OnEditorChanged(object? sender, EventArgs e) + { + UpdateMarkdown(); + } + + private void UpdateMarkdown() + { + if (Dispatcher.UIThread.CheckAccess()) + MarkdownText = Editor.Document?.Text ?? string.Empty; + else + Dispatcher.UIThread.Post(() => MarkdownText = Editor.Document?.Text ?? string.Empty); + } + + public override bool OnClose() + { + var result = base.OnClose(); + if (!result) return false; + + Editor.DocumentChanged -= OnEditorChanged; + _markdownComposite.Dispose(); + return true; + } +} + + + + + + diff --git a/src/OneWare.MarkdownViewer/Views/MarkdownEditView.axaml b/src/OneWare.MarkdownViewer/Views/MarkdownEditView.axaml new file mode 100644 index 000000000..309330d68 --- /dev/null +++ b/src/OneWare.MarkdownViewer/Views/MarkdownEditView.axaml @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/OneWare.MarkdownViewer/Views/MarkdownEditView.axaml.cs b/src/OneWare.MarkdownViewer/Views/MarkdownEditView.axaml.cs new file mode 100644 index 000000000..785eaffac --- /dev/null +++ b/src/OneWare.MarkdownViewer/Views/MarkdownEditView.axaml.cs @@ -0,0 +1,12 @@ +using Avalonia.Controls; + +namespace OneWare.MarkdownViewer.Views; + +public partial class MarkdownEditView : UserControl +{ + public MarkdownEditView() + { + InitializeComponent(); + } +} + diff --git a/studio/OneWare.Studio/OneWare.Studio.csproj b/studio/OneWare.Studio/OneWare.Studio.csproj index accb5e86b..9b8326985 100644 --- a/studio/OneWare.Studio/OneWare.Studio.csproj +++ b/studio/OneWare.Studio/OneWare.Studio.csproj @@ -21,6 +21,7 @@ + diff --git a/studio/OneWare.Studio/StudioApp.cs b/studio/OneWare.Studio/StudioApp.cs index 7760944e4..a907f80f3 100644 --- a/studio/OneWare.Studio/StudioApp.cs +++ b/studio/OneWare.Studio/StudioApp.cs @@ -8,6 +8,7 @@ using OneWare.CruviAdapterExtensions; using OneWare.Essentials.Models; using OneWare.Essentials.Services; +using OneWare.MarkdownViewer; using OneWare.Settings; using OneWare.Studio.Styles; using OneWare.UniversalFpgaProjectSystem; @@ -98,5 +99,6 @@ protected override void ConfigureModuleCatalog(OneWareModuleCatalog moduleCatalo moduleCatalog.AddModule(); moduleCatalog.AddModule(); moduleCatalog.AddModule(); + moduleCatalog.AddModule(); } } \ No newline at end of file From 1bf01f55f4bf1988fad50ae66f952535a37916fd Mon Sep 17 00:00:00 2001 From: Hendrik Mennen Date: Fri, 19 Jun 2026 11:14:25 +0200 Subject: [PATCH 2/2] fix AI Mistake --- OneWare.slnx | 1 + 1 file changed, 1 insertion(+) diff --git a/OneWare.slnx b/OneWare.slnx index bdc8fde32..2ccfc40de 100644 --- a/OneWare.slnx +++ b/OneWare.slnx @@ -89,6 +89,7 @@ +