feat(render): list_ignore_newline / text_ignore_newline = false → <br>
Implements the deferred half of these options: a soft line break inside a
paragraph / list item can render as <br /> instead of a space.
- Parser: soft breaks now emit a dedicated InlineNode::SoftBreak node
(parse_inline_seq K::Newline + the list-continuation synthetic join) instead
of collapsing to Text(" "). Added SoftBreakNode + the variant.
- All inline consumers treat SoftBreak as whitespace: AST visitor (no-op),
text extraction (index.rs + lib.rs → space), nav/semantic_tokens span_of_inline,
semantic emit (skip like Text), parser span_of_inline.
- Renderer: render_inlines_break renders top-level SoftBreaks as the
context-specific string; render_paragraph uses text_ignore_newline,
render_list_item uses list_ignore_newline; default render_inline → space.
with_newline_handling builder; export.rs wires both from HtmlConfig.
Default (true/true = upstream default) behaviour is unchanged (space). Updated
3 core tests + 1 parser test that asserted the old Text(" ") shape to treat
SoftBreak as whitespace. New test render_page_html_ignore_newline_controls_soft_breaks.
Gap doc: P3 Config item closed — only the deferred markdown cluster remains.
Full rust suite + clippy clean; Neovim 307, Vim 301/18/21.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -39,7 +39,7 @@ use crate::ast::{
|
||||
InlineNode, ItalicNode, KeywordNode, LinkKind, LinkTarget, ListItemNode, ListNode, ListSymbol,
|
||||
MathBlockNode, MathInlineNode, PageMetadata, ParagraphNode, PreformattedNode, RawUrlNode, Span,
|
||||
StrikethroughNode, SubscriptNode, SuperscriptNode, TableCellNode, TableNode, TableRowNode,
|
||||
TagNode, TagScope, TextNode, TransclusionNode, WikiLinkNode,
|
||||
SoftBreakNode, TagNode, TagScope, TextNode, TransclusionNode, WikiLinkNode,
|
||||
};
|
||||
use crate::syntax::{Parser, TokenStream};
|
||||
|
||||
@@ -596,14 +596,11 @@ impl<'a> ParseState<'a> {
|
||||
}
|
||||
}
|
||||
}
|
||||
// Insert a synthetic " " between the previous content and
|
||||
// the continuation so the rendered text flows naturally.
|
||||
// Insert a soft break between the previous content and the
|
||||
// continuation so the rendered text flows naturally (and honours
|
||||
// `*_ignore_newline`).
|
||||
if !children.is_empty() {
|
||||
let span = first.span;
|
||||
children.push(InlineNode::Text(TextNode {
|
||||
span,
|
||||
content: " ".into(),
|
||||
}));
|
||||
children.push(InlineNode::SoftBreak(SoftBreakNode { span: first.span }));
|
||||
}
|
||||
let cont = parse_inline_seq(&buf);
|
||||
children.extend(cont);
|
||||
@@ -1008,11 +1005,10 @@ fn parse_inline_seq(toks: &[VimwikiToken]) -> Vec<InlineNode> {
|
||||
i += 1;
|
||||
}
|
||||
K::Newline => {
|
||||
// Soft break inside a multi-line block: render as space.
|
||||
out.push(InlineNode::Text(TextNode {
|
||||
span: token.span,
|
||||
content: " ".into(),
|
||||
}));
|
||||
// Soft break inside a multi-line block. A dedicated node lets
|
||||
// the renderer honour `*_ignore_newline` (space vs `<br />`);
|
||||
// other consumers treat it as whitespace.
|
||||
out.push(InlineNode::SoftBreak(SoftBreakNode { span: token.span }));
|
||||
i += 1;
|
||||
}
|
||||
K::BoldDelim => {
|
||||
@@ -1454,5 +1450,6 @@ fn span_of_inline(node: &InlineNode) -> Span {
|
||||
InlineNode::ExternalLink(n) => n.span,
|
||||
InlineNode::Transclusion(n) => n.span,
|
||||
InlineNode::RawUrl(n) => n.span,
|
||||
InlineNode::SoftBreak(n) => n.span,
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user