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::parser::langparser::LangParser;
use crate::parser::parser::ParseMode;
use crate::parser::parser::Parser;
use crate::parser::parser::ParserState;
use crate::parser::source::Source;
@ -25,7 +26,7 @@ fn parse(
) -> Result<Box<dyn Document<'static>>, String> {
// Parse
//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()) {
println!("-- BEGIN AST DEBUGGING --");

View file

@ -43,9 +43,10 @@ pub mod tests {
use super::*;
use crate::parser::langparser::LangParser;
use crate::parser::parser::ParseMode;
use crate::parser::parser::Parser;
use crate::parser::source::SourceFile;
use crate::parser::parser::ParserState;
use crate::parser::source::SourceFile;
#[test]
fn validate_refname_tests() {
@ -55,7 +56,12 @@ pub mod tests {
None,
));
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!(

View file

@ -1,5 +1,6 @@
use super::document::Document;
use crate::elements::text::Text;
use crate::parser::parser::ParseMode;
use crate::parser::parser::ParserState;
use crate::parser::source::Source;
use crate::parser::source::Token;
@ -63,7 +64,7 @@ impl Variable for BaseVariable {
));
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::elements::paragraph::Paragraph;
use crate::elements::text::Text;
use crate::parser::parser::ParseMode;
use crate::parser::parser::ParserState;
use crate::parser::rule::Rule;
use crate::parser::source::Cursor;
@ -233,7 +234,15 @@ impl Rule for BlockquoteRule {
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
.find_at(cursor.source.content(), cursor.pos)
.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| {
new_state
.parser
.parse(new_state, entry_src, Some(document))
.parse(new_state, entry_src, Some(document), ParseMode::default())
.0
});
@ -447,7 +456,12 @@ END
None,
));
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,
Paragraph { Text{ content == "BEFORE" }; };
@ -496,7 +510,12 @@ AFTER
None,
));
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
.shared

View file

@ -26,6 +26,7 @@ use crate::document::element::ElemKind;
use crate::document::element::Element;
use crate::lsp::semantic::Semantics;
use crate::lua::kernel::CTX;
use crate::parser::parser::ParseMode;
use crate::parser::parser::ParserState;
use crate::parser::rule::RegexRule;
use crate::parser::source::Source;
@ -309,8 +310,7 @@ impl CodeRule {
Regex::new(
r"``(?:\[((?:\\.|[^\\\\])*?)\])?(?:([^\r\n`]*?)(?:,|\n))?((?:\\(?:.|\n)|[^\\\\])*?)``",
)
.unwrap()
.unwrap(),
],
properties: PropertyParser { properties: props },
}
@ -319,10 +319,15 @@ impl CodeRule {
impl RegexRule for CodeRule {
fn name(&self) -> &'static str { "Code" }
fn previous(&self) -> Option<&'static str> { Some("Blockquote") }
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(
&self,
index: usize,
@ -710,7 +715,12 @@ fn fact(n: usize) -> usize
None,
));
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 found = borrow
@ -756,7 +766,12 @@ fn fact(n: usize) -> usize
None,
));
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 found = borrow
@ -806,6 +821,7 @@ test code
ParserState::new_with_semantics(&parser, None),
source.clone(),
None,
ParseMode::default(),
);
validate_semantics!(state, source.clone(), 0,
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::Element;
use crate::lsp::semantic::Semantics;
use crate::parser::parser::ParseMode;
use crate::parser::parser::ParserState;
use crate::parser::rule::RegexRule;
use crate::parser::source::Source;
@ -56,6 +57,8 @@ impl RegexRule for CommentRule {
fn regexes(&self) -> &[Regex] { &self.re }
fn enabled(&self, _mode: &ParseMode, _id: usize) -> bool { true }
fn on_regex_match(
&self,
_: usize,
@ -132,7 +135,12 @@ COMMENT ::Test
None,
));
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,
Paragraph {
@ -160,6 +168,7 @@ COMMENT ::Test
ParserState::new_with_semantics(&parser, None),
source.clone(),
None,
ParseMode::default(),
);
validate_semantics!(state, source.clone(), 0,

View file

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

View file

@ -1,3 +1,4 @@
use crate::parser::parser::ParseMode;
use crate::parser::style::ElementStyle;
use std::any::Any;
use std::ops::Range;
@ -59,11 +60,18 @@ impl ElemStyleRule {
impl Rule for ElemStyleRule {
fn name(&self) -> &'static str { "Element Style" }
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
.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>(
@ -132,7 +140,9 @@ impl Rule for ElemStyleRule {
.with_message("Invalid Style Value")
.with_label(
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),
)
.finish(),

View file

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

View file

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

View file

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

View file

@ -6,6 +6,7 @@ use crate::document::element::ElemKind;
use crate::document::element::Element;
use crate::lsp::semantic::Semantics;
use crate::lua::kernel::CTX;
use crate::parser::parser::ParseMode;
use crate::parser::parser::ParserState;
use crate::parser::rule::RegexRule;
use crate::parser::source::Source;
@ -94,10 +95,13 @@ impl LinkRule {
impl RegexRule for LinkRule {
fn name(&self) -> &'static str { "Link" }
fn previous(&self) -> Option<&'static str> { Some("Link") }
fn regexes(&self) -> &[Regex] { &self.re }
fn enabled(&self, _mode: &ParseMode, _id: usize) -> bool { true }
fn on_regex_match<'a>(
&self,
_: usize,
@ -314,7 +318,12 @@ Some [link](url).
None,
));
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,
Paragraph {
@ -344,7 +353,12 @@ nml.link.push("**BOLD link**", "another url")
None,
));
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,
Paragraph {
@ -375,6 +389,7 @@ nml.link.push("**BOLD link**", "another url")
ParserState::new_with_semantics(&parser, None),
source.clone(),
None,
ParseMode::default(),
);
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::Element;
use crate::lsp::semantic::Semantics;
use crate::parser::parser::ParseMode;
use crate::parser::parser::ParserState;
use crate::parser::rule::Rule;
use crate::parser::source::Cursor;
@ -269,9 +270,18 @@ impl ListRule {
impl Rule for ListRule {
fn name(&self) -> &'static str { "List" }
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
.find_at(cursor.source.content(), cursor.pos)
.map(|m| (m.start(), Box::new([false; 0]) as Box<dyn Any>))
@ -406,6 +416,7 @@ impl Rule for ListRule {
// Parse entry content
let token = Token::new(entry_start..end_cursor.pos, end_cursor.source.clone());
//println!("content={}", entry_content);
let entry_src = Rc::new(VirtualSource::new(
token.clone(),
"List Entry".to_string(),
@ -475,7 +486,8 @@ mod tests {
use crate::parser::langparser::LangParser;
use crate::parser::parser::Parser;
use crate::parser::source::SourceFile;
use crate::{validate_document, validate_semantics};
use crate::validate_document;
use crate::validate_semantics;
#[test]
fn parser() {
@ -498,7 +510,7 @@ mod tests {
));
let parser = LangParser::default();
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,
ListMarker { numbered == false, kind == MarkerKind::Open };
@ -549,7 +561,8 @@ mod tests {
*[offset=5] First **bold**
Second line
*- Another
>@
"#
.to_string(),
None,
@ -559,6 +572,7 @@ mod tests {
ParserState::new_with_semantics(&parser, None),
source.clone(),
None,
ParseMode::default(),
);
validate_semantics!(state, source.clone(), 0,
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::ReferenceableElement;
use crate::document::references::validate_refname;
use crate::parser::parser::ParseMode;
use crate::parser::parser::ParserState;
use crate::parser::parser::ReportColors;
use crate::parser::rule::RegexRule;
@ -72,14 +73,21 @@ impl Element for Media {
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() {
Target::HTML => {
let mut result = String::new();
result.push_str("<div class=\"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>");
@ -132,7 +140,12 @@ impl Element for Medium {
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() {
Target::HTML => {
let mut result = String::new();
@ -145,10 +158,18 @@ impl Element for Medium {
.width
.as_ref()
.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 {
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 => {
format!(r#"<audio controls src="{0}"{width}></audio>"#, self.uri)
@ -158,17 +179,17 @@ impl Element for Medium {
let caption = self
.caption
.as_ref().map(|cap| format!(
" {}",
Compiler::sanitize(compiler.target(), cap.as_str())
))
.as_ref()
.map(|cap| format!(" {}", Compiler::sanitize(compiler.target(), cap.as_str())))
.unwrap_or_default();
result.push_str(
format!(r#"<p class="medium-refname">({refcount}){caption}</p>"#).as_str(),
);
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>");
@ -214,9 +235,7 @@ impl ReferenceableElement for Medium {
}
}
fn refid(&self, _compiler: &Compiler, refid: usize) -> String {
format!("medium-{refid}")
}
fn refid(&self, _compiler: &Compiler, refid: usize) -> String { format!("medium-{refid}") }
}
#[auto_registry::auto_registry(registry = "rules", path = "crate::elements::media")]
@ -324,10 +343,13 @@ impl MediaRule {
impl RegexRule for MediaRule {
fn name(&self) -> &'static str { "Media" }
fn previous(&self) -> Option<&'static str> { Some("Graphviz") }
fn regexes(&self) -> &[regex::Regex] { &self.re }
fn enabled(&self, mode: &ParseMode, _id: usize) -> bool { !mode.paragraph_only }
fn on_regex_match<'a>(
&self,
_: usize,
@ -433,13 +455,15 @@ impl RegexRule for MediaRule {
.get("width", |_, value| -> Result<String, ()> {
Ok(value.clone())
})
.ok().map(|(_, s)| s);
.ok()
.map(|(_, s)| s);
let caption = properties
.get("caption", |_, value| -> Result<String, ()> {
Ok(value.clone())
})
.ok().map(|(_, value)| value);
.ok()
.map(|(_, value)| value);
let description = match matches.get(4) {
Some(content) => {
@ -546,7 +570,12 @@ mod tests {
None,
));
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 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::ElemKind;
use crate::document::element::Element;
use crate::parser::parser::ParseMode;
use crate::parser::parser::ParserState;
use crate::parser::rule::Rule;
use crate::parser::source::Cursor;
@ -48,7 +49,12 @@ impl Element for 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() {
return Ok(String::new());
}
@ -63,7 +69,9 @@ impl Element for Paragraph {
result.push_str("<p>");
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>");
@ -106,11 +114,18 @@ impl ParagraphRule {
impl Rule for ParagraphRule {
fn name(&self) -> &'static str { "Paragraph" }
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
.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(
@ -166,7 +181,12 @@ Last paragraph
None,
));
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,
Paragraph {

View file

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

View file

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

View file

@ -2,6 +2,7 @@ use crate::document::document::Document;
use crate::lsp::semantic::Semantics;
use crate::lua::kernel::Kernel;
use crate::lua::kernel::KernelContext;
use crate::parser::parser::ParseMode;
use crate::parser::parser::ParserState;
use crate::parser::parser::ReportColors;
use crate::parser::rule::RegexRule;
@ -79,10 +80,13 @@ impl ScriptRule {
impl RegexRule for ScriptRule {
fn name(&self) -> &'static str { "Script" }
fn previous(&self) -> Option<&'static str> { Some("Import") }
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>(
&self,
index: usize,
@ -244,9 +248,12 @@ impl RegexRule for ScriptRule {
)) as Rc<dyn Source>;
state.with_state(|new_state| {
new_state
.parser
.parse_into(new_state, parse_source, document);
new_state.parser.parse_into(
new_state,
parse_source,
document,
ParseMode::default(),
);
})
}
}
@ -350,7 +357,12 @@ Evaluation: %<! make_ref("hello", "id")>%
None,
));
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,
Paragraph;
@ -393,6 +405,7 @@ end
ParserState::new_with_semantics(&parser, None),
source.clone(),
None,
ParseMode::default(),
);
validate_semantics!(state, source.clone(), 0,
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::lsp::semantic::Semantics;
use crate::lua::kernel::CTX;
use crate::parser::parser::ParseMode;
use crate::parser::parser::ParserState;
use crate::parser::rule::RegexRule;
use crate::parser::source::Source;
@ -168,10 +169,13 @@ pub mod section_kind {
impl RegexRule for SectionRule {
fn name(&self) -> &'static str { "Section" }
fn previous(&self) -> Option<&'static str> { Some("Custom Style") }
fn regexes(&self) -> &[Regex] { &self.re }
fn enabled(&self, mode: &ParseMode, _id: usize) -> bool { !mode.paragraph_only }
fn on_regex_match(
&self,
_: 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);
if let Some(reference) = matches.get(2)
{
sems.add(reference.start()-1..reference.end()+1, tokens.section_reference);
if let Some(reference) = matches.get(2) {
sems.add(
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(matches.get(5).unwrap().range(), tokens.section_name);
@ -452,7 +458,8 @@ mod tests {
use crate::parser::langparser::LangParser;
use crate::parser::parser::Parser;
use crate::parser::source::SourceFile;
use crate::{validate_document, validate_semantics};
use crate::validate_document;
use crate::validate_semantics;
use super::*;
@ -472,7 +479,12 @@ mod tests {
None,
));
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,
Section { depth == 1, title == "1" };
@ -502,7 +514,12 @@ nml.section.push("6", 6, "", "refname")
None,
));
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,
Section { depth == 1, title == "1" };
@ -529,7 +546,7 @@ nml.section.push("6", 6, "", "refname")
));
let parser = LangParser::default();
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
.shared
@ -547,8 +564,7 @@ nml.section.push("6", 6, "", "refname")
}
#[test]
fn semantics()
{
fn semantics() {
let source = Rc::new(SourceFile::with_content(
"".to_string(),
r#"
@ -560,21 +576,26 @@ nml.section.push("6", 6, "", "refname")
None,
));
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,
section_heading { delta_line == 1, delta_start == 0, length == 1 };
section_name { delta_line == 0, delta_start == 1 };
section_heading { delta_line == 1, delta_start == 0, length == 1 };
section_name { delta_line == 0, delta_start == 1 };
section_heading { delta_line == 1, delta_start == 0, length == 2 };
section_reference { delta_line == 0, delta_start == 2, length == 4 };
section_kind { delta_line == 0, delta_start == 4, length == 1 };
section_name { delta_line == 0, delta_start == 1 };
section_heading { delta_line == 1, delta_start == 0, length == 2 };
section_reference { delta_line == 0, delta_start == 2, length == 4 };
section_kind { delta_line == 0, delta_start == 4, length == 1 };
section_name { delta_line == 0, delta_start == 1 };
section_heading { delta_line == 1, delta_start == 0, length == 1 };
section_reference { delta_line == 0, delta_start == 1, length == 9 };
section_kind { delta_line == 0, delta_start == 9, length == 2 };
section_name { delta_line == 0, delta_start == 2 };
);
section_heading { delta_line == 1, delta_start == 0, length == 1 };
section_reference { delta_line == 0, delta_start == 1, length == 9 };
section_kind { delta_line == 0, delta_start == 9, length == 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::lsp::semantic::Semantics;
use crate::lua::kernel::CTX;
use crate::parser::parser::ParseMode;
use crate::parser::parser::ParserState;
use crate::parser::rule::RegexRule;
use crate::parser::source::Source;
@ -167,10 +168,13 @@ static STATE_NAME: &str = "elements.style";
impl RegexRule for StyleRule {
fn name(&self) -> &'static str { "Style" }
fn previous(&self) -> Option<&'static str> { Some("Layout") }
fn regexes(&self) -> &[regex::Regex] { &self.re }
fn enabled(&self, _mode: &ParseMode, _id: usize) -> bool { true }
fn on_regex_match(
&self,
index: usize,
@ -316,7 +320,12 @@ __`UNDERLINE+EM`__
None,
));
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,
Paragraph {
@ -357,7 +366,12 @@ terminated here%<nml.style.toggle("Italic")>%
None,
));
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,
Paragraph {
@ -399,6 +413,7 @@ __teかst__ *another*
ParserState::new_with_semantics(&parser, None),
source.clone(),
None,
ParseMode::default(),
);
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::Element;
use crate::lua::kernel::CTX;
use crate::parser::parser::ParseMode;
use crate::parser::parser::ParserState;
use crate::parser::parser::ReportColors;
use crate::parser::rule::RegexRule;
@ -114,7 +115,9 @@ impl FormattedTex {
}
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!");
Ok(result)
@ -303,10 +306,13 @@ impl TexRule {
impl RegexRule for TexRule {
fn name(&self) -> &'static str { "Tex" }
fn previous(&self) -> Option<&'static str> { Some("Code") }
fn regexes(&self) -> &[regex::Regex] { &self.re }
fn enabled(&self, _mode: &ParseMode, _id: usize) -> bool { true }
fn on_regex_match(
&self,
index: usize,
@ -407,14 +413,16 @@ impl RegexRule for TexRule {
.get("caption", |_, value| -> Result<String, ()> {
Ok(value.clone())
})
.ok().map(|(_, value)| value);
.ok()
.map(|(_, value)| value);
// Environ
let tex_env = properties
.get("env", |_, value| -> Result<String, ()> {
Ok(value.clone())
})
.ok().map(|(_, value)| value)
.ok()
.map(|(_, value)| value)
.unwrap();
state.push(
@ -548,7 +556,12 @@ $[kind=block,env=another] e^{i\pi}=-1$
None,
));
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,
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,
));
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,
Paragraph {

View file

@ -11,6 +11,7 @@ use crate::document::document::Document;
use crate::document::element::ElemKind;
use crate::document::element::Element;
use crate::lua::kernel::CTX;
use crate::parser::parser::ParseMode;
use crate::parser::parser::ParserState;
use crate::parser::rule::Rule;
use crate::parser::source::Cursor;
@ -24,12 +25,7 @@ pub struct Text {
}
impl Text {
pub fn new(location: Token, content: String) -> Text {
Text {
location,
content,
}
}
pub fn new(location: Token, content: String) -> Text { Text { location, content } }
}
impl Element for Text {
@ -37,7 +33,12 @@ impl Element for Text {
fn kind(&self) -> ElemKind { ElemKind::Inline }
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()))
}
}
@ -51,9 +52,15 @@ impl TextRule {
impl Rule for TextRule {
fn name(&self) -> &'static str { "Text" }
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
}

View file

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

View file

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

View file

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

View file

@ -147,7 +147,10 @@ impl<'a, 'b> ParserState<'a, 'b> {
/// Constructs a new state with semantics enabled
/// 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 shared = if let Some(parent) = &parent {
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
/// in a table: [`ParserState::matches`]. Until the cursor steps over a
/// 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();
self.parser
@ -212,7 +219,7 @@ impl<'a, 'b> ParserState<'a, 'b> {
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),
Some((mut pos, mut data)) => {
// Check if escaped
@ -233,7 +240,7 @@ impl<'a, 'b> ParserState<'a, 'b> {
}
// 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),
None => (usize::MAX, data), // Stop iterating
}
@ -308,24 +315,28 @@ impl<'a, 'b> ParserState<'a, 'b> {
/// # Error
///
/// Returns an error if `rule_name` was not found in the parser's ruleset.
pub fn reset_match(&self, rule_name: &str) -> Result<(), String>
{
if self.parser.rules().iter()
pub fn reset_match(&self, rule_name: &str) -> Result<(), String> {
if self
.parser
.rules()
.iter()
.zip(self.matches.borrow_mut().iter_mut())
.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_data.take();
Err(())
}).is_ok()
})
.is_ok()
{
return Err(format!("Could not find rule: {rule_name}"));
}
// Resurcively reset
if let Some(parent) = self.parent
{
if let Some(parent) = self.parent {
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 {
/// Gets the colors for formatting errors
///
@ -365,6 +388,7 @@ pub trait Parser {
state: ParserState<'p, 'a>,
source: Rc<dyn Source>,
parent: Option<&'doc dyn Document<'doc>>,
mode: ParseMode,
) -> (Box<dyn Document<'doc> + 'doc>, ParserState<'p, 'a>);
/// Parse [`Source`] into an already existing [`Document`]
@ -384,6 +408,7 @@ pub trait Parser {
state: ParserState<'p, 'a>,
source: Rc<dyn Source>,
document: &'doc dyn Document<'doc>,
mode: ParseMode,
) -> ParserState<'p, 'a>;
/// Adds a rule to the parser.
@ -444,8 +469,11 @@ pub trait Parser {
if let Some(_s) = source.downcast_ref::<VirtualSource>() {
let start = location.start()
+ if location.source().content().as_bytes()[location.start()]
== b'\n' { 1 } else { 0 };
+ if location.source().content().as_bytes()[location.start()] == b'\n' {
1
} else {
0
};
report.labels.push(
Label::new((location.source(), start..location.end()))
.with_message("In evaluation of")

View file

@ -1,4 +1,5 @@
use super::layout::LayoutHolder;
use super::parser::ParseMode;
use super::parser::ParserState;
use super::source::Cursor;
use super::source::Source;
@ -73,7 +74,13 @@ pub trait Rule: Downcast {
fn previous(&self) -> Option<&'static str>;
/// 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
fn on_match<'a>(
&self,
@ -110,6 +117,9 @@ pub trait RegexRule {
/// Returns the rule's regexes
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
fn on_regex_match<'a>(
&self,
@ -127,13 +137,22 @@ pub trait RegexRule {
impl<T: RegexRule + 'static> Rule for T {
fn name(&self) -> &'static str { RegexRule::name(self) }
fn previous(&self) -> Option<&'static str> { RegexRule::previous(self) }
/// 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 mut found: Option<(usize, usize)> = None;
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) {
found = found
.map(|(f_pos, f_id)| {

View file

@ -60,7 +60,8 @@ macro_rules! impl_elementstyle {
serde_json::from_str::<$t>(json)
.map_err(|e| e.to_string())
.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::elements::paragraph::Paragraph;
use super::parser::ParseMode;
use super::parser::ParserState;
use super::source::Source;
@ -143,7 +144,7 @@ pub fn parse_paragraph<'a>(
let parsed = state.with_state(|new_state| -> Box<dyn Document> {
new_state
.parser
.parse(new_state, source.clone(), Some(document))
.parse(new_state, source.clone(), Some(document), ParseMode { paragraph_only: true })
.0
});
if parsed.content().borrow().len() > 1 {

View file

@ -10,6 +10,7 @@ use std::rc::Rc;
use dashmap::DashMap;
use parser::langparser::LangParser;
use parser::parser::ParseMode;
use parser::parser::Parser;
use parser::parser::ParserState;
use parser::source::SourceFile;
@ -42,7 +43,7 @@ impl Backend {
// Which will require a dyn Document to work
let source = Rc::new(SourceFile::with_content(params.uri.to_string(), params.text.clone(), None));
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()
{