|
| 1 | +using System.Text.RegularExpressions; |
1 | 2 | using DocumentFormat.OpenXml; |
2 | 3 | using DocumentFormat.OpenXml.Packaging; |
3 | 4 | using SlideKit.Models; |
@@ -144,37 +145,30 @@ private static void AddTextBox(P.ShapeTree tree, ref uint id, Shape shape, strin |
144 | 145 | string bulletChar = shape.BulletChar ?? "\u2022"; |
145 | 146 | foreach (var item in shape.Bullets) |
146 | 147 | { |
147 | | - var runProps = new D.RunProperties { Language = "ja-JP", FontSize = fontSize, Bold = shape.Bold }; |
148 | | - runProps.Append(new D.SolidFill(new D.RgbColorModelHex { Val = color })); |
149 | | - runProps.Append(new D.LatinFont { Typeface = font }); |
150 | | - runProps.Append(new D.EastAsianFont { Typeface = font }); |
151 | | - |
152 | | - body.Append(new D.Paragraph( |
| 148 | + var para = new D.Paragraph( |
153 | 149 | new D.ParagraphProperties( |
154 | 150 | new D.SpaceAfter(new D.SpacingPoints { Val = 600 }), |
155 | 151 | new D.BulletFont { Typeface = "Arial" }, |
156 | 152 | new D.CharacterBullet { Char = bulletChar } |
157 | | - ) { LeftMargin = 342900, Indent = -342900, Alignment = alignment }, |
158 | | - new D.Run(runProps, new D.Text { Text = item }))); |
| 153 | + ) { LeftMargin = 342900, Indent = -342900, Alignment = alignment }); |
| 154 | + |
| 155 | + foreach (var run in CreateRuns(item, fontSize, color, font, shape.Bold)) |
| 156 | + para.Append(run); |
| 157 | + |
| 158 | + body.Append(para); |
159 | 159 | } |
160 | 160 | } |
161 | 161 | else |
162 | 162 | { |
163 | | - var runProps = new D.RunProperties(new D.SolidFill(new D.RgbColorModelHex { Val = color })) |
164 | | - { |
165 | | - Language = "ja-JP", |
166 | | - FontSize = fontSize, |
167 | | - Bold = shape.Bold, |
168 | | - }; |
169 | | - runProps.Append(new D.LatinFont { Typeface = font }); |
170 | | - runProps.Append(new D.EastAsianFont { Typeface = font }); |
| 163 | + var para = new D.Paragraph( |
| 164 | + new D.ParagraphProperties { Alignment = alignment }); |
| 165 | + foreach (var run in CreateRuns(shape.Text ?? "", fontSize, color, font, shape.Bold)) |
| 166 | + para.Append(run); |
171 | 167 |
|
172 | 168 | body = new D.TextBody( |
173 | 169 | new D.BodyProperties { Wrap = D.TextWrappingValues.Square, Anchor = D.TextAnchoringTypeValues.Top }, |
174 | 170 | new D.ListStyle(), |
175 | | - new D.Paragraph( |
176 | | - new D.ParagraphProperties { Alignment = alignment }, |
177 | | - new D.Run(runProps, new D.Text { Text = shape.Text ?? "" }))); |
| 171 | + para); |
178 | 172 | } |
179 | 173 |
|
180 | 174 | var sp = new P.Shape( |
@@ -457,6 +451,46 @@ private static void AddSpeakerNotes(SlidePart slidePart, string notes) |
457 | 451 | private static string Hex(string? color, string fallback = "FFFFFF") |
458 | 452 | => (color ?? fallback).TrimStart('#'); |
459 | 453 |
|
| 454 | + // Inline markdown: **bold**, *italic*, __bold__, _italic_ (and nesting like **_both_**) |
| 455 | + private static readonly Regex InlinePattern = new( |
| 456 | + @"(\*{1,3}|_{1,3})(.+?)\1", |
| 457 | + RegexOptions.Compiled); |
| 458 | + |
| 459 | + /// <summary> |
| 460 | + /// Creates D.Run elements from text with inline markdown, supporting nesting. |
| 461 | + /// </summary> |
| 462 | + private static IEnumerable<D.Run> CreateRuns(string text, int fontSize, string color, string font, |
| 463 | + bool shapeBold, bool shapeItalic = false) |
| 464 | + { |
| 465 | + int pos = 0; |
| 466 | + foreach (Match m in InlinePattern.Matches(text)) |
| 467 | + { |
| 468 | + if (m.Index > pos) |
| 469 | + yield return MakeRun(text[pos..m.Index], fontSize, color, font, shapeBold, shapeItalic); |
| 470 | + |
| 471 | + bool isBold = m.Groups[1].Value.Length >= 2; |
| 472 | + bool isItalic = m.Groups[1].Value.Length == 1 || m.Groups[1].Value.Length == 3; |
| 473 | + |
| 474 | + // Recurse into inner text to handle nesting (e.g. **_both_**) |
| 475 | + foreach (var run in CreateRuns(m.Groups[2].Value, fontSize, color, font, |
| 476 | + shapeBold || isBold, shapeItalic || isItalic)) |
| 477 | + yield return run; |
| 478 | + |
| 479 | + pos = m.Index + m.Length; |
| 480 | + } |
| 481 | + if (pos < text.Length) |
| 482 | + yield return MakeRun(text[pos..], fontSize, color, font, shapeBold, shapeItalic); |
| 483 | + } |
| 484 | + |
| 485 | + private static D.Run MakeRun(string text, int fontSize, string color, string font, bool bold, bool italic) |
| 486 | + { |
| 487 | + var props = new D.RunProperties { Language = "ja-JP", FontSize = fontSize, Bold = bold, Italic = italic }; |
| 488 | + props.Append(new D.SolidFill(new D.RgbColorModelHex { Val = color })); |
| 489 | + props.Append(new D.LatinFont { Typeface = font }); |
| 490 | + props.Append(new D.EastAsianFont { Typeface = font }); |
| 491 | + return new D.Run(props, new D.Text { Text = text }); |
| 492 | + } |
| 493 | + |
460 | 494 | // ---- Presentation initialization (fallback when no template) ---- |
461 | 495 |
|
462 | 496 | private static void InitializePresentation(PresentationDocument pres, SlideTheme theme) |
|
0 commit comments