phase 4: vimwiki parser + SyntaxPlugin glue
Hand-rolled recursive-descent parser over the token stream. Resilient per SPEC §6.7: never aborts the document — anything the dispatcher can't claim becomes BlockNode::Error and the cursor advances, and unterminated wikilinks / transclusions / delimiters fall back to literal text. Block coverage: every variant from §6.4 — Heading (with inline content between markers), Paragraph (with soft-break across single newlines), HorizontalRule, Blockquote (both `>` and 4-space styles), Preformatted, MathBlock, List (with checkbox + indent-driven sublists), DefinitionList, Table (header separator promotes the preceding row, plus colspan / rowspan cells), Comment (single + multiline), and page-level placeholders threaded into PageMetadata. Inline pairing: left-to-right scan with "find next matching delim", recursing on the slice between. `_*x*_` becomes Italic(Bold(...)), mirroring SPEC §6.7 precedence. URLs inside `[[ ]]` route to ExternalLinkNode; everything else to WikiLinkNode with full LinkTarget classification (Wiki / Interwiki numbered + named / Diary / File / Local / AnchorOnly / directory / root-relative / filesystem-absolute). VimwikiSyntax registers as id="vimwiki", extensions=[".wiki"] and chains lexer + parser inside SyntaxPlugin::parse. SPEC §4 updated to record the hand-rolled choice with rationale — span-bearing tokens fit awkwardly into winnow/nom combinator style; resilience and recovery are explicit in code instead. Tests (41 new parser cases) cover every AST construct, inline precedence including nested bold/italic, every LinkKind, transclusion alt + attrs, resilience on unterminated links, and end-to-end SyntaxRegistry dispatch. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,8 +1,40 @@
|
||||
//! Vimwiki syntax plugin.
|
||||
//!
|
||||
//! Phase 3 lands the lexer; the parser arrives in Phase 4 and the full
|
||||
//! `SyntaxPlugin` impl follows.
|
||||
|
||||
pub mod lexer;
|
||||
pub mod parser;
|
||||
|
||||
pub use lexer::{VimwikiLexer, VimwikiToken, VimwikiTokenKind};
|
||||
pub use parser::VimwikiParser;
|
||||
|
||||
use crate::ast::DocumentNode;
|
||||
use crate::syntax::{Lexer, Parser, SyntaxPlugin};
|
||||
|
||||
/// SyntaxPlugin facade: chains `VimwikiLexer` + `VimwikiParser` so the
|
||||
/// registry can hand out a single trait object per SPEC.md §6.3.
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub struct VimwikiSyntax;
|
||||
|
||||
impl VimwikiSyntax {
|
||||
pub fn new() -> Self {
|
||||
Self
|
||||
}
|
||||
}
|
||||
|
||||
impl SyntaxPlugin for VimwikiSyntax {
|
||||
fn id(&self) -> &str {
|
||||
"vimwiki"
|
||||
}
|
||||
|
||||
fn display_name(&self) -> &str {
|
||||
"Vimwiki"
|
||||
}
|
||||
|
||||
fn file_extensions(&self) -> &[&str] {
|
||||
&[".wiki"]
|
||||
}
|
||||
|
||||
fn parse(&self, text: &str) -> DocumentNode {
|
||||
let tokens = VimwikiLexer::new().lex(text);
|
||||
VimwikiParser::new().parse(tokens)
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user