Docs
This commit is contained in:
parent
ac8862e459
commit
347fd6ce59
8 changed files with 65 additions and 27 deletions
4
src/cache/cache.rs
vendored
4
src/cache/cache.rs
vendored
|
@ -33,9 +33,9 @@ pub trait Cached {
|
||||||
/// # Error
|
/// # Error
|
||||||
///
|
///
|
||||||
/// Will return an error if the database connection(s) fail,
|
/// Will return an error if the database connection(s) fail,
|
||||||
/// or if not cached, an error from the generator [`f`]
|
/// or if not cached, an error from the generator `f`
|
||||||
///
|
///
|
||||||
/// Note that on error, [`f`] may still have been called
|
/// Note that on error, `f` may still have been called
|
||||||
fn cached<E, F>(
|
fn cached<E, F>(
|
||||||
&self,
|
&self,
|
||||||
con: &Connection,
|
con: &Connection,
|
||||||
|
|
|
@ -300,7 +300,7 @@ pub struct CompiledDocument {
|
||||||
pub variables: HashMap<String, String>,
|
pub variables: HashMap<String, String>,
|
||||||
|
|
||||||
/// All the referenceable elements in the document
|
/// All the referenceable elements in the document
|
||||||
/// with values mapped by [`ReferenceableElement::refid()`]
|
/// with values mapped by [`crate::document::element::ReferenceableElement::refid()`]
|
||||||
pub references: HashMap<String, String>,
|
pub references: HashMap<String, String>,
|
||||||
|
|
||||||
/// Compiled document's header
|
/// Compiled document's header
|
||||||
|
|
|
@ -177,11 +177,11 @@ pub trait Document<'a>: core::fmt::Debug {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Merges [`other`] into [`self`]
|
/// Merges another [`Document`]'s scope into [`self`]
|
||||||
///
|
///
|
||||||
/// # Parameters
|
/// # Parameters
|
||||||
///
|
///
|
||||||
/// If [`merge_as`] is None, references and variables from the other document are not merged into self
|
/// If `merge_as` is None, references and variables from the other document are not merged into self
|
||||||
fn merge(
|
fn merge(
|
||||||
&self,
|
&self,
|
||||||
content: &RefCell<Vec<Box<dyn Element>>>,
|
content: &RefCell<Vec<Box<dyn Element>>>,
|
||||||
|
|
|
@ -180,7 +180,7 @@ impl<'a, 'b> ParserState<'a, 'b> {
|
||||||
/// 2. (Optional) The winning match with it's match data
|
/// 2. (Optional) The winning match with it's match data
|
||||||
/// If the winning match is None, it means that the document has no more
|
/// If the winning match is None, it means that the document has no more
|
||||||
/// rule to match. I.e The rest of the content should be added as a
|
/// rule to match. I.e The rest of the content should be added as a
|
||||||
/// [`Text`] element.
|
/// [`crate::elements::text::Text`] element.
|
||||||
/// The match data should be passed to the [`Rule::on_match`] method.
|
/// The match data should be passed to the [`Rule::on_match`] method.
|
||||||
///
|
///
|
||||||
/// # Strategy
|
/// # Strategy
|
||||||
|
@ -298,13 +298,13 @@ impl<'a, 'b> ParserState<'a, 'b> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Resets the position and the match_data for a given rule. This is used
|
/// Resets the position and the match_data for a given rule. This is used
|
||||||
/// in order to have 'dynamic' rules that may not match at first, but their
|
/// in order to have 'dynamic' rules that may not match at first, but may match
|
||||||
/// matching rule is modified through the parsing process.
|
/// in the future when modified.
|
||||||
///
|
///
|
||||||
/// This function also recursively calls itself on it's `parent`, in order
|
/// This function also recursively calls itself on it's `parent`, in order
|
||||||
/// to fully reset the match.
|
/// to fully reset the match.
|
||||||
///
|
///
|
||||||
/// See [`CustomStyleRule`] for an example of how this is used.
|
/// See [`crate::elements::customstyle::CustomStyleRule`] for an example of how this is used.
|
||||||
///
|
///
|
||||||
/// # Error
|
/// # Error
|
||||||
///
|
///
|
||||||
|
|
|
@ -70,7 +70,7 @@ pub trait Rule: Downcast {
|
||||||
/// The name of the rule that should come before this one
|
/// The name of the rule that should come before this one
|
||||||
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(
|
fn next_match(
|
||||||
&self,
|
&self,
|
||||||
mode: &ParseMode,
|
mode: &ParseMode,
|
||||||
|
@ -137,7 +137,7 @@ impl<T: RegexRule + 'static> Rule for T {
|
||||||
|
|
||||||
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(
|
fn next_match(
|
||||||
&self,
|
&self,
|
||||||
mode: &ParseMode,
|
mode: &ParseMode,
|
||||||
|
|
|
@ -10,8 +10,13 @@ use unicode_segmentation::UnicodeSegmentation;
|
||||||
/// Trait for source content
|
/// Trait for source content
|
||||||
pub trait Source: Downcast + Debug {
|
pub trait Source: Downcast + Debug {
|
||||||
/// Gets the source's location
|
/// Gets the source's location
|
||||||
|
///
|
||||||
|
/// This usually means the parent source.
|
||||||
|
/// If the source is a [`SourceFile`], this generally means the [`SourceFile`] that included it.
|
||||||
fn location(&self) -> Option<&Token>;
|
fn location(&self) -> Option<&Token>;
|
||||||
/// Gets the source's name
|
/// Gets the source's name
|
||||||
|
///
|
||||||
|
/// For [`SourceFile`] this means the path of the source. Note that some [`VirtualSource`] are prefixed with a special identifier such as `:LUA:`.
|
||||||
fn name(&self) -> &String;
|
fn name(&self) -> &String;
|
||||||
/// Gets the source's content
|
/// Gets the source's content
|
||||||
fn content(&self) -> &String;
|
fn content(&self) -> &String;
|
||||||
|
@ -37,13 +42,19 @@ impl std::hash::Hash for dyn Source {
|
||||||
/// [`SourceFile`] is a type of [`Source`] that represents a real file.
|
/// [`SourceFile`] is a type of [`Source`] that represents a real file.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct SourceFile {
|
pub struct SourceFile {
|
||||||
|
/// The token that created this [`SourceFile`], empty if file comes from the executable's
|
||||||
|
/// options.
|
||||||
location: Option<Token>,
|
location: Option<Token>,
|
||||||
|
/// Path to the file, used for the [`Self::name()`] method
|
||||||
path: String,
|
path: String,
|
||||||
|
/// Content of the file
|
||||||
content: String,
|
content: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SourceFile {
|
impl SourceFile {
|
||||||
// TODO: Create a SourceFileRegistry holding already loaded files to avoid reloading them
|
// TODO: Create a SourceFileRegistry holding already loaded files to avoid reloading them
|
||||||
|
/// Creates a [`SourceFile`] from a `path`. This will read the content of the file at that
|
||||||
|
/// `path`. In case the file is not accessible or reading fails, an error is returned.
|
||||||
pub fn new(path: String, location: Option<Token>) -> Result<Self, String> {
|
pub fn new(path: String, location: Option<Token>) -> Result<Self, String> {
|
||||||
match fs::read_to_string(&path) {
|
match fs::read_to_string(&path) {
|
||||||
Err(_) => Err(format!("Unable to read file content: `{}`", path)),
|
Err(_) => Err(format!("Unable to read file content: `{}`", path)),
|
||||||
|
@ -55,6 +66,7 @@ impl SourceFile {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates a [`SourceFile`] from a `String`
|
||||||
pub fn with_content(path: String, content: String, location: Option<Token>) -> Self {
|
pub fn with_content(path: String, content: String, location: Option<Token>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
location,
|
location,
|
||||||
|
@ -63,6 +75,7 @@ impl SourceFile {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Gets the path of this [`SourceFile`]
|
||||||
pub fn path(&self) -> &String { &self.path }
|
pub fn path(&self) -> &String { &self.path }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,8 +92,8 @@ impl Source for SourceFile {
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// Let's say you make a virtual source from the following: "Con\]tent" -> "Con]tent"
|
/// Let's say you make a virtual source from the following: "Con\\]tent" -> "Con]tent"
|
||||||
/// Then at position 3, an offset of 1 will be created to account for the removed '\'
|
/// Then at position 3, an offset of 1 will be created to account for the removed '\\'
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct SourceOffset {
|
struct SourceOffset {
|
||||||
/// Stores the total offsets
|
/// Stores the total offsets
|
||||||
|
@ -105,16 +118,25 @@ impl SourceOffset {
|
||||||
|
|
||||||
/// [`VirtualSource`] is a type of [`Source`] that represents a virtual file. [`VirtualSource`]s
|
/// [`VirtualSource`] is a type of [`Source`] that represents a virtual file. [`VirtualSource`]s
|
||||||
/// can be created from other [`VirtualSource`]s but it must always come from a [`SourceFile`].
|
/// can be created from other [`VirtualSource`]s but it must always come from a [`SourceFile`].
|
||||||
|
///
|
||||||
|
/// # Offsets
|
||||||
|
///
|
||||||
|
/// [`VirtualSource`] will keep a list of offsets that were applied from the their parent source (available via [`Self::location`]).
|
||||||
|
/// For instance, if you consider the [`VirtualSource`] created by removing the '\\' from the following string: "He\\llo", then an offset is stored to account for the missing '\\'. This is required in order to keep diagnostics accurate.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct VirtualSource {
|
pub struct VirtualSource {
|
||||||
|
/// Token that createrd this [`VirtualSource`]
|
||||||
location: Token,
|
location: Token,
|
||||||
|
/// Name of the [`VirtualSource`]
|
||||||
name: String,
|
name: String,
|
||||||
|
/// Content of the [`VirtualSource`]
|
||||||
content: String,
|
content: String,
|
||||||
/// Offset relative to the [`location`]'s source
|
/// Offsets relative to the [`Self::location`]'s source
|
||||||
offsets: Option<SourceOffset>,
|
offsets: Option<SourceOffset>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VirtualSource {
|
impl VirtualSource {
|
||||||
|
/// Creates a new [`VirtualSource`] from a `location`, `name` and `content`.
|
||||||
pub fn new(location: Token, name: String, content: String) -> Self {
|
pub fn new(location: Token, name: String, content: String) -> Self {
|
||||||
Self {
|
Self {
|
||||||
location,
|
location,
|
||||||
|
@ -124,6 +146,11 @@ impl VirtualSource {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates a new [`VirtualSource`] from a `location`, `name`, `content` and `offsets`.
|
||||||
|
///
|
||||||
|
/// # Notes
|
||||||
|
///
|
||||||
|
/// This should be called by [`crate::parser::util::escape_source`]
|
||||||
pub fn new_offsets(
|
pub fn new_offsets(
|
||||||
location: Token,
|
location: Token,
|
||||||
name: String,
|
name: String,
|
||||||
|
@ -233,7 +260,7 @@ pub struct Cursor {
|
||||||
impl Cursor {
|
impl Cursor {
|
||||||
pub fn new(pos: usize, source: Rc<dyn Source>) -> Self { Self { pos, source } }
|
pub fn new(pos: usize, source: Rc<dyn Source>) -> Self { Self { pos, source } }
|
||||||
|
|
||||||
/// Creates [`cursor`] at [`new_pos`] in the same [`file`]
|
/// Creates [`Cursor`] at `new_pos` in the same [`Source`]
|
||||||
pub fn at(&self, new_pos: usize) -> Self {
|
pub fn at(&self, new_pos: usize) -> Self {
|
||||||
Self {
|
Self {
|
||||||
pos: new_pos,
|
pos: new_pos,
|
||||||
|
@ -246,7 +273,7 @@ impl Cursor {
|
||||||
///
|
///
|
||||||
/// # Notes
|
/// # Notes
|
||||||
///
|
///
|
||||||
/// Because the LSP uses UTF-16 encoded positions, field [`line_pos`] corresponds to the UTF-16
|
/// Because the LSP uses UTF-16 encoded positions, field [`Self::line_pos`] corresponds to the UTF-16
|
||||||
/// distance between the first character (position = 0 or after '\n') and the character at the
|
/// distance between the first character (position = 0 or after '\n') and the character at the
|
||||||
/// current position.
|
/// current position.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
@ -273,10 +300,11 @@ impl LineCursor {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Moves [`LineCursor`] to an absolute byte position
|
/// Moves [`LineCursor`] to an absolute byte position
|
||||||
|
/// This function may only advance the position, as is required for the LSP semantics.
|
||||||
///
|
///
|
||||||
/// # Error
|
/// # Error
|
||||||
///
|
///
|
||||||
/// This function will panic if [`pos`] is not utf8 aligned
|
/// This function will panic if [`Self::pos`] is not UTF-88 aligned, or if trying to go to a previous position.
|
||||||
pub fn move_to(&mut self, pos: usize) {
|
pub fn move_to(&mut self, pos: usize) {
|
||||||
if self.pos < pos {
|
if self.pos < pos {
|
||||||
let start = self.pos;
|
let start = self.pos;
|
||||||
|
|
|
@ -5,18 +5,20 @@ use downcast_rs::impl_downcast;
|
||||||
use downcast_rs::Downcast;
|
use downcast_rs::Downcast;
|
||||||
|
|
||||||
/// Styling for an element
|
/// Styling for an element
|
||||||
|
///
|
||||||
|
/// Some elements have support for styling.
|
||||||
pub trait ElementStyle: Downcast + core::fmt::Debug {
|
pub trait ElementStyle: Downcast + core::fmt::Debug {
|
||||||
/// The style key
|
/// The style key
|
||||||
fn key(&self) -> &'static str;
|
fn key(&self) -> &'static str;
|
||||||
|
|
||||||
/// Attempts to create a new style from a [`json`] string
|
/// Attempts to create a new style from a `json` string
|
||||||
///
|
///
|
||||||
/// # Errors
|
/// # Errors
|
||||||
///
|
///
|
||||||
/// Will fail if deserialization fails
|
/// Will fail if deserialization fails
|
||||||
fn from_json(&self, json: &str) -> Result<Rc<dyn ElementStyle>, String>;
|
fn from_json(&self, json: &str) -> Result<Rc<dyn ElementStyle>, String>;
|
||||||
|
|
||||||
/// Attempts to deserialize lua table into a new style
|
/// Attempts to deserialize a `lua table` into a new style
|
||||||
fn from_lua(
|
fn from_lua(
|
||||||
&self,
|
&self,
|
||||||
lua: &mlua::Lua,
|
lua: &mlua::Lua,
|
||||||
|
@ -25,6 +27,7 @@ pub trait ElementStyle: Downcast + core::fmt::Debug {
|
||||||
}
|
}
|
||||||
impl_downcast!(ElementStyle);
|
impl_downcast!(ElementStyle);
|
||||||
|
|
||||||
|
/// A structure that holds registered [`ElementStyle`]
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct StyleHolder {
|
pub struct StyleHolder {
|
||||||
styles: HashMap<String, Rc<dyn ElementStyle>>,
|
styles: HashMap<String, Rc<dyn ElementStyle>>,
|
||||||
|
@ -35,13 +38,17 @@ impl StyleHolder {
|
||||||
pub fn is_registered(&self, style_key: &str) -> bool { self.styles.contains_key(style_key) }
|
pub fn is_registered(&self, style_key: &str) -> bool { self.styles.contains_key(style_key) }
|
||||||
|
|
||||||
/// Gets the current active style for an element
|
/// Gets the current active style for an element
|
||||||
/// NOTE: Will panic if a style is not defined for a given element
|
/// If you need to process user input, use [`Self::is_registered`]
|
||||||
/// If you need to process user input, use [`is_registered`]
|
///
|
||||||
|
/// # Notes
|
||||||
|
///
|
||||||
|
/// Will panic if a style is not defined for a given element.
|
||||||
|
/// Elements should have their styles (when they support it) registered when the parser starts.
|
||||||
pub fn current(&self, style_key: &str) -> Rc<dyn ElementStyle> {
|
pub fn current(&self, style_key: &str) -> Rc<dyn ElementStyle> {
|
||||||
self.styles.get(style_key).cloned().unwrap()
|
self.styles.get(style_key).cloned().unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the [`style`]
|
/// Sets the style
|
||||||
pub fn set_current(&mut self, style: Rc<dyn ElementStyle>) {
|
pub fn set_current(&mut self, style: Rc<dyn ElementStyle>) {
|
||||||
self.styles.insert(style.key().to_string(), style);
|
self.styles.insert(style.key().to_string(), style);
|
||||||
}
|
}
|
||||||
|
|
|
@ -90,12 +90,15 @@ pub fn process_text(document: &dyn Document, content: &str) -> String {
|
||||||
processed
|
processed
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Transforms source into a new [`VirtualSource`]. Transforms range from source by
|
/// Transforms source into a new [`VirtualSource`] using a `range`.
|
||||||
/// detecting escaped tokens.
|
///
|
||||||
|
/// This function will extract the sub-source using the specified `range`, then escape `token` using the specified `escape` character.
|
||||||
|
/// It will also keep a list of removed/added characters and build an offset list that will be passed to the newly created source, via [`VirtualSource::new_offsets`].
|
||||||
|
///
|
||||||
///
|
///
|
||||||
/// # Notes
|
/// # Notes
|
||||||
///
|
///
|
||||||
/// If you only need to escape content that won't be parsed, use [`process_escaped`] instead.
|
/// If you only need to escape content that won't be parsed, use [`escape_text`] instead.
|
||||||
pub fn escape_source(
|
pub fn escape_source(
|
||||||
source: Rc<dyn Source>,
|
source: Rc<dyn Source>,
|
||||||
range: Range<usize>,
|
range: Range<usize>,
|
||||||
|
@ -147,11 +150,11 @@ pub fn escape_source(
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Processed a string and escapes a single token out of it
|
/// Processed a string and escapes a single token out of it
|
||||||
/// Escaped characters other than the [`token`] will be not be treated as escaped
|
/// Escaped characters other than the [`Token`] will be not be treated as escaped
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```
|
/// ```
|
||||||
/// assert_eq!(process_escaped('\\', "%", "escaped: \\%, also escaped: \\\\\\%, untouched: \\a"),
|
/// assert_eq!(scape_text('\\', "%", "escaped: \\%, also escaped: \\\\\\%, untouched: \\a"),
|
||||||
/// "escaped: %, also escaped: \\%, untouched: \\a");
|
/// "escaped: %, also escaped: \\%, untouched: \\a");
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
|
|
Loading…
Reference in a new issue