This commit is contained in:
ef3d0c3e 2024-10-20 19:38:15 +02:00
parent 7f1229b5fe
commit d4c8e1c897
30 changed files with 552 additions and 177 deletions

View file

@ -7,6 +7,7 @@ use rusqlite::Connection;
use crate::document::document::Document; use crate::document::document::Document;
use crate::parser::langparser::LangParser; use crate::parser::langparser::LangParser;
use crate::parser::parser::ParseMode;
use crate::parser::parser::Parser; use crate::parser::parser::Parser;
use crate::parser::parser::ParserState; use crate::parser::parser::ParserState;
use crate::parser::source::Source; use crate::parser::source::Source;
@ -25,7 +26,7 @@ fn parse(
) -> Result<Box<dyn Document<'static>>, String> { ) -> Result<Box<dyn Document<'static>>, String> {
// Parse // Parse
//let source = SourceFile::new(input.to_string(), None).unwrap(); //let source = SourceFile::new(input.to_string(), None).unwrap();
let (doc, _) = parser.parse(ParserState::new(parser, None), source.clone(), None); let (doc, _) = parser.parse(ParserState::new(parser, None), source.clone(), None, ParseMode::default());
if debug_opts.contains(&"ast".to_string()) { if debug_opts.contains(&"ast".to_string()) {
println!("-- BEGIN AST DEBUGGING --"); println!("-- BEGIN AST DEBUGGING --");

View file

@ -43,9 +43,10 @@ pub mod tests {
use super::*; use super::*;
use crate::parser::langparser::LangParser; use crate::parser::langparser::LangParser;
use crate::parser::parser::ParseMode;
use crate::parser::parser::Parser; use crate::parser::parser::Parser;
use crate::parser::source::SourceFile;
use crate::parser::parser::ParserState; use crate::parser::parser::ParserState;
use crate::parser::source::SourceFile;
#[test] #[test]
fn validate_refname_tests() { fn validate_refname_tests() {
@ -55,7 +56,12 @@ pub mod tests {
None, None,
)); ));
let parser = LangParser::default(); let parser = LangParser::default();
let (doc, _) = parser.parse(ParserState::new(&parser, None), source, None); let (doc, _) = parser.parse(
ParserState::new(&parser, None),
source,
None,
ParseMode::default(),
);
assert_eq!(validate_refname(&*doc, " abc ", true), Ok("abc")); assert_eq!(validate_refname(&*doc, " abc ", true), Ok("abc"));
assert_eq!( assert_eq!(

View file

@ -1,5 +1,6 @@
use super::document::Document; use super::document::Document;
use crate::elements::text::Text; use crate::elements::text::Text;
use crate::parser::parser::ParseMode;
use crate::parser::parser::ParserState; use crate::parser::parser::ParserState;
use crate::parser::source::Source; use crate::parser::source::Source;
use crate::parser::source::Token; use crate::parser::source::Token;
@ -63,7 +64,7 @@ impl Variable for BaseVariable {
)); ));
state.with_state(|new_state| { state.with_state(|new_state| {
let _ = new_state.parser.parse_into(new_state, source, document); let _ = new_state.parser.parse_into(new_state, source, document, ParseMode::default());
}); });
} }
} }

View file

@ -25,6 +25,7 @@ use crate::document::element::ElemKind;
use crate::document::element::Element; use crate::document::element::Element;
use crate::elements::paragraph::Paragraph; use crate::elements::paragraph::Paragraph;
use crate::elements::text::Text; use crate::elements::text::Text;
use crate::parser::parser::ParseMode;
use crate::parser::parser::ParserState; use crate::parser::parser::ParserState;
use crate::parser::rule::Rule; use crate::parser::rule::Rule;
use crate::parser::source::Cursor; use crate::parser::source::Cursor;
@ -233,7 +234,15 @@ impl Rule for BlockquoteRule {
fn previous(&self) -> Option<&'static str> { Some("List") } fn previous(&self) -> Option<&'static str> { Some("List") }
fn next_match(&self, _state: &ParserState, cursor: &Cursor) -> Option<(usize, Box<dyn Any>)> { fn next_match(
&self,
mode: &ParseMode,
_state: &ParserState,
cursor: &Cursor,
) -> Option<(usize, Box<dyn Any>)> {
if mode.paragraph_only {
return None;
}
self.start_re self.start_re
.find_at(cursor.source.content(), cursor.pos) .find_at(cursor.source.content(), cursor.pos)
.map(|m| (m.start(), Box::new([false; 0]) as Box<dyn Any>)) .map(|m| (m.start(), Box::new([false; 0]) as Box<dyn Any>))
@ -310,7 +319,7 @@ impl Rule for BlockquoteRule {
let parsed_doc = state.with_state(|new_state| { let parsed_doc = state.with_state(|new_state| {
new_state new_state
.parser .parser
.parse(new_state, entry_src, Some(document)) .parse(new_state, entry_src, Some(document), ParseMode::default())
.0 .0
}); });
@ -447,7 +456,12 @@ END
None, None,
)); ));
let parser = LangParser::default(); let parser = LangParser::default();
let (doc, _) = parser.parse(ParserState::new(&parser, None), source, None); let (doc, _) = parser.parse(
ParserState::new(&parser, None),
source,
None,
ParseMode::default(),
);
validate_document!(doc.content().borrow(), 0, validate_document!(doc.content().borrow(), 0,
Paragraph { Text{ content == "BEFORE" }; }; Paragraph { Text{ content == "BEFORE" }; };
@ -496,7 +510,12 @@ AFTER
None, None,
)); ));
let parser = LangParser::default(); let parser = LangParser::default();
let (_, state) = parser.parse(ParserState::new(&parser, None), source, None); let (_, state) = parser.parse(
ParserState::new(&parser, None),
source,
None,
ParseMode::default(),
);
let style = state let style = state
.shared .shared

View file

@ -26,6 +26,7 @@ use crate::document::element::ElemKind;
use crate::document::element::Element; use crate::document::element::Element;
use crate::lsp::semantic::Semantics; use crate::lsp::semantic::Semantics;
use crate::lua::kernel::CTX; use crate::lua::kernel::CTX;
use crate::parser::parser::ParseMode;
use crate::parser::parser::ParserState; use crate::parser::parser::ParserState;
use crate::parser::rule::RegexRule; use crate::parser::rule::RegexRule;
use crate::parser::source::Source; use crate::parser::source::Source;
@ -309,8 +310,7 @@ impl CodeRule {
Regex::new( Regex::new(
r"``(?:\[((?:\\.|[^\\\\])*?)\])?(?:([^\r\n`]*?)(?:,|\n))?((?:\\(?:.|\n)|[^\\\\])*?)``", r"``(?:\[((?:\\.|[^\\\\])*?)\])?(?:([^\r\n`]*?)(?:,|\n))?((?:\\(?:.|\n)|[^\\\\])*?)``",
) )
.unwrap() .unwrap(),
], ],
properties: PropertyParser { properties: props }, properties: PropertyParser { properties: props },
} }
@ -319,10 +319,15 @@ impl CodeRule {
impl RegexRule for CodeRule { impl RegexRule for CodeRule {
fn name(&self) -> &'static str { "Code" } fn name(&self) -> &'static str { "Code" }
fn previous(&self) -> Option<&'static str> { Some("Blockquote") } fn previous(&self) -> Option<&'static str> { Some("Blockquote") }
fn regexes(&self) -> &[regex::Regex] { &self.re } fn regexes(&self) -> &[regex::Regex] { &self.re }
fn enabled(&self, mode: &ParseMode, id: usize) -> bool {
return !mode.paragraph_only || id != 0;
}
fn on_regex_match( fn on_regex_match(
&self, &self,
index: usize, index: usize,
@ -710,7 +715,12 @@ fn fact(n: usize) -> usize
None, None,
)); ));
let parser = LangParser::default(); let parser = LangParser::default();
let (doc, _) = parser.parse(ParserState::new(&parser, None), source, None); let (doc, _) = parser.parse(
ParserState::new(&parser, None),
source,
None,
ParseMode::default(),
);
let borrow = doc.content().borrow(); let borrow = doc.content().borrow();
let found = borrow let found = borrow
@ -756,7 +766,12 @@ fn fact(n: usize) -> usize
None, None,
)); ));
let parser = LangParser::default(); let parser = LangParser::default();
let (doc, _) = parser.parse(ParserState::new(&parser, None), source, None); let (doc, _) = parser.parse(
ParserState::new(&parser, None),
source,
None,
ParseMode::default(),
);
let borrow = doc.content().borrow(); let borrow = doc.content().borrow();
let found = borrow let found = borrow
@ -806,6 +821,7 @@ test code
ParserState::new_with_semantics(&parser, None), ParserState::new_with_semantics(&parser, None),
source.clone(), source.clone(),
None, None,
ParseMode::default(),
); );
validate_semantics!(state, source.clone(), 0, validate_semantics!(state, source.clone(), 0,
code_sep { delta_line == 1, delta_start == 0, length == 3 }; code_sep { delta_line == 1, delta_start == 0, length == 3 };

View file

@ -3,6 +3,7 @@ use crate::document::document::Document;
use crate::document::element::ElemKind; use crate::document::element::ElemKind;
use crate::document::element::Element; use crate::document::element::Element;
use crate::lsp::semantic::Semantics; use crate::lsp::semantic::Semantics;
use crate::parser::parser::ParseMode;
use crate::parser::parser::ParserState; use crate::parser::parser::ParserState;
use crate::parser::rule::RegexRule; use crate::parser::rule::RegexRule;
use crate::parser::source::Source; use crate::parser::source::Source;
@ -56,6 +57,8 @@ impl RegexRule for CommentRule {
fn regexes(&self) -> &[Regex] { &self.re } fn regexes(&self) -> &[Regex] { &self.re }
fn enabled(&self, _mode: &ParseMode, _id: usize) -> bool { true }
fn on_regex_match( fn on_regex_match(
&self, &self,
_: usize, _: usize,
@ -132,7 +135,12 @@ COMMENT ::Test
None, None,
)); ));
let parser = LangParser::default(); let parser = LangParser::default();
let (doc, _) = parser.parse(ParserState::new(&parser, None), source, None); let (doc, _) = parser.parse(
ParserState::new(&parser, None),
source,
None,
ParseMode::default(),
);
validate_document!(doc.content().borrow(), 0, validate_document!(doc.content().borrow(), 0,
Paragraph { Paragraph {
@ -160,6 +168,7 @@ COMMENT ::Test
ParserState::new_with_semantics(&parser, None), ParserState::new_with_semantics(&parser, None),
source.clone(), source.clone(),
None, None,
ParseMode::default(),
); );
validate_semantics!(state, source.clone(), 0, validate_semantics!(state, source.clone(), 0,

View file

@ -1,4 +1,5 @@
use crate::lua::kernel::Kernel; use crate::lua::kernel::Kernel;
use crate::parser::parser::ParseMode;
use std::any::Any; use std::any::Any;
use std::cell::Ref; use std::cell::Ref;
use std::cell::RefCell; use std::cell::RefCell;
@ -140,10 +141,13 @@ impl RuleState for CustomStyleState {
let paragraph = document.last_element::<Paragraph>().unwrap(); let paragraph = document.last_element::<Paragraph>().unwrap();
let paragraph_end = paragraph let paragraph_end = paragraph
.content .content
.last().map(|last| ( .last()
.map(|last| {
(
last.location().source(), last.location().source(),
last.location().end() - 1..last.location().end(), last.location().end() - 1..last.location().end(),
)) )
})
.unwrap(); .unwrap();
reports.push( reports.push(
@ -179,14 +183,20 @@ static STATE_NAME: &str = "elements.custom_style";
pub struct CustomStyleRule; pub struct CustomStyleRule;
impl CustomStyleRule { impl CustomStyleRule {
pub fn new() -> Self { Self{} } pub fn new() -> Self { Self {} }
} }
impl Rule for CustomStyleRule { impl Rule for CustomStyleRule {
fn name(&self) -> &'static str { "Custom Style" } fn name(&self) -> &'static str { "Custom Style" }
fn previous(&self) -> Option<&'static str> { Some("Style") } fn previous(&self) -> Option<&'static str> { Some("Style") }
fn next_match(&self, state: &ParserState, cursor: &Cursor) -> Option<(usize, Box<dyn Any>)> { fn next_match(
&self,
_mode: &ParseMode,
state: &ParserState,
cursor: &Cursor,
) -> Option<(usize, Box<dyn Any>)> {
let content = cursor.source.content(); let content = cursor.source.content();
let mut closest_match = usize::MAX; let mut closest_match = usize::MAX;
@ -479,6 +489,7 @@ mod tests {
use crate::elements::raw::Raw; use crate::elements::raw::Raw;
use crate::elements::text::Text; use crate::elements::text::Text;
use crate::parser::langparser::LangParser; use crate::parser::langparser::LangParser;
use crate::parser::parser::ParseMode;
use crate::parser::parser::Parser; use crate::parser::parser::Parser;
use crate::parser::source::SourceFile; use crate::parser::source::SourceFile;
use crate::validate_document; use crate::validate_document;
@ -512,7 +523,12 @@ pre |styled| post °Hello°.
None, None,
)); ));
let parser = LangParser::default(); let parser = LangParser::default();
let (doc, _) = parser.parse(ParserState::new(&parser, None), source, None); let (doc, _) = parser.parse(
ParserState::new(&parser, None),
source,
None,
ParseMode::default(),
);
validate_document!(doc.content().borrow(), 0, validate_document!(doc.content().borrow(), 0,
Paragraph { Paragraph {
@ -556,7 +572,12 @@ pre [styled] post (Hello).
None, None,
)); ));
let parser = LangParser::default(); let parser = LangParser::default();
let (doc, _) = parser.parse(ParserState::new(&parser, None), source, None); let (doc, _) = parser.parse(
ParserState::new(&parser, None),
source,
None,
ParseMode::default(),
);
validate_document!(doc.content().borrow(), 0, validate_document!(doc.content().borrow(), 0,
Paragraph { Paragraph {

View file

@ -1,3 +1,4 @@
use crate::parser::parser::ParseMode;
use crate::parser::style::ElementStyle; use crate::parser::style::ElementStyle;
use std::any::Any; use std::any::Any;
use std::ops::Range; use std::ops::Range;
@ -59,11 +60,18 @@ impl ElemStyleRule {
impl Rule for ElemStyleRule { impl Rule for ElemStyleRule {
fn name(&self) -> &'static str { "Element Style" } fn name(&self) -> &'static str { "Element Style" }
fn previous(&self) -> Option<&'static str> { Some("Script") } fn previous(&self) -> Option<&'static str> { Some("Script") }
fn next_match(&self, _state: &ParserState, cursor: &Cursor) -> Option<(usize, Box<dyn Any>)> { fn next_match(
&self,
_mode: &ParseMode,
_state: &ParserState,
cursor: &Cursor,
) -> Option<(usize, Box<dyn Any>)> {
self.start_re self.start_re
.find_at(cursor.source.content(), cursor.pos).map(|m| (m.start(), Box::new([false; 0]) as Box<dyn Any>)) .find_at(cursor.source.content(), cursor.pos)
.map(|m| (m.start(), Box::new([false; 0]) as Box<dyn Any>))
} }
fn on_match<'a>( fn on_match<'a>(
@ -132,7 +140,9 @@ impl Rule for ElemStyleRule {
.with_message("Invalid Style Value") .with_message("Invalid Style Value")
.with_label( .with_label(
Label::new((cursor.source.clone(), matches.get(0).unwrap().range())) Label::new((cursor.source.clone(), matches.get(0).unwrap().range()))
.with_message("Unable to parse json string after style key".to_string()) .with_message(
"Unable to parse json string after style key".to_string(),
)
.with_color(state.parser.colors().error), .with_color(state.parser.colors().error),
) )
.finish(), .finish(),

View file

@ -5,6 +5,7 @@ use std::sync::Arc;
use std::sync::Once; use std::sync::Once;
use crate::lua::kernel::CTX; use crate::lua::kernel::CTX;
use crate::parser::parser::ParseMode;
use crate::parser::parser::ParserState; use crate::parser::parser::ParserState;
use crate::parser::util::Property; use crate::parser::util::Property;
use crate::parser::util::PropertyMapError; use crate::parser::util::PropertyMapError;
@ -189,10 +190,13 @@ impl GraphRule {
impl RegexRule for GraphRule { impl RegexRule for GraphRule {
fn name(&self) -> &'static str { "Graphviz" } fn name(&self) -> &'static str { "Graphviz" }
fn previous(&self) -> Option<&'static str> { Some("Tex") } fn previous(&self) -> Option<&'static str> { Some("Tex") }
fn regexes(&self) -> &[regex::Regex] { &self.re } fn regexes(&self) -> &[regex::Regex] { &self.re }
fn enabled(&self, mode: &ParseMode, _id: usize) -> bool { !mode.paragraph_only }
fn on_regex_match( fn on_regex_match(
&self, &self,
_: usize, _: usize,
@ -441,7 +445,12 @@ Another graph
None, None,
)); ));
let parser = LangParser::default(); let parser = LangParser::default();
let (doc, _) = parser.parse(ParserState::new(&parser, None), source, None); let (doc, _) = parser.parse(
ParserState::new(&parser, None),
source,
None,
ParseMode::default(),
);
validate_document!(doc.content().borrow(), 0, validate_document!(doc.content().borrow(), 0,
Graphviz { width == "200px", dot == "Some graph..." }; Graphviz { width == "200px", dot == "Some graph..." };
@ -461,7 +470,12 @@ Another graph
None, None,
)); ));
let parser = LangParser::default(); let parser = LangParser::default();
let (doc, _) = parser.parse(ParserState::new(&parser, None), source, None); let (doc, _) = parser.parse(
ParserState::new(&parser, None),
source,
None,
ParseMode::default(),
);
validate_document!(doc.content().borrow(), 0, validate_document!(doc.content().borrow(), 0,
Graphviz { width == "200px", dot == "Some graph..." }; Graphviz { width == "200px", dot == "Some graph..." };

View file

@ -1,6 +1,7 @@
use crate::document::document::Document; use crate::document::document::Document;
use crate::document::document::DocumentAccessors; use crate::document::document::DocumentAccessors;
use crate::lsp::semantic::Semantics; use crate::lsp::semantic::Semantics;
use crate::parser::parser::ParseMode;
use crate::parser::parser::ParserState; use crate::parser::parser::ParserState;
use crate::parser::parser::ReportColors; use crate::parser::parser::ReportColors;
use crate::parser::rule::RegexRule; use crate::parser::rule::RegexRule;
@ -43,10 +44,13 @@ impl ImportRule {
impl RegexRule for ImportRule { impl RegexRule for ImportRule {
fn name(&self) -> &'static str { "Import" } fn name(&self) -> &'static str { "Import" }
fn previous(&self) -> Option<&'static str> { Some("Paragraph") } fn previous(&self) -> Option<&'static str> { Some("Paragraph") }
fn regexes(&self) -> &[Regex] { &self.re } fn regexes(&self) -> &[Regex] { &self.re }
fn enabled(&self, mode: &ParseMode, _id: usize) -> bool { !mode.paragraph_only }
fn on_regex_match<'a>( fn on_regex_match<'a>(
&self, &self,
_: usize, _: usize,
@ -165,7 +169,10 @@ impl RegexRule for ImportRule {
}; };
state.with_state(|new_state| { state.with_state(|new_state| {
let (import_doc, _) = new_state.parser.parse(new_state, import, Some(document)); let (import_doc, _) =
new_state
.parser
.parse(new_state, import, Some(document), ParseMode::default());
document.merge(import_doc.content(), import_doc.scope(), Some(&import_as)); document.merge(import_doc.content(), import_doc.scope(), Some(&import_as));
}); });
@ -181,25 +188,25 @@ impl RegexRule for ImportRule {
); );
} }
if let Some((sems, tokens)) =
if let Some((sems, tokens)) = Semantics::from_source(token.source(), &state.shared.semantics) Semantics::from_source(token.source(), &state.shared.semantics)
{ {
// @import // @import
let import = if token.source().content().as_bytes()[matches.get(0).unwrap().start()] == b'\n' let import =
{ if token.source().content().as_bytes()[matches.get(0).unwrap().start()] == b'\n' {
matches.get(0).unwrap().start() + 1 matches.get(0).unwrap().start() + 1
} } else {
else matches.get(0).unwrap().start()
{ };
matches.get(0).unwrap().start()
};
sems.add(import..import + 7, tokens.import_import); sems.add(import..import + 7, tokens.import_import);
if let Some(import_as) = matches.get(1) if let Some(import_as) = matches.get(1) {
{ sems.add(
sems.add(import_as.start()-1..import_as.start(), tokens.import_as_sep); import_as.start() - 1..import_as.start(),
tokens.import_as_sep,
);
sems.add(import_as.range(), tokens.import_as); sems.add(import_as.range(), tokens.import_as);
sems.add(import_as.end()..import_as.end()+1, tokens.import_as_sep); sems.add(import_as.end()..import_as.end() + 1, tokens.import_as_sep);
} }
let path = matches.get(2).unwrap().range(); let path = matches.get(2).unwrap().range();

View file

@ -6,6 +6,7 @@ use crate::document::element::Element;
use crate::lua::kernel::CTX; use crate::lua::kernel::CTX;
use crate::parser::layout::LayoutHolder; use crate::parser::layout::LayoutHolder;
use crate::parser::layout::LayoutType; use crate::parser::layout::LayoutType;
use crate::parser::parser::ParseMode;
use crate::parser::parser::ParserState; use crate::parser::parser::ParserState;
use crate::parser::parser::ReportColors; use crate::parser::parser::ReportColors;
use crate::parser::rule::RegexRule; use crate::parser::rule::RegexRule;
@ -232,7 +233,12 @@ impl Element for Layout {
fn location(&self) -> &Token { &self.location } fn location(&self) -> &Token { &self.location }
fn kind(&self) -> ElemKind { ElemKind::Block } fn kind(&self) -> ElemKind { ElemKind::Block }
fn element_name(&self) -> &'static str { "Layout" } fn element_name(&self) -> &'static str { "Layout" }
fn compile(&self, compiler: &Compiler, document: &dyn Document, _cursor: usize) -> Result<String, String> { fn compile(
&self,
compiler: &Compiler,
document: &dyn Document,
_cursor: usize,
) -> Result<String, String> {
self.layout self.layout
.compile(self.token, self.id, &self.properties, compiler, document) .compile(self.token, self.id, &self.properties, compiler, document)
} }
@ -379,10 +385,13 @@ static STATE_NAME: &str = "elements.layout";
impl RegexRule for LayoutRule { impl RegexRule for LayoutRule {
fn name(&self) -> &'static str { "Layout" } fn name(&self) -> &'static str { "Layout" }
fn previous(&self) -> Option<&'static str> { Some("Media") } fn previous(&self) -> Option<&'static str> { Some("Media") }
fn regexes(&self) -> &[regex::Regex] { &self.re } fn regexes(&self) -> &[regex::Regex] { &self.re }
fn enabled(&self, mode: &ParseMode, _id: usize) -> bool { !mode.paragraph_only }
fn on_regex_match( fn on_regex_match(
&self, &self,
index: usize, index: usize,
@ -897,7 +906,12 @@ mod tests {
None, None,
)); ));
let parser = LangParser::default(); let parser = LangParser::default();
let (doc, _) = parser.parse(ParserState::new(&parser, None), source, None); let (doc, _) = parser.parse(
ParserState::new(&parser, None),
source,
None,
ParseMode::default(),
);
validate_document!(doc.content().borrow(), 0, validate_document!(doc.content().borrow(), 0,
Layout { token == LayoutToken::Begin, id == 0 }; Layout { token == LayoutToken::Begin, id == 0 };
@ -949,7 +963,12 @@ mod tests {
None, None,
)); ));
let parser = LangParser::default(); let parser = LangParser::default();
let (doc, _) = parser.parse(ParserState::new(&parser, None), source, None); let (doc, _) = parser.parse(
ParserState::new(&parser, None),
source,
None,
ParseMode::default(),
);
validate_document!(doc.content().borrow(), 0, validate_document!(doc.content().borrow(), 0,
Layout { token == LayoutToken::Begin, id == 0 }; Layout { token == LayoutToken::Begin, id == 0 };

View file

@ -6,6 +6,7 @@ use crate::document::element::ElemKind;
use crate::document::element::Element; use crate::document::element::Element;
use crate::lsp::semantic::Semantics; use crate::lsp::semantic::Semantics;
use crate::lua::kernel::CTX; use crate::lua::kernel::CTX;
use crate::parser::parser::ParseMode;
use crate::parser::parser::ParserState; use crate::parser::parser::ParserState;
use crate::parser::rule::RegexRule; use crate::parser::rule::RegexRule;
use crate::parser::source::Source; use crate::parser::source::Source;
@ -94,10 +95,13 @@ impl LinkRule {
impl RegexRule for LinkRule { impl RegexRule for LinkRule {
fn name(&self) -> &'static str { "Link" } fn name(&self) -> &'static str { "Link" }
fn previous(&self) -> Option<&'static str> { Some("Link") } fn previous(&self) -> Option<&'static str> { Some("Link") }
fn regexes(&self) -> &[Regex] { &self.re } fn regexes(&self) -> &[Regex] { &self.re }
fn enabled(&self, _mode: &ParseMode, _id: usize) -> bool { true }
fn on_regex_match<'a>( fn on_regex_match<'a>(
&self, &self,
_: usize, _: usize,
@ -314,7 +318,12 @@ Some [link](url).
None, None,
)); ));
let parser = LangParser::default(); let parser = LangParser::default();
let (doc, _) = parser.parse(ParserState::new(&parser, None), source, None); let (doc, _) = parser.parse(
ParserState::new(&parser, None),
source,
None,
ParseMode::default(),
);
validate_document!(doc.content().borrow(), 0, validate_document!(doc.content().borrow(), 0,
Paragraph { Paragraph {
@ -344,7 +353,12 @@ nml.link.push("**BOLD link**", "another url")
None, None,
)); ));
let parser = LangParser::default(); let parser = LangParser::default();
let (doc, _) = parser.parse(ParserState::new(&parser, None), source, None); let (doc, _) = parser.parse(
ParserState::new(&parser, None),
source,
None,
ParseMode::default(),
);
validate_document!(doc.content().borrow(), 0, validate_document!(doc.content().borrow(), 0,
Paragraph { Paragraph {
@ -375,6 +389,7 @@ nml.link.push("**BOLD link**", "another url")
ParserState::new_with_semantics(&parser, None), ParserState::new_with_semantics(&parser, None),
source.clone(), source.clone(),
None, None,
ParseMode::default(),
); );
validate_semantics!(state, source.clone(), 0, validate_semantics!(state, source.clone(), 0,

View file

@ -12,6 +12,7 @@ use crate::document::element::ContainerElement;
use crate::document::element::ElemKind; use crate::document::element::ElemKind;
use crate::document::element::Element; use crate::document::element::Element;
use crate::lsp::semantic::Semantics; use crate::lsp::semantic::Semantics;
use crate::parser::parser::ParseMode;
use crate::parser::parser::ParserState; use crate::parser::parser::ParserState;
use crate::parser::rule::Rule; use crate::parser::rule::Rule;
use crate::parser::source::Cursor; use crate::parser::source::Cursor;
@ -269,9 +270,18 @@ impl ListRule {
impl Rule for ListRule { impl Rule for ListRule {
fn name(&self) -> &'static str { "List" } fn name(&self) -> &'static str { "List" }
fn previous(&self) -> Option<&'static str> { Some("Raw") } fn previous(&self) -> Option<&'static str> { Some("Raw") }
fn next_match(&self, _state: &ParserState, cursor: &Cursor) -> Option<(usize, Box<dyn Any>)> { fn next_match(
&self,
mode: &ParseMode,
_state: &ParserState,
cursor: &Cursor,
) -> Option<(usize, Box<dyn Any>)> {
if mode.paragraph_only {
return None;
}
self.start_re self.start_re
.find_at(cursor.source.content(), cursor.pos) .find_at(cursor.source.content(), cursor.pos)
.map(|m| (m.start(), Box::new([false; 0]) as Box<dyn Any>)) .map(|m| (m.start(), Box::new([false; 0]) as Box<dyn Any>))
@ -406,6 +416,7 @@ impl Rule for ListRule {
// Parse entry content // Parse entry content
let token = Token::new(entry_start..end_cursor.pos, end_cursor.source.clone()); let token = Token::new(entry_start..end_cursor.pos, end_cursor.source.clone());
//println!("content={}", entry_content);
let entry_src = Rc::new(VirtualSource::new( let entry_src = Rc::new(VirtualSource::new(
token.clone(), token.clone(),
"List Entry".to_string(), "List Entry".to_string(),
@ -475,7 +486,8 @@ mod tests {
use crate::parser::langparser::LangParser; use crate::parser::langparser::LangParser;
use crate::parser::parser::Parser; use crate::parser::parser::Parser;
use crate::parser::source::SourceFile; use crate::parser::source::SourceFile;
use crate::{validate_document, validate_semantics}; use crate::validate_document;
use crate::validate_semantics;
#[test] #[test]
fn parser() { fn parser() {
@ -498,7 +510,7 @@ mod tests {
)); ));
let parser = LangParser::default(); let parser = LangParser::default();
let state = ParserState::new(&parser, None); let state = ParserState::new(&parser, None);
let (doc, _) = parser.parse(state, source, None); let (doc, _) = parser.parse(state, source, None, ParseMode::default());
validate_document!(doc.content().borrow(), 0, validate_document!(doc.content().borrow(), 0,
ListMarker { numbered == false, kind == MarkerKind::Open }; ListMarker { numbered == false, kind == MarkerKind::Open };
@ -549,7 +561,8 @@ mod tests {
*[offset=5] First **bold** *[offset=5] First **bold**
Second line Second line
*- Another *- Another
>@
"# "#
.to_string(), .to_string(),
None, None,
@ -559,6 +572,7 @@ mod tests {
ParserState::new_with_semantics(&parser, None), ParserState::new_with_semantics(&parser, None),
source.clone(), source.clone(),
None, None,
ParseMode::default(),
); );
validate_semantics!(state, source.clone(), 0, validate_semantics!(state, source.clone(), 0,
list_bullet { delta_line == 1, delta_start == 1, length == 1 }; list_bullet { delta_line == 1, delta_start == 1, length == 1 };

View file

@ -21,6 +21,7 @@ use crate::document::element::ElemKind;
use crate::document::element::Element; use crate::document::element::Element;
use crate::document::element::ReferenceableElement; use crate::document::element::ReferenceableElement;
use crate::document::references::validate_refname; use crate::document::references::validate_refname;
use crate::parser::parser::ParseMode;
use crate::parser::parser::ParserState; use crate::parser::parser::ParserState;
use crate::parser::parser::ReportColors; use crate::parser::parser::ReportColors;
use crate::parser::rule::RegexRule; use crate::parser::rule::RegexRule;
@ -72,14 +73,21 @@ impl Element for Media {
fn as_container(&self) -> Option<&dyn ContainerElement> { Some(self) } fn as_container(&self) -> Option<&dyn ContainerElement> { Some(self) }
fn compile(&self, compiler: &Compiler, document: &dyn Document, cursor: usize) -> Result<String, String> { fn compile(
&self,
compiler: &Compiler,
document: &dyn Document,
cursor: usize,
) -> Result<String, String> {
match compiler.target() { match compiler.target() {
Target::HTML => { Target::HTML => {
let mut result = String::new(); let mut result = String::new();
result.push_str("<div class=\"media\">"); result.push_str("<div class=\"media\">");
for medium in &self.media { for medium in &self.media {
result += medium.compile(compiler, document, cursor+result.len())?.as_str(); result += medium
.compile(compiler, document, cursor + result.len())?
.as_str();
} }
result.push_str("</div>"); result.push_str("</div>");
@ -132,7 +140,12 @@ impl Element for Medium {
fn as_referenceable(&self) -> Option<&dyn ReferenceableElement> { Some(self) } fn as_referenceable(&self) -> Option<&dyn ReferenceableElement> { Some(self) }
fn compile(&self, compiler: &Compiler, document: &dyn Document, cursor: usize) -> Result<String, String> { fn compile(
&self,
compiler: &Compiler,
document: &dyn Document,
cursor: usize,
) -> Result<String, String> {
match compiler.target() { match compiler.target() {
Target::HTML => { Target::HTML => {
let mut result = String::new(); let mut result = String::new();
@ -145,10 +158,18 @@ impl Element for Medium {
.width .width
.as_ref() .as_ref()
.map_or(String::new(), |w| format!(r#" style="width:{w};""#)); .map_or(String::new(), |w| format!(r#" style="width:{w};""#));
result.push_str(format!(r#"<div id="{}" class="medium"{width}>"#, self.refid(compiler, refcount)).as_str()); result.push_str(
format!(
r#"<div id="{}" class="medium"{width}>"#,
self.refid(compiler, refcount)
)
.as_str(),
);
result += match self.media_type { result += match self.media_type {
MediaType::IMAGE => format!(r#"<a href="{0}"><img src="{0}"></a>"#, self.uri), MediaType::IMAGE => format!(r#"<a href="{0}"><img src="{0}"></a>"#, self.uri),
MediaType::VIDEO => format!(r#"<video controls{width}><source src="{0}"></video>"#, self.uri MediaType::VIDEO => format!(
r#"<video controls{width}><source src="{0}"></video>"#,
self.uri
), ),
MediaType::AUDIO => { MediaType::AUDIO => {
format!(r#"<audio controls src="{0}"{width}></audio>"#, self.uri) format!(r#"<audio controls src="{0}"{width}></audio>"#, self.uri)
@ -158,17 +179,17 @@ impl Element for Medium {
let caption = self let caption = self
.caption .caption
.as_ref().map(|cap| format!( .as_ref()
" {}", .map(|cap| format!(" {}", Compiler::sanitize(compiler.target(), cap.as_str())))
Compiler::sanitize(compiler.target(), cap.as_str())
))
.unwrap_or_default(); .unwrap_or_default();
result.push_str( result.push_str(
format!(r#"<p class="medium-refname">({refcount}){caption}</p>"#).as_str(), format!(r#"<p class="medium-refname">({refcount}){caption}</p>"#).as_str(),
); );
if let Some(paragraph) = self.description.as_ref() { if let Some(paragraph) = self.description.as_ref() {
result += paragraph.compile(compiler, document, cursor+result.len())?.as_str(); result += paragraph
.compile(compiler, document, cursor + result.len())?
.as_str();
} }
result.push_str("</div>"); result.push_str("</div>");
@ -214,9 +235,7 @@ impl ReferenceableElement for Medium {
} }
} }
fn refid(&self, _compiler: &Compiler, refid: usize) -> String { fn refid(&self, _compiler: &Compiler, refid: usize) -> String { format!("medium-{refid}") }
format!("medium-{refid}")
}
} }
#[auto_registry::auto_registry(registry = "rules", path = "crate::elements::media")] #[auto_registry::auto_registry(registry = "rules", path = "crate::elements::media")]
@ -324,10 +343,13 @@ impl MediaRule {
impl RegexRule for MediaRule { impl RegexRule for MediaRule {
fn name(&self) -> &'static str { "Media" } fn name(&self) -> &'static str { "Media" }
fn previous(&self) -> Option<&'static str> { Some("Graphviz") } fn previous(&self) -> Option<&'static str> { Some("Graphviz") }
fn regexes(&self) -> &[regex::Regex] { &self.re } fn regexes(&self) -> &[regex::Regex] { &self.re }
fn enabled(&self, mode: &ParseMode, _id: usize) -> bool { !mode.paragraph_only }
fn on_regex_match<'a>( fn on_regex_match<'a>(
&self, &self,
_: usize, _: usize,
@ -433,13 +455,15 @@ impl RegexRule for MediaRule {
.get("width", |_, value| -> Result<String, ()> { .get("width", |_, value| -> Result<String, ()> {
Ok(value.clone()) Ok(value.clone())
}) })
.ok().map(|(_, s)| s); .ok()
.map(|(_, s)| s);
let caption = properties let caption = properties
.get("caption", |_, value| -> Result<String, ()> { .get("caption", |_, value| -> Result<String, ()> {
Ok(value.clone()) Ok(value.clone())
}) })
.ok().map(|(_, value)| value); .ok()
.map(|(_, value)| value);
let description = match matches.get(4) { let description = match matches.get(4) {
Some(content) => { Some(content) => {
@ -546,7 +570,12 @@ mod tests {
None, None,
)); ));
let parser = LangParser::default(); let parser = LangParser::default();
let (doc, _) = parser.parse(ParserState::new(&parser, None), source, None); let (doc, _) = parser.parse(
ParserState::new(&parser, None),
source,
None,
ParseMode::default(),
);
let borrow = doc.content().borrow(); let borrow = doc.content().borrow();
let group = borrow.first().as_ref().unwrap().as_container().unwrap(); let group = borrow.first().as_ref().unwrap().as_container().unwrap();

View file

@ -11,6 +11,7 @@ use crate::document::document::Document;
use crate::document::element::ContainerElement; use crate::document::element::ContainerElement;
use crate::document::element::ElemKind; use crate::document::element::ElemKind;
use crate::document::element::Element; use crate::document::element::Element;
use crate::parser::parser::ParseMode;
use crate::parser::parser::ParserState; use crate::parser::parser::ParserState;
use crate::parser::rule::Rule; use crate::parser::rule::Rule;
use crate::parser::source::Cursor; use crate::parser::source::Cursor;
@ -48,7 +49,12 @@ impl Element for Paragraph {
fn element_name(&self) -> &'static str { "Paragraph" } fn element_name(&self) -> &'static str { "Paragraph" }
fn compile(&self, compiler: &Compiler, document: &dyn Document, cursor: usize) -> Result<String, String> { fn compile(
&self,
compiler: &Compiler,
document: &dyn Document,
cursor: usize,
) -> Result<String, String> {
if self.content.is_empty() { if self.content.is_empty() {
return Ok(String::new()); return Ok(String::new());
} }
@ -63,7 +69,9 @@ impl Element for Paragraph {
result.push_str("<p>"); result.push_str("<p>");
for elems in &self.content { for elems in &self.content {
result += elems.compile(compiler, document, cursor+result.len())?.as_str(); result += elems
.compile(compiler, document, cursor + result.len())?
.as_str();
} }
result.push_str("</p>"); result.push_str("</p>");
@ -106,11 +114,18 @@ impl ParagraphRule {
impl Rule for ParagraphRule { impl Rule for ParagraphRule {
fn name(&self) -> &'static str { "Paragraph" } fn name(&self) -> &'static str { "Paragraph" }
fn previous(&self) -> Option<&'static str> { Some("Comment") } fn previous(&self) -> Option<&'static str> { Some("Comment") }
fn next_match(&self, _state: &ParserState, cursor: &Cursor) -> Option<(usize, Box<dyn Any>)> { fn next_match(
&self,
_mode: &ParseMode,
_state: &ParserState,
cursor: &Cursor,
) -> Option<(usize, Box<dyn Any>)> {
self.re self.re
.find_at(cursor.source.content(), cursor.pos).map(|m| (m.start(), Box::new([false; 0]) as Box<dyn Any>)) .find_at(cursor.source.content(), cursor.pos)
.map(|m| (m.start(), Box::new([false; 0]) as Box<dyn Any>))
} }
fn on_match( fn on_match(
@ -166,7 +181,12 @@ Last paragraph
None, None,
)); ));
let parser = LangParser::default(); let parser = LangParser::default();
let (doc, _) = parser.parse(ParserState::new(&parser, None), source, None); let (doc, _) = parser.parse(
ParserState::new(&parser, None),
source,
None,
ParseMode::default(),
);
validate_document!(doc.content().borrow(), 0, validate_document!(doc.content().borrow(), 0,
Paragraph { Paragraph {

View file

@ -3,6 +3,7 @@ use crate::document::document::Document;
use crate::document::element::ElemKind; use crate::document::element::ElemKind;
use crate::document::element::Element; use crate::document::element::Element;
use crate::lua::kernel::CTX; use crate::lua::kernel::CTX;
use crate::parser::parser::ParseMode;
use crate::parser::parser::ParserState; use crate::parser::parser::ParserState;
use crate::parser::rule::RegexRule; use crate::parser::rule::RegexRule;
use crate::parser::source::Source; use crate::parser::source::Source;
@ -39,7 +40,12 @@ impl Element for Raw {
fn element_name(&self) -> &'static str { "Raw" } fn element_name(&self) -> &'static str { "Raw" }
fn compile(&self, _compiler: &Compiler, _document: &dyn Document, _cursor: usize) -> Result<String, String> { fn compile(
&self,
_compiler: &Compiler,
_document: &dyn Document,
_cursor: usize,
) -> Result<String, String> {
Ok(self.content.clone()) Ok(self.content.clone())
} }
} }
@ -73,10 +79,13 @@ impl RawRule {
impl RegexRule for RawRule { impl RegexRule for RawRule {
fn name(&self) -> &'static str { "Raw" } fn name(&self) -> &'static str { "Raw" }
fn previous(&self) -> Option<&'static str> { Some("Variable Substitution") } fn previous(&self) -> Option<&'static str> { Some("Variable Substitution") }
fn regexes(&self) -> &[regex::Regex] { &self.re } fn regexes(&self) -> &[regex::Regex] { &self.re }
fn enabled(&self, _mode: &ParseMode, _id: usize) -> bool { true }
fn on_regex_match( fn on_regex_match(
&self, &self,
_index: usize, _index: usize,
@ -271,7 +280,7 @@ mod tests {
use crate::elements::text::Text; use crate::elements::text::Text;
use crate::parser::langparser::LangParser; use crate::parser::langparser::LangParser;
use crate::parser::parser::Parser; use crate::parser::parser::Parser;
use crate::parser::source::SourceFile; use crate::parser::source::SourceFile;
use crate::validate_document; use crate::validate_document;
#[test] #[test]
@ -285,7 +294,12 @@ Break{?[kind=block] Raw?}NewParagraph{?<b>?}
None, None,
)); ));
let parser = LangParser::default(); let parser = LangParser::default();
let (doc, _) = parser.parse(ParserState::new(&parser, None), source, None); let (doc, _) = parser.parse(
ParserState::new(&parser, None),
source,
None,
ParseMode::default(),
);
validate_document!(doc.content().borrow(), 0, validate_document!(doc.content().borrow(), 0,
Paragraph; Paragraph;
@ -308,7 +322,12 @@ Break%<nml.raw.push("block", "Raw")>%NewParagraph%<nml.raw.push("inline", "<b>")
None, None,
)); ));
let parser = LangParser::default(); let parser = LangParser::default();
let (doc, _) = parser.parse(ParserState::new(&parser, None), source, None); let (doc, _) = parser.parse(
ParserState::new(&parser, None),
source,
None,
ParseMode::default(),
);
validate_document!(doc.content().borrow(), 0, validate_document!(doc.content().borrow(), 0,
Paragraph; Paragraph;

View file

@ -22,6 +22,7 @@ use crate::document::element::ElemKind;
use crate::document::element::Element; use crate::document::element::Element;
use crate::document::references::validate_refname; use crate::document::references::validate_refname;
use crate::lsp::semantic::Semantics; use crate::lsp::semantic::Semantics;
use crate::parser::parser::ParseMode;
use crate::parser::parser::ParserState; use crate::parser::parser::ParserState;
use crate::parser::parser::ReportColors; use crate::parser::parser::ReportColors;
use crate::parser::rule::RegexRule; use crate::parser::rule::RegexRule;
@ -227,10 +228,13 @@ impl ReferenceRule {
impl RegexRule for ReferenceRule { impl RegexRule for ReferenceRule {
fn name(&self) -> &'static str { "Reference" } fn name(&self) -> &'static str { "Reference" }
fn previous(&self) -> Option<&'static str> { Some("Text") } fn previous(&self) -> Option<&'static str> { Some("Text") }
fn regexes(&self) -> &[regex::Regex] { &self.re } fn regexes(&self) -> &[regex::Regex] { &self.re }
fn enabled(&self, _mode: &ParseMode, _id: usize) -> bool { true }
fn on_regex_match<'a>( fn on_regex_match<'a>(
&self, &self,
_: usize, _: usize,
@ -449,7 +453,12 @@ mod tests {
None, None,
)); ));
let parser = LangParser::default(); let parser = LangParser::default();
let (doc, _) = parser.parse(ParserState::new(&parser, None), source, None); let (doc, _) = parser.parse(
ParserState::new(&parser, None),
source,
None,
ParseMode::default(),
);
validate_document!(doc.content().borrow(), 0, validate_document!(doc.content().borrow(), 0,
Section; Section;
@ -476,7 +485,12 @@ mod tests {
None, None,
)); ));
let parser = LangParser::default(); let parser = LangParser::default();
let (doc, _) = parser.parse(ParserState::new(&parser, None), source, None); let (doc, _) = parser.parse(
ParserState::new(&parser, None),
source,
None,
ParseMode::default(),
);
validate_document!(doc.content().borrow(), 0, validate_document!(doc.content().borrow(), 0,
Paragraph { Paragraph {

View file

@ -2,6 +2,7 @@ use crate::document::document::Document;
use crate::lsp::semantic::Semantics; use crate::lsp::semantic::Semantics;
use crate::lua::kernel::Kernel; use crate::lua::kernel::Kernel;
use crate::lua::kernel::KernelContext; use crate::lua::kernel::KernelContext;
use crate::parser::parser::ParseMode;
use crate::parser::parser::ParserState; use crate::parser::parser::ParserState;
use crate::parser::parser::ReportColors; use crate::parser::parser::ReportColors;
use crate::parser::rule::RegexRule; use crate::parser::rule::RegexRule;
@ -79,10 +80,13 @@ impl ScriptRule {
impl RegexRule for ScriptRule { impl RegexRule for ScriptRule {
fn name(&self) -> &'static str { "Script" } fn name(&self) -> &'static str { "Script" }
fn previous(&self) -> Option<&'static str> { Some("Import") } fn previous(&self) -> Option<&'static str> { Some("Import") }
fn regexes(&self) -> &[regex::Regex] { &self.re } fn regexes(&self) -> &[regex::Regex] { &self.re }
fn enabled(&self, mode: &ParseMode, id: usize) -> bool { !mode.paragraph_only || id != 0 }
fn on_regex_match<'a>( fn on_regex_match<'a>(
&self, &self,
index: usize, index: usize,
@ -244,9 +248,12 @@ impl RegexRule for ScriptRule {
)) as Rc<dyn Source>; )) as Rc<dyn Source>;
state.with_state(|new_state| { state.with_state(|new_state| {
new_state new_state.parser.parse_into(
.parser new_state,
.parse_into(new_state, parse_source, document); parse_source,
document,
ParseMode::default(),
);
}) })
} }
} }
@ -350,7 +357,12 @@ Evaluation: %<! make_ref("hello", "id")>%
None, None,
)); ));
let parser = LangParser::default(); let parser = LangParser::default();
let (doc, _) = parser.parse(ParserState::new(&parser, None), source, None); let (doc, _) = parser.parse(
ParserState::new(&parser, None),
source,
None,
ParseMode::default(),
);
validate_document!(doc.content().borrow(), 0, validate_document!(doc.content().borrow(), 0,
Paragraph; Paragraph;
@ -393,6 +405,7 @@ end
ParserState::new_with_semantics(&parser, None), ParserState::new_with_semantics(&parser, None),
source.clone(), source.clone(),
None, None,
ParseMode::default(),
); );
validate_semantics!(state, source.clone(), 0, validate_semantics!(state, source.clone(), 0,
script_sep { delta_line == 1, delta_start == 0, length == 2 }; script_sep { delta_line == 1, delta_start == 0, length == 2 };

View file

@ -6,6 +6,7 @@ use crate::document::element::Element;
use crate::document::element::ReferenceableElement; use crate::document::element::ReferenceableElement;
use crate::lsp::semantic::Semantics; use crate::lsp::semantic::Semantics;
use crate::lua::kernel::CTX; use crate::lua::kernel::CTX;
use crate::parser::parser::ParseMode;
use crate::parser::parser::ParserState; use crate::parser::parser::ParserState;
use crate::parser::rule::RegexRule; use crate::parser::rule::RegexRule;
use crate::parser::source::Source; use crate::parser::source::Source;
@ -168,10 +169,13 @@ pub mod section_kind {
impl RegexRule for SectionRule { impl RegexRule for SectionRule {
fn name(&self) -> &'static str { "Section" } fn name(&self) -> &'static str { "Section" }
fn previous(&self) -> Option<&'static str> { Some("Custom Style") } fn previous(&self) -> Option<&'static str> { Some("Custom Style") }
fn regexes(&self) -> &[Regex] { &self.re } fn regexes(&self) -> &[Regex] { &self.re }
fn enabled(&self, mode: &ParseMode, _id: usize) -> bool { !mode.paragraph_only }
fn on_regex_match( fn on_regex_match(
&self, &self,
_: usize, _: usize,
@ -327,15 +331,17 @@ impl RegexRule for SectionRule {
}), }),
); );
if let Some((sems, tokens)) = Semantics::from_source(token.source(), &state.shared.semantics) if let Some((sems, tokens)) =
Semantics::from_source(token.source(), &state.shared.semantics)
{ {
sems.add(matches.get(1).unwrap().range(), tokens.section_heading); sems.add(matches.get(1).unwrap().range(), tokens.section_heading);
if let Some(reference) = matches.get(2) if let Some(reference) = matches.get(2) {
{ sems.add(
sems.add(reference.start()-1..reference.end()+1, tokens.section_reference); reference.start() - 1..reference.end() + 1,
tokens.section_reference,
);
} }
if let Some(kind) = matches.get(3) if let Some(kind) = matches.get(3) {
{
sems.add(kind.range(), tokens.section_kind); sems.add(kind.range(), tokens.section_kind);
} }
sems.add(matches.get(5).unwrap().range(), tokens.section_name); sems.add(matches.get(5).unwrap().range(), tokens.section_name);
@ -452,7 +458,8 @@ mod tests {
use crate::parser::langparser::LangParser; use crate::parser::langparser::LangParser;
use crate::parser::parser::Parser; use crate::parser::parser::Parser;
use crate::parser::source::SourceFile; use crate::parser::source::SourceFile;
use crate::{validate_document, validate_semantics}; use crate::validate_document;
use crate::validate_semantics;
use super::*; use super::*;
@ -472,7 +479,12 @@ mod tests {
None, None,
)); ));
let parser = LangParser::default(); let parser = LangParser::default();
let (doc, _) = parser.parse(ParserState::new(&parser, None), source, None); let (doc, _) = parser.parse(
ParserState::new(&parser, None),
source,
None,
ParseMode::default(),
);
validate_document!(doc.content().borrow(), 0, validate_document!(doc.content().borrow(), 0,
Section { depth == 1, title == "1" }; Section { depth == 1, title == "1" };
@ -502,7 +514,12 @@ nml.section.push("6", 6, "", "refname")
None, None,
)); ));
let parser = LangParser::default(); let parser = LangParser::default();
let (doc, _) = parser.parse(ParserState::new(&parser, None), source, None); let (doc, _) = parser.parse(
ParserState::new(&parser, None),
source,
None,
ParseMode::default(),
);
validate_document!(doc.content().borrow(), 0, validate_document!(doc.content().borrow(), 0,
Section { depth == 1, title == "1" }; Section { depth == 1, title == "1" };
@ -529,7 +546,7 @@ nml.section.push("6", 6, "", "refname")
)); ));
let parser = LangParser::default(); let parser = LangParser::default();
let state = ParserState::new(&parser, None); let state = ParserState::new(&parser, None);
let (_, state) = parser.parse(state, source, None); let (_, state) = parser.parse(state, source, None, ParseMode::default());
let style = state let style = state
.shared .shared
@ -547,8 +564,7 @@ nml.section.push("6", 6, "", "refname")
} }
#[test] #[test]
fn semantics() fn semantics() {
{
let source = Rc::new(SourceFile::with_content( let source = Rc::new(SourceFile::with_content(
"".to_string(), "".to_string(),
r#" r#"
@ -560,21 +576,26 @@ nml.section.push("6", 6, "", "refname")
None, None,
)); ));
let parser = LangParser::default(); let parser = LangParser::default();
let (_, state) = parser.parse(ParserState::new_with_semantics(&parser, None), source.clone(), None); let (_, state) = parser.parse(
ParserState::new_with_semantics(&parser, None),
source.clone(),
None,
ParseMode::default(),
);
validate_semantics!(state, source.clone(), 0, validate_semantics!(state, source.clone(), 0,
section_heading { delta_line == 1, delta_start == 0, length == 1 }; section_heading { delta_line == 1, delta_start == 0, length == 1 };
section_name { delta_line == 0, delta_start == 1 }; section_name { delta_line == 0, delta_start == 1 };
section_heading { delta_line == 1, delta_start == 0, length == 2 }; section_heading { delta_line == 1, delta_start == 0, length == 2 };
section_reference { delta_line == 0, delta_start == 2, length == 4 }; section_reference { delta_line == 0, delta_start == 2, length == 4 };
section_kind { delta_line == 0, delta_start == 4, length == 1 }; section_kind { delta_line == 0, delta_start == 4, length == 1 };
section_name { delta_line == 0, delta_start == 1 }; section_name { delta_line == 0, delta_start == 1 };
section_heading { delta_line == 1, delta_start == 0, length == 1 }; section_heading { delta_line == 1, delta_start == 0, length == 1 };
section_reference { delta_line == 0, delta_start == 1, length == 9 }; section_reference { delta_line == 0, delta_start == 1, length == 9 };
section_kind { delta_line == 0, delta_start == 9, length == 2 }; section_kind { delta_line == 0, delta_start == 9, length == 2 };
section_name { delta_line == 0, delta_start == 2 }; section_name { delta_line == 0, delta_start == 2 };
); );
} }
} }

View file

@ -6,6 +6,7 @@ use crate::document::element::ElemKind;
use crate::document::element::Element; use crate::document::element::Element;
use crate::lsp::semantic::Semantics; use crate::lsp::semantic::Semantics;
use crate::lua::kernel::CTX; use crate::lua::kernel::CTX;
use crate::parser::parser::ParseMode;
use crate::parser::parser::ParserState; use crate::parser::parser::ParserState;
use crate::parser::rule::RegexRule; use crate::parser::rule::RegexRule;
use crate::parser::source::Source; use crate::parser::source::Source;
@ -167,10 +168,13 @@ static STATE_NAME: &str = "elements.style";
impl RegexRule for StyleRule { impl RegexRule for StyleRule {
fn name(&self) -> &'static str { "Style" } fn name(&self) -> &'static str { "Style" }
fn previous(&self) -> Option<&'static str> { Some("Layout") } fn previous(&self) -> Option<&'static str> { Some("Layout") }
fn regexes(&self) -> &[regex::Regex] { &self.re } fn regexes(&self) -> &[regex::Regex] { &self.re }
fn enabled(&self, _mode: &ParseMode, _id: usize) -> bool { true }
fn on_regex_match( fn on_regex_match(
&self, &self,
index: usize, index: usize,
@ -316,7 +320,12 @@ __`UNDERLINE+EM`__
None, None,
)); ));
let parser = LangParser::default(); let parser = LangParser::default();
let (doc, _) = parser.parse(ParserState::new(&parser, None), source, None); let (doc, _) = parser.parse(
ParserState::new(&parser, None),
source,
None,
ParseMode::default(),
);
validate_document!(doc.content().borrow(), 0, validate_document!(doc.content().borrow(), 0,
Paragraph { Paragraph {
@ -357,7 +366,12 @@ terminated here%<nml.style.toggle("Italic")>%
None, None,
)); ));
let parser = LangParser::default(); let parser = LangParser::default();
let (doc, _) = parser.parse(ParserState::new(&parser, None), source, None); let (doc, _) = parser.parse(
ParserState::new(&parser, None),
source,
None,
ParseMode::default(),
);
validate_document!(doc.content().borrow(), 0, validate_document!(doc.content().borrow(), 0,
Paragraph { Paragraph {
@ -399,6 +413,7 @@ __teかst__ *another*
ParserState::new_with_semantics(&parser, None), ParserState::new_with_semantics(&parser, None),
source.clone(), source.clone(),
None, None,
ParseMode::default(),
); );
validate_semantics!(state, source.clone(), 0, validate_semantics!(state, source.clone(), 0,

View file

@ -29,6 +29,7 @@ use crate::document::document::Document;
use crate::document::element::ElemKind; use crate::document::element::ElemKind;
use crate::document::element::Element; use crate::document::element::Element;
use crate::lua::kernel::CTX; use crate::lua::kernel::CTX;
use crate::parser::parser::ParseMode;
use crate::parser::parser::ParserState; use crate::parser::parser::ParserState;
use crate::parser::parser::ReportColors; use crate::parser::parser::ReportColors;
use crate::parser::rule::RegexRule; use crate::parser::rule::RegexRule;
@ -114,7 +115,9 @@ impl FormattedTex {
} }
let mut result = String::new(); let mut result = String::new();
if let Err(e) = process.stdout.unwrap().read_to_string(&mut result) { panic!("Unable to read `latex2svg` stdout: {}", e) } if let Err(e) = process.stdout.unwrap().read_to_string(&mut result) {
panic!("Unable to read `latex2svg` stdout: {}", e)
}
println!("Done!"); println!("Done!");
Ok(result) Ok(result)
@ -303,10 +306,13 @@ impl TexRule {
impl RegexRule for TexRule { impl RegexRule for TexRule {
fn name(&self) -> &'static str { "Tex" } fn name(&self) -> &'static str { "Tex" }
fn previous(&self) -> Option<&'static str> { Some("Code") } fn previous(&self) -> Option<&'static str> { Some("Code") }
fn regexes(&self) -> &[regex::Regex] { &self.re } fn regexes(&self) -> &[regex::Regex] { &self.re }
fn enabled(&self, _mode: &ParseMode, _id: usize) -> bool { true }
fn on_regex_match( fn on_regex_match(
&self, &self,
index: usize, index: usize,
@ -407,14 +413,16 @@ impl RegexRule for TexRule {
.get("caption", |_, value| -> Result<String, ()> { .get("caption", |_, value| -> Result<String, ()> {
Ok(value.clone()) Ok(value.clone())
}) })
.ok().map(|(_, value)| value); .ok()
.map(|(_, value)| value);
// Environ // Environ
let tex_env = properties let tex_env = properties
.get("env", |_, value| -> Result<String, ()> { .get("env", |_, value| -> Result<String, ()> {
Ok(value.clone()) Ok(value.clone())
}) })
.ok().map(|(_, value)| value) .ok()
.map(|(_, value)| value)
.unwrap(); .unwrap();
state.push( state.push(
@ -548,7 +556,12 @@ $[kind=block,env=another] e^{i\pi}=-1$
None, None,
)); ));
let parser = LangParser::default(); let parser = LangParser::default();
let (doc, _) = parser.parse(ParserState::new(&parser, None), source, None); let (doc, _) = parser.parse(
ParserState::new(&parser, None),
source,
None,
ParseMode::default(),
);
validate_document!(doc.content().borrow(), 0, validate_document!(doc.content().borrow(), 0,
Tex { mathmode == true, tex == "1+1=2", env == "main", caption == Some("Some, text\\".to_string()) }; Tex { mathmode == true, tex == "1+1=2", env == "main", caption == Some("Some, text\\".to_string()) };
@ -576,7 +589,12 @@ $[env=another] e^{i\pi}=-1$
None, None,
)); ));
let parser = LangParser::default(); let parser = LangParser::default();
let (doc, _) = parser.parse(ParserState::new(&parser, None), source, None); let (doc, _) = parser.parse(
ParserState::new(&parser, None),
source,
None,
ParseMode::default(),
);
validate_document!(doc.content().borrow(), 0, validate_document!(doc.content().borrow(), 0,
Paragraph { Paragraph {

View file

@ -11,6 +11,7 @@ use crate::document::document::Document;
use crate::document::element::ElemKind; use crate::document::element::ElemKind;
use crate::document::element::Element; use crate::document::element::Element;
use crate::lua::kernel::CTX; use crate::lua::kernel::CTX;
use crate::parser::parser::ParseMode;
use crate::parser::parser::ParserState; use crate::parser::parser::ParserState;
use crate::parser::rule::Rule; use crate::parser::rule::Rule;
use crate::parser::source::Cursor; use crate::parser::source::Cursor;
@ -24,12 +25,7 @@ pub struct Text {
} }
impl Text { impl Text {
pub fn new(location: Token, content: String) -> Text { pub fn new(location: Token, content: String) -> Text { Text { location, content } }
Text {
location,
content,
}
}
} }
impl Element for Text { impl Element for Text {
@ -37,7 +33,12 @@ impl Element for Text {
fn kind(&self) -> ElemKind { ElemKind::Inline } fn kind(&self) -> ElemKind { ElemKind::Inline }
fn element_name(&self) -> &'static str { "Text" } fn element_name(&self) -> &'static str { "Text" }
fn compile(&self, compiler: &Compiler, _document: &dyn Document, _cursor: usize) -> Result<String, String> { fn compile(
&self,
compiler: &Compiler,
_document: &dyn Document,
_cursor: usize,
) -> Result<String, String> {
Ok(Compiler::sanitize(compiler.target(), self.content.as_str())) Ok(Compiler::sanitize(compiler.target(), self.content.as_str()))
} }
} }
@ -51,9 +52,15 @@ impl TextRule {
impl Rule for TextRule { impl Rule for TextRule {
fn name(&self) -> &'static str { "Text" } fn name(&self) -> &'static str { "Text" }
fn previous(&self) -> Option<&'static str> { Some("Link") } fn previous(&self) -> Option<&'static str> { Some("Link") }
fn next_match(&self, _state: &ParserState, _cursor: &Cursor) -> Option<(usize, Box<dyn Any>)> { fn next_match(
&self,
_mode: &ParseMode,
_state: &ParserState,
_cursor: &Cursor,
) -> Option<(usize, Box<dyn Any>)> {
None None
} }

View file

@ -4,6 +4,7 @@ use crate::document::variable::PathVariable;
use crate::document::variable::Variable; use crate::document::variable::Variable;
use crate::lsp::semantic::Semantics; use crate::lsp::semantic::Semantics;
use crate::lua::kernel::CTX; use crate::lua::kernel::CTX;
use crate::parser::parser::ParseMode;
use crate::parser::parser::ParserState; use crate::parser::parser::ParserState;
use crate::parser::parser::ReportColors; use crate::parser::parser::ReportColors;
use crate::parser::rule::RegexRule; use crate::parser::rule::RegexRule;
@ -119,10 +120,13 @@ impl VariableRule {
impl RegexRule for VariableRule { impl RegexRule for VariableRule {
fn name(&self) -> &'static str { "Variable" } fn name(&self) -> &'static str { "Variable" }
fn previous(&self) -> Option<&'static str> { Some("Element Style") } fn previous(&self) -> Option<&'static str> { Some("Element Style") }
fn regexes(&self) -> &[Regex] { &self.re } fn regexes(&self) -> &[Regex] { &self.re }
fn enabled(&self, mode: &ParseMode, _id: usize) -> bool { !mode.paragraph_only }
fn on_regex_match( fn on_regex_match(
&self, &self,
_: usize, _: usize,
@ -257,17 +261,18 @@ impl RegexRule for VariableRule {
} }
} }
if let Some((sems, tokens)) = Semantics::from_source(token.source(), &state.shared.semantics) if let Some((sems, tokens)) =
Semantics::from_source(token.source(), &state.shared.semantics)
{ {
let name = matches.get(2).unwrap().range(); let name = matches.get(2).unwrap().range();
if let Some(kind) = matches.get(1).map(|m| m.range()) { if let Some(kind) = matches.get(1).map(|m| m.range()) {
sems.add(kind.start-1..kind.start, tokens.variable_operator); sems.add(kind.start - 1..kind.start, tokens.variable_operator);
sems.add(kind, tokens.variable_kind); sems.add(kind, tokens.variable_kind);
} else { } else {
sems.add(name.start-1..name.start, tokens.variable_operator); sems.add(name.start - 1..name.start, tokens.variable_operator);
} }
sems.add(name.clone(), tokens.variable_name); sems.add(name.clone(), tokens.variable_name);
sems.add(name.end..name.end+1, tokens.variable_sep); sems.add(name.end..name.end + 1, tokens.variable_sep);
let value = matches.get(3).unwrap().range(); let value = matches.get(3).unwrap().range();
sems.add(value.clone(), tokens.variable_value); sems.add(value.clone(), tokens.variable_value);
} }
@ -297,8 +302,7 @@ impl RegexRule for VariableRule {
let mut value: Option<String> = None; let mut value: Option<String> = None;
CTX.with_borrow(|ctx| { CTX.with_borrow(|ctx| {
ctx.as_ref().map(|ctx| { ctx.as_ref().map(|ctx| {
if let Some(var) = ctx.document.get_variable(name.as_str()) if let Some(var) = ctx.document.get_variable(name.as_str()) {
{
value = Some(var.to_string()); value = Some(var.to_string());
} }
}) })
@ -328,10 +332,13 @@ impl VariableSubstitutionRule {
impl RegexRule for VariableSubstitutionRule { impl RegexRule for VariableSubstitutionRule {
fn name(&self) -> &'static str { "Variable Substitution" } fn name(&self) -> &'static str { "Variable Substitution" }
fn previous(&self) -> Option<&'static str> { Some("Variable") } fn previous(&self) -> Option<&'static str> { Some("Variable") }
fn regexes(&self) -> &[regex::Regex] { &self.re } fn regexes(&self) -> &[regex::Regex] { &self.re }
fn enabled(&self, _mode: &ParseMode, _id: usize) -> bool { true }
fn on_regex_match<'a>( fn on_regex_match<'a>(
&self, &self,
_index: usize, _index: usize,
@ -351,7 +358,9 @@ impl RegexRule for VariableSubstitutionRule {
.with_message("Empty variable name") .with_message("Empty variable name")
.with_label( .with_label(
Label::new((token.source(), matches.get(0).unwrap().range())) Label::new((token.source(), matches.get(0).unwrap().range()))
.with_message("Missing variable name for substitution".to_string()) .with_message(
"Missing variable name for substitution".to_string(),
)
.with_color(state.parser.colors().error), .with_color(state.parser.colors().error),
) )
.finish(), .finish(),
@ -366,7 +375,9 @@ impl RegexRule for VariableSubstitutionRule {
.with_message("Invalid variable name") .with_message("Invalid variable name")
.with_label( .with_label(
Label::new((token.source(), name.range())) Label::new((token.source(), name.range()))
.with_message("Variable names contains leading spaces".to_string()) .with_message(
"Variable names contains leading spaces".to_string(),
)
.with_color(state.parser.colors().error), .with_color(state.parser.colors().error),
) )
.with_help("Remove leading spaces") .with_help("Remove leading spaces")
@ -382,7 +393,9 @@ impl RegexRule for VariableSubstitutionRule {
.with_message("Invalid variable name") .with_message("Invalid variable name")
.with_label( .with_label(
Label::new((token.source(), name.range())) Label::new((token.source(), name.range()))
.with_message("Variable names contains trailing spaces".to_string()) .with_message(
"Variable names contains trailing spaces".to_string(),
)
.with_color(state.parser.colors().error), .with_color(state.parser.colors().error),
) )
.with_help("Remove trailing spaces") .with_help("Remove trailing spaces")
@ -392,20 +405,21 @@ impl RegexRule for VariableSubstitutionRule {
return result; return result;
} }
// Invalid name // Invalid name
if let Err(msg) = VariableRule::validate_name(state.parser.colors(), name.as_str()) { if let Err(msg) = VariableRule::validate_name(state.parser.colors(), name.as_str())
result.push( {
Report::build(ReportKind::Error, token.source(), name.start()) result.push(
.with_message("Invalid variable name") Report::build(ReportKind::Error, token.source(), name.start())
.with_label( .with_message("Invalid variable name")
Label::new((token.source(), name.range())) .with_label(
.with_message(msg) Label::new((token.source(), name.range()))
.with_color(state.parser.colors().error), .with_message(msg)
) .with_color(state.parser.colors().error),
.finish(), )
); .finish(),
);
return result; return result;
} }
// Get variable // Get variable
match document.get_variable(name.as_str()) { match document.get_variable(name.as_str()) {
@ -433,12 +447,13 @@ impl RegexRule for VariableSubstitutionRule {
variable.parse(state, token.clone(), document); variable.parse(state, token.clone(), document);
if let Some((sems, tokens)) = Semantics::from_source(token.source(), &state.shared.semantics) if let Some((sems, tokens)) =
Semantics::from_source(token.source(), &state.shared.semantics)
{ {
let name = matches.get(1).unwrap().range(); let name = matches.get(1).unwrap().range();
sems.add(name.start-1..name.start, tokens.variable_sub_sep); sems.add(name.start - 1..name.start, tokens.variable_sub_sep);
sems.add(name.clone(), tokens.variable_sub_name); sems.add(name.clone(), tokens.variable_sub_name);
sems.add(name.end..name.end+1, tokens.variable_sub_sep); sems.add(name.end..name.end + 1, tokens.variable_sub_sep);
} }
result result

View file

@ -2,9 +2,9 @@ mod cache;
mod compiler; mod compiler;
mod document; mod document;
mod elements; mod elements;
mod lsp;
mod lua; mod lua;
mod parser; mod parser;
mod lsp;
use std::env; use std::env;
use std::io::BufWriter; use std::io::BufWriter;

View file

@ -5,9 +5,9 @@ use crate::document::document::Document;
use crate::document::element::DocumentEnd; use crate::document::element::DocumentEnd;
use crate::document::langdocument::LangDocument; use crate::document::langdocument::LangDocument;
use crate::elements::text::Text; use crate::elements::text::Text;
use crate::lsp::semantic::Semantics;
use crate::lsp::semantic::SemanticsData; use crate::lsp::semantic::SemanticsData;
use super::parser::ParseMode;
use super::parser::Parser; use super::parser::Parser;
use super::parser::ParserState; use super::parser::ParserState;
use super::parser::ReportColors; use super::parser::ReportColors;
@ -37,8 +37,7 @@ impl LangParser {
}; };
// Register rules // Register rules
for rule in super::rule::get_rule_registry() for rule in super::rule::get_rule_registry() {
{
s.add_rule(rule).unwrap(); s.add_rule(rule).unwrap();
} }
@ -59,16 +58,19 @@ impl Parser for LangParser {
state: ParserState<'p, 'a>, state: ParserState<'p, 'a>,
source: Rc<dyn Source>, source: Rc<dyn Source>,
parent: Option<&'doc dyn Document<'doc>>, parent: Option<&'doc dyn Document<'doc>>,
mode: ParseMode,
) -> (Box<dyn Document<'doc> + 'doc>, ParserState<'p, 'a>) { ) -> (Box<dyn Document<'doc> + 'doc>, ParserState<'p, 'a>) {
let doc = LangDocument::new(source.clone(), parent); let doc = LangDocument::new(source.clone(), parent);
// Insert semantics into state // Insert semantics into state
if let (Some(_), Some(semantics)) = (source.clone().downcast_rc::<SourceFile>().ok(), state.shared.semantics.as_ref()) if let (Some(_), Some(semantics)) = (
{ source.clone().downcast_rc::<SourceFile>().ok(),
state.shared.semantics.as_ref(),
) {
let mut b = semantics.borrow_mut(); let mut b = semantics.borrow_mut();
if !b.sems.contains_key(&source) if !b.sems.contains_key(&source) {
{ b.sems
b.sems.insert(source.clone(), SemanticsData::new(source.clone())); .insert(source.clone(), SemanticsData::new(source.clone()));
} }
} }
@ -86,7 +88,7 @@ impl Parser for LangParser {
} }
loop { loop {
let (rule_pos, mut result) = state.update_matches(&cursor); let (rule_pos, mut result) = state.update_matches(&mode, &cursor);
// Unmatched content // Unmatched content
let text_content = let text_content =
@ -125,13 +127,12 @@ impl Parser for LangParser {
super::state::Scope::DOCUMENT, super::state::Scope::DOCUMENT,
)); ));
if parent.is_none() if parent.is_none() {
{
state.push( state.push(
&doc, &doc,
Box::new(DocumentEnd(Token::new( Box::new(DocumentEnd(Token::new(
doc.source().content().len()..doc.source().content().len(), doc.source().content().len()..doc.source().content().len(),
doc.source(), doc.source(),
))), ))),
); );
} }
@ -144,12 +145,13 @@ impl Parser for LangParser {
state: ParserState<'p, 'a>, state: ParserState<'p, 'a>,
source: Rc<dyn Source>, source: Rc<dyn Source>,
document: &'doc dyn Document<'doc>, document: &'doc dyn Document<'doc>,
mode: ParseMode,
) -> ParserState<'p, 'a> { ) -> ParserState<'p, 'a> {
let content = source.content(); let content = source.content();
let mut cursor = Cursor::new(0usize, source.clone()); let mut cursor = Cursor::new(0usize, source.clone());
loop { loop {
let (rule_pos, mut result) = state.update_matches(&cursor); let (rule_pos, mut result) = state.update_matches(&mode, &cursor);
// Unmatched content // Unmatched content
let text_content = let text_content =

View file

@ -147,7 +147,10 @@ impl<'a, 'b> ParserState<'a, 'b> {
/// Constructs a new state with semantics enabled /// Constructs a new state with semantics enabled
/// See [`ParserState::new`] for mote information /// See [`ParserState::new`] for mote information
pub fn new_with_semantics(parser: &'a dyn Parser, parent: Option<&'a ParserState<'a, 'b>>) -> Self { pub fn new_with_semantics(
parser: &'a dyn Parser,
parent: Option<&'a ParserState<'a, 'b>>,
) -> Self {
let matches = parser.rules().iter().map(|_| (0, None)).collect::<Vec<_>>(); let matches = parser.rules().iter().map(|_| (0, None)).collect::<Vec<_>>();
let shared = if let Some(parent) = &parent { let shared = if let Some(parent) = &parent {
parent.shared.clone() parent.shared.clone()
@ -199,7 +202,11 @@ impl<'a, 'b> ParserState<'a, 'b> {
/// Notes that the result of every call to [`Rule::next_match`] gets stored /// Notes that the result of every call to [`Rule::next_match`] gets stored
/// in a table: [`ParserState::matches`]. Until the cursor steps over a /// in a table: [`ParserState::matches`]. Until the cursor steps over a
/// position in the table, `next_match` won't be called. /// position in the table, `next_match` won't be called.
pub fn update_matches(&self, cursor: &Cursor) -> (Cursor, Option<(usize, Box<dyn Any>)>) { pub fn update_matches(
&self,
mode: &ParseMode,
cursor: &Cursor,
) -> (Cursor, Option<(usize, Box<dyn Any>)>) {
let mut matches_borrow = self.matches.borrow_mut(); let mut matches_borrow = self.matches.borrow_mut();
self.parser self.parser
@ -212,7 +219,7 @@ impl<'a, 'b> ParserState<'a, 'b> {
return; return;
} }
(*matched_at, *match_data) = match rule.next_match(self, cursor) { (*matched_at, *match_data) = match rule.next_match(&mode, self, cursor) {
None => (usize::MAX, None), None => (usize::MAX, None),
Some((mut pos, mut data)) => { Some((mut pos, mut data)) => {
// Check if escaped // Check if escaped
@ -233,7 +240,7 @@ impl<'a, 'b> ParserState<'a, 'b> {
} }
// Find next potential match // Find next potential match
(pos, data) = match rule.next_match(self, &cursor.at(pos + 1)) { (pos, data) = match rule.next_match(&mode, self, &cursor.at(pos + 1)) {
Some((new_pos, new_data)) => (new_pos, new_data), Some((new_pos, new_data)) => (new_pos, new_data),
None => (usize::MAX, data), // Stop iterating None => (usize::MAX, data), // Stop iterating
} }
@ -308,24 +315,28 @@ impl<'a, 'b> ParserState<'a, 'b> {
/// # Error /// # Error
/// ///
/// Returns an error if `rule_name` was not found in the parser's ruleset. /// Returns an error if `rule_name` was not found in the parser's ruleset.
pub fn reset_match(&self, rule_name: &str) -> Result<(), String> pub fn reset_match(&self, rule_name: &str) -> Result<(), String> {
{ if self
if self.parser.rules().iter() .parser
.rules()
.iter()
.zip(self.matches.borrow_mut().iter_mut()) .zip(self.matches.borrow_mut().iter_mut())
.try_for_each(|(rule, (match_pos, match_data))| { .try_for_each(|(rule, (match_pos, match_data))| {
if rule.name() != rule_name { return Ok(()) } if rule.name() != rule_name {
return Ok(());
}
*match_pos = 0; *match_pos = 0;
match_data.take(); match_data.take();
Err(()) Err(())
}).is_ok() })
.is_ok()
{ {
return Err(format!("Could not find rule: {rule_name}")); return Err(format!("Could not find rule: {rule_name}"));
} }
// Resurcively reset // Resurcively reset
if let Some(parent) = self.parent if let Some(parent) = self.parent {
{
return parent.reset_match(rule_name); return parent.reset_match(rule_name);
} }
@ -333,6 +344,18 @@ impl<'a, 'b> ParserState<'a, 'b> {
} }
} }
pub struct ParseMode {
pub paragraph_only: bool,
}
impl Default for ParseMode {
fn default() -> Self {
Self {
paragraph_only: false,
}
}
}
pub trait Parser { pub trait Parser {
/// Gets the colors for formatting errors /// Gets the colors for formatting errors
/// ///
@ -365,6 +388,7 @@ pub trait Parser {
state: ParserState<'p, 'a>, state: ParserState<'p, 'a>,
source: Rc<dyn Source>, source: Rc<dyn Source>,
parent: Option<&'doc dyn Document<'doc>>, parent: Option<&'doc dyn Document<'doc>>,
mode: ParseMode,
) -> (Box<dyn Document<'doc> + 'doc>, ParserState<'p, 'a>); ) -> (Box<dyn Document<'doc> + 'doc>, ParserState<'p, 'a>);
/// Parse [`Source`] into an already existing [`Document`] /// Parse [`Source`] into an already existing [`Document`]
@ -384,6 +408,7 @@ pub trait Parser {
state: ParserState<'p, 'a>, state: ParserState<'p, 'a>,
source: Rc<dyn Source>, source: Rc<dyn Source>,
document: &'doc dyn Document<'doc>, document: &'doc dyn Document<'doc>,
mode: ParseMode,
) -> ParserState<'p, 'a>; ) -> ParserState<'p, 'a>;
/// Adds a rule to the parser. /// Adds a rule to the parser.
@ -444,8 +469,11 @@ pub trait Parser {
if let Some(_s) = source.downcast_ref::<VirtualSource>() { if let Some(_s) = source.downcast_ref::<VirtualSource>() {
let start = location.start() let start = location.start()
+ if location.source().content().as_bytes()[location.start()] + if location.source().content().as_bytes()[location.start()] == b'\n' {
== b'\n' { 1 } else { 0 }; 1
} else {
0
};
report.labels.push( report.labels.push(
Label::new((location.source(), start..location.end())) Label::new((location.source(), start..location.end()))
.with_message("In evaluation of") .with_message("In evaluation of")

View file

@ -1,4 +1,5 @@
use super::layout::LayoutHolder; use super::layout::LayoutHolder;
use super::parser::ParseMode;
use super::parser::ParserState; use super::parser::ParserState;
use super::source::Cursor; use super::source::Cursor;
use super::source::Source; use super::source::Source;
@ -73,7 +74,13 @@ pub trait Rule: Downcast {
fn previous(&self) -> Option<&'static str>; fn previous(&self) -> Option<&'static str>;
/// Finds the next match starting from [`cursor`] /// Finds the next match starting from [`cursor`]
fn next_match(&self, state: &ParserState, cursor: &Cursor) -> Option<(usize, Box<dyn Any>)>; fn next_match(
&self,
mode: &ParseMode,
state: &ParserState,
cursor: &Cursor,
) -> Option<(usize, Box<dyn Any>)>;
/// Callback when rule matches /// Callback when rule matches
fn on_match<'a>( fn on_match<'a>(
&self, &self,
@ -110,6 +117,9 @@ pub trait RegexRule {
/// Returns the rule's regexes /// Returns the rule's regexes
fn regexes(&self) -> &[regex::Regex]; fn regexes(&self) -> &[regex::Regex];
/// Wheter parsing for the rule is enabled
fn enabled(&self, mode: &ParseMode, index: usize) -> bool;
/// Callback on regex rule match /// Callback on regex rule match
fn on_regex_match<'a>( fn on_regex_match<'a>(
&self, &self,
@ -127,13 +137,22 @@ pub trait RegexRule {
impl<T: RegexRule + 'static> Rule for T { impl<T: RegexRule + 'static> Rule for T {
fn name(&self) -> &'static str { RegexRule::name(self) } fn name(&self) -> &'static str { RegexRule::name(self) }
fn previous(&self) -> Option<&'static str> { RegexRule::previous(self) } fn previous(&self) -> Option<&'static str> { RegexRule::previous(self) }
/// Finds the next match starting from [`cursor`] /// Finds the next match starting from [`cursor`]
fn next_match(&self, _state: &ParserState, cursor: &Cursor) -> Option<(usize, Box<dyn Any>)> { fn next_match(
&self,
mode: &ParseMode,
_state: &ParserState,
cursor: &Cursor,
) -> Option<(usize, Box<dyn Any>)> {
let content = cursor.source.content(); let content = cursor.source.content();
let mut found: Option<(usize, usize)> = None; let mut found: Option<(usize, usize)> = None;
self.regexes().iter().enumerate().for_each(|(id, re)| { self.regexes().iter().enumerate().for_each(|(id, re)| {
if !RegexRule::enabled(self, mode, id) {
return;
}
if let Some(m) = re.find_at(content.as_str(), cursor.pos) { if let Some(m) = re.find_at(content.as_str(), cursor.pos) {
found = found found = found
.map(|(f_pos, f_id)| { .map(|(f_pos, f_id)| {

View file

@ -60,7 +60,8 @@ macro_rules! impl_elementstyle {
serde_json::from_str::<$t>(json) serde_json::from_str::<$t>(json)
.map_err(|e| e.to_string()) .map_err(|e| e.to_string())
.map(|obj| { .map(|obj| {
std::rc::Rc::new(obj) as std::rc::Rc<dyn $crate::parser::style::ElementStyle> std::rc::Rc::new(obj)
as std::rc::Rc<dyn $crate::parser::style::ElementStyle>
}) })
} }

View file

@ -8,6 +8,7 @@ use crate::document::document::DocumentAccessors;
use crate::document::element::ElemKind; use crate::document::element::ElemKind;
use crate::elements::paragraph::Paragraph; use crate::elements::paragraph::Paragraph;
use super::parser::ParseMode;
use super::parser::ParserState; use super::parser::ParserState;
use super::source::Source; use super::source::Source;
@ -143,7 +144,7 @@ pub fn parse_paragraph<'a>(
let parsed = state.with_state(|new_state| -> Box<dyn Document> { let parsed = state.with_state(|new_state| -> Box<dyn Document> {
new_state new_state
.parser .parser
.parse(new_state, source.clone(), Some(document)) .parse(new_state, source.clone(), Some(document), ParseMode { paragraph_only: true })
.0 .0
}); });
if parsed.content().borrow().len() > 1 { if parsed.content().borrow().len() > 1 {

View file

@ -10,6 +10,7 @@ use std::rc::Rc;
use dashmap::DashMap; use dashmap::DashMap;
use parser::langparser::LangParser; use parser::langparser::LangParser;
use parser::parser::ParseMode;
use parser::parser::Parser; use parser::parser::Parser;
use parser::parser::ParserState; use parser::parser::ParserState;
use parser::source::SourceFile; use parser::source::SourceFile;
@ -42,7 +43,7 @@ impl Backend {
// Which will require a dyn Document to work // Which will require a dyn Document to work
let source = Rc::new(SourceFile::with_content(params.uri.to_string(), params.text.clone(), None)); let source = Rc::new(SourceFile::with_content(params.uri.to_string(), params.text.clone(), None));
let parser = LangParser::default(); let parser = LangParser::default();
let (_doc, state) = parser.parse(ParserState::new_with_semantics(&parser, None), source.clone(), None); let (_doc, state) = parser.parse(ParserState::new_with_semantics(&parser, None), source.clone(), None, ParseMode::default());
if let Some(sems) = state.shared.semantics.as_ref() if let Some(sems) = state.shared.semantics.as_ref()
{ {