Emphasis Rendering in WYSIWYG Mode
January 17, 2026 · View on GitHub
Overview
Ferrite supports bold, italic, and strikethrough text formatting in the WYSIWYG (Rendered) view mode. This document describes how emphasis markdown is parsed and rendered, including support for nested/combined formatting.
Supported Syntax
Basic Emphasis
| Markdown | Rendered | Style |
|---|---|---|
*italic* | italic | Italic |
_italic_ | italic | Italic |
**bold** | bold | Bold |
__bold__ | bold | Bold |
~~strikethrough~~ | Strikethrough |
Nested/Combined Emphasis
| Markdown | Rendered | Styles Applied |
|---|---|---|
***bold italic*** | bold italic | Bold + Italic |
___bold italic___ | bold italic | Bold + Italic |
**_bold italic_** | bold italic | Bold + Italic |
__*bold italic*__ | bold italic | Bold + Italic |
*__bold italic__* | bold italic | Bold + Italic |
_**bold italic**_ | bold italic | Bold + Italic |
~~**bold strikethrough**~~ | Bold + Strikethrough | |
~~*italic strikethrough*~~ | Italic + Strikethrough | |
~~***all three***~~ | Bold + Italic + Strikethrough |
Implementation
Architecture
The emphasis rendering is implemented in src/markdown/editor.rs using a style accumulation pattern:
Parser (comrak) → AST with nested nodes → Renderer with TextStyle accumulator → egui RichText
Key Components
1. TextStyle Accumulator
struct TextStyle {
bold: bool,
italic: bool,
strikethrough: bool,
}
The TextStyle struct accumulates formatting as the renderer traverses nested AST nodes. When entering a Strong node, bold is added; when entering Emphasis, italic is added; etc.
2. Style Propagation
When rendering nested emphasis nodes:
- The renderer starts with an empty
TextStyle - For each formatting node (Strong, Emphasis, Strikethrough), the corresponding flag is set
- The accumulated style is passed to child nodes
- When a
Textnode is reached, all accumulated styles are applied viastyle.apply(rich_text)
3. RichText Application
The TextStyle::apply() method chains egui's RichText styling methods:
fn apply(&self, mut text: RichText) -> RichText {
if self.bold { text = text.strong(); }
if self.italic { text = text.italics(); }
if self.strikethrough { text = text.strikethrough(); }
text
}
AST Structure Example
For ***bold italic***, comrak produces:
Paragraph
└── Strong
└── Emphasis
└── Text("bold italic")
Or alternatively (depending on marker order):
Paragraph
└── Emphasis
└── Strong
└── Text("bold italic")
Both structures render identically because the TextStyle accumulator collects all formatting regardless of nesting order.
Files Modified
-
src/markdown/editor.rs- Main WYSIWYG rendering logic- Added
TextStylestruct for style accumulation - Updated
render_inline_node()to propagate styles - Updated
render_styled_inline()for top-level emphasis nodes - Removed simple
render_strong()andrender_emphasis()functions
- Added
-
src/markdown/parser.rs- Added tests for nested emphasis parsing
Testing
Unit Tests Added
test_text_style_default- Default style has no formattingtest_text_style_with_bold- Bold flag workstest_text_style_with_italic- Italic flag workstest_text_style_with_strikethrough- Strikethrough flag workstest_text_style_bold_and_italic- Combined styles worktest_text_style_all_combined- All three styles combinedtest_text_style_chaining_order_independent- Order doesn't mattertest_text_style_apply_no_style- Apply with empty styletest_text_style_apply_with_styles- Apply with combined styles
Parser Tests Added
test_parse_bold_italic_triple_asterisk-***text***parsingtest_parse_bold_inside_italic-_**text**_parsingtest_parse_italic_inside_bold-**_text_**parsingtest_parse_mixed_emphasis_in_sentence- Multiple emphasis types in one paragraphtest_parse_underscore_emphasis- Underscore syntax variantstest_parse_strikethrough_with_bold- Combined strikethrough and bold
Limitations
- Inline code (
code) does not inherit text styles - it uses monospace font with code background - Links do not inherit text styles - they maintain their distinctive link appearance
- Very deep nesting (4+ levels) is technically supported but unusual in practice
Round-Trip Behavior
When switching between Raw and Rendered modes:
- The markdown source is preserved exactly as written
- Emphasis markers (
*,_,~) are not modified during editing - Visual styling in Rendered mode reflects the source accurately