| 1 | using Markdig; |
| 2 | using CascadeIDE.Models; |
| 3 | |
| 4 | namespace CascadeIDE.Services.MarkdownPreview; |
| 5 | |
| 6 | /// <summary>Единая точка include/diagram expansion и Markdig parse перед рендером.</summary> |
| 7 | public sealed class MarkdownPreviewPayloadBuilder |
| 8 | { |
| 9 | private static readonly MarkdownPipeline Pipeline = new MarkdownPipelineBuilder() |
| 10 | .UseAdvancedExtensions() |
| 11 | .Build(); |
| 12 | |
| 13 | public async Task<MarkdownPreviewPayload> BuildAsync( |
| 14 | MarkdownPreviewSource source, |
| 15 | CascadeIdeSettings settings, |
| 16 | CancellationToken cancellationToken = default) |
| 17 | { |
| 18 | var title = string.IsNullOrWhiteSpace(source.Title) ? "Markdown Preview" : source.Title.Trim(); |
| 19 | var raw = source.Markdown ?? ""; |
| 20 | var renderMarkdown = raw; |
| 21 | var notices = new List<string>(); |
| 22 | |
| 23 | if (!string.IsNullOrWhiteSpace(source.SourcePath)) |
| 24 | { |
| 25 | try |
| 26 | { |
| 27 | renderMarkdown = MarkdownIncludeExpansion.ExpandMarkdown(renderMarkdown, source.SourcePath!); |
| 28 | } |
| 29 | catch (IncludeExpansionException ex) |
| 30 | { |
| 31 | notices.Add($"Include expansion: {ex.Message}"); |
| 32 | } |
| 33 | } |
| 34 | |
| 35 | try |
| 36 | { |
| 37 | renderMarkdown = MarkdownCodeAnchorPreviewExpander.Expand(renderMarkdown); |
| 38 | } |
| 39 | catch (Exception ex) |
| 40 | { |
| 41 | notices.Add($"Code anchor links: {ex.Message}"); |
| 42 | } |
| 43 | |
| 44 | try |
| 45 | { |
| 46 | renderMarkdown = await MarkdownDiagramExpansion.ExpandAsync(renderMarkdown, settings, cancellationToken).ConfigureAwait(false); |
| 47 | } |
| 48 | catch (OperationCanceledException) |
| 49 | { |
| 50 | throw; |
| 51 | } |
| 52 | catch (Exception ex) |
| 53 | { |
| 54 | notices.Add($"Diagram expansion: {ex.Message}"); |
| 55 | } |
| 56 | |
| 57 | try |
| 58 | { |
| 59 | var document = Markdig.Markdown.Parse(renderMarkdown, Pipeline); |
| 60 | return new MarkdownPreviewPayload(title, raw, renderMarkdown, source.SourcePath, document, notices, null); |
| 61 | } |
| 62 | catch (Exception ex) |
| 63 | { |
| 64 | notices.Add("Rendered as fallback because Markdown parsing failed."); |
| 65 | return new MarkdownPreviewPayload(title, raw, renderMarkdown, source.SourcePath, null, notices, ex.Message); |
| 66 | } |
| 67 | } |
| 68 | } |
| 69 | |