Merge branch 'keyword_constants'
This commit is contained in:
commit
a4381e5e39
@ -1,15 +1,27 @@
|
||||
use super::global_settings::EntityDefinition;
|
||||
|
||||
pub(crate) const DEFAULT_ORG_ELEMENT_PARSED_KEYWORDS: [&str; 1] = ["CAPTION"];
|
||||
/// Keywords that contain the standard set of objects (excluding footnote references).
|
||||
///
|
||||
/// Corresponds to org-element-parsed-keywords elisp variable.
|
||||
pub(crate) const ORG_ELEMENT_PARSED_KEYWORDS: [&str; 1] = ["CAPTION"];
|
||||
|
||||
pub(crate) const DEFAULT_ORG_ELEMENT_DUAL_KEYWORDS: [&str; 2] = ["CAPTION", "RESULTS"];
|
||||
/// Keywords that can have a secondary value in square brackets.
|
||||
///
|
||||
/// Corresponds to org-element-dual-keywords elisp variable.
|
||||
pub(crate) const ORG_ELEMENT_DUAL_KEYWORDS: [&str; 2] = ["CAPTION", "RESULTS"];
|
||||
|
||||
pub(crate) const DEFAULT_ORG_ELEMENT_AFFILIATED_KEYWORDS: [&str; 13] = [
|
||||
/// Keywords that can be affiliated with an element.
|
||||
///
|
||||
/// Corresponds to org-element-affiliated-keywords elisp variable.
|
||||
pub(crate) const ORG_ELEMENT_AFFILIATED_KEYWORDS: [&str; 13] = [
|
||||
"CAPTION", "DATA", "HEADER", "HEADERS", "LABEL", "NAME", "PLOT", "RESNAME", "RESULT",
|
||||
"RESULTS", "SOURCE", "SRCNAME", "TBLNAME",
|
||||
];
|
||||
|
||||
pub(crate) const DEFAULT_ORG_ELEMENT_KEYWORD_TRANSLATION_ALIST: [(&str, &str); 8] = [
|
||||
/// Mapping of keyword names.
|
||||
///
|
||||
/// Corresponds to org-element-keyword-translation-alist elisp variable.
|
||||
pub(crate) const ORG_ELEMENT_KEYWORD_TRANSLATION_ALIST: [(&str, &str); 8] = [
|
||||
("DATA", "NAME"),
|
||||
("LABEL", "NAME"),
|
||||
("RESNAME", "NAME"),
|
||||
|
@ -12,7 +12,6 @@ use crate::error::CustomError;
|
||||
use crate::error::Res;
|
||||
use crate::parser::OrgSource;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) enum ContextElement<'r, 's> {
|
||||
/// Stores a parser that indicates that children should exit upon matching an exit matcher.
|
||||
ExitMatcherNode(ExitMatcherNode<'r>),
|
||||
@ -34,15 +33,6 @@ pub(crate) struct ExitMatcherNode<'r> {
|
||||
pub(crate) class: ExitClass,
|
||||
}
|
||||
|
||||
impl<'r> std::fmt::Debug for ExitMatcherNode<'r> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let mut formatter = f.debug_struct("ExitMatcherNode");
|
||||
formatter.field("class", &self.class.to_string());
|
||||
formatter.finish()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct Context<'g, 'r, 's> {
|
||||
global_settings: &'g GlobalSettings<'g, 's>,
|
||||
tree: List<'r, &'r ContextElement<'r, 's>>,
|
||||
|
@ -1,13 +1,7 @@
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
#[derive(Copy, Clone)]
|
||||
pub(crate) enum ExitClass {
|
||||
Document = 1,
|
||||
Alpha = 2,
|
||||
Beta = 3,
|
||||
Gamma = 4,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for ExitClass {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
write!(f, "{:?}", self)
|
||||
}
|
||||
}
|
||||
|
@ -1,17 +1,16 @@
|
||||
use std::fmt::Debug;
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[cfg(any(feature = "compare", feature = "foreign_document_test"))]
|
||||
pub trait FileAccessInterface: Sync + Debug {
|
||||
pub trait FileAccessInterface: Sync {
|
||||
fn read_file(&self, path: &str) -> Result<String, std::io::Error>;
|
||||
}
|
||||
|
||||
#[cfg(not(any(feature = "compare", feature = "foreign_document_test")))]
|
||||
pub trait FileAccessInterface: Debug {
|
||||
pub trait FileAccessInterface {
|
||||
fn read_file(&self, path: &str) -> Result<String, std::io::Error>;
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Clone)]
|
||||
pub struct LocalFileAccessInterface {
|
||||
pub working_directory: Option<PathBuf>,
|
||||
}
|
||||
|
@ -5,16 +5,12 @@ use super::constants::DEFAULT_ORG_ENTITIES;
|
||||
use super::constants::DEFAULT_ORG_LINK_PARAMETERS;
|
||||
use super::FileAccessInterface;
|
||||
use super::LocalFileAccessInterface;
|
||||
use crate::context::constants::DEFAULT_ORG_ELEMENT_AFFILIATED_KEYWORDS;
|
||||
use crate::context::constants::DEFAULT_ORG_ELEMENT_DUAL_KEYWORDS;
|
||||
use crate::context::constants::DEFAULT_ORG_ELEMENT_KEYWORD_TRANSLATION_ALIST;
|
||||
use crate::context::constants::DEFAULT_ORG_ELEMENT_PARSED_KEYWORDS;
|
||||
use crate::types::IndentationLevel;
|
||||
use crate::types::Object;
|
||||
|
||||
// TODO: Ultimately, I think we'll need most of this: https://orgmode.org/manual/In_002dbuffer-Settings.html
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Clone)]
|
||||
pub struct GlobalSettings<'g, 's> {
|
||||
pub radio_targets: Vec<&'g Vec<Object<'s>>>,
|
||||
pub file_access: &'g dyn FileAccessInterface,
|
||||
@ -58,26 +54,6 @@ pub struct GlobalSettings<'g, 's> {
|
||||
///
|
||||
/// Corresponds to org-entities elisp variable.
|
||||
pub entities: &'g [EntityDefinition<'s>],
|
||||
|
||||
/// Keywords that contain the standard set of objects (excluding footnote references).
|
||||
///
|
||||
/// Corresponds to org-element-parsed-keywords elisp variable.
|
||||
pub element_parsed_keywords: &'g [&'s str],
|
||||
|
||||
/// Keywords that can have a secondary value in square brackets.
|
||||
///
|
||||
/// Corresponds to org-element-dual-keywords elisp variable.
|
||||
pub element_dual_keywords: &'g [&'s str],
|
||||
|
||||
/// Keywords that can be affiliated with an element.
|
||||
///
|
||||
/// Corresponds to org-element-affiliated-keywords elisp variable.
|
||||
pub element_affiliated_keywords: &'g [&'s str],
|
||||
|
||||
/// Mapping of keyword names.
|
||||
///
|
||||
/// Corresponds to org-element-keyword-translation-alist elisp variable.
|
||||
pub element_keyword_translation_alist: &'g [(&'s str, &'s str)],
|
||||
}
|
||||
|
||||
pub const DEFAULT_TAB_WIDTH: IndentationLevel = 8;
|
||||
@ -112,10 +88,6 @@ impl<'g, 's> GlobalSettings<'g, 's> {
|
||||
link_parameters: &DEFAULT_ORG_LINK_PARAMETERS,
|
||||
link_templates: BTreeMap::new(),
|
||||
entities: &DEFAULT_ORG_ENTITIES,
|
||||
element_parsed_keywords: &DEFAULT_ORG_ELEMENT_PARSED_KEYWORDS,
|
||||
element_dual_keywords: &DEFAULT_ORG_ELEMENT_DUAL_KEYWORDS,
|
||||
element_affiliated_keywords: &DEFAULT_ORG_ELEMENT_AFFILIATED_KEYWORDS,
|
||||
element_keyword_translation_alist: &DEFAULT_ORG_ELEMENT_KEYWORD_TRANSLATION_ALIST,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -126,7 +98,7 @@ impl<'g, 's> Default for GlobalSettings<'g, 's> {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Default)]
|
||||
#[derive(Clone, PartialEq, Default)]
|
||||
pub enum HeadlineLevelFilter {
|
||||
Odd,
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
use crate::error::Res;
|
||||
use crate::parser::OrgSource;
|
||||
|
||||
mod constants;
|
||||
pub(crate) mod constants;
|
||||
#[allow(clippy::module_inception)]
|
||||
mod context;
|
||||
mod exiting;
|
||||
|
@ -19,29 +19,27 @@ use super::object_parser::standard_set_object;
|
||||
use super::util::confine_context;
|
||||
use super::OrgSource;
|
||||
use crate::context::bind_context;
|
||||
use crate::context::constants::ORG_ELEMENT_DUAL_KEYWORDS;
|
||||
use crate::context::constants::ORG_ELEMENT_KEYWORD_TRANSLATION_ALIST;
|
||||
use crate::context::constants::ORG_ELEMENT_PARSED_KEYWORDS;
|
||||
use crate::context::Context;
|
||||
use crate::context::ContextElement;
|
||||
use crate::context::GlobalSettings;
|
||||
use crate::context::List;
|
||||
use crate::context::RefContext;
|
||||
use crate::error::Res;
|
||||
use crate::types::AffiliatedKeywordValue;
|
||||
use crate::types::AffiliatedKeywords;
|
||||
use crate::types::Keyword;
|
||||
|
||||
#[cfg_attr(
|
||||
feature = "tracing",
|
||||
tracing::instrument(ret, level = "debug", skip(context))
|
||||
)]
|
||||
pub(crate) fn affiliated_keywords<'b, 'g, 'r, 's>(
|
||||
context: RefContext<'b, 'g, 'r, 's>,
|
||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||
pub(crate) fn affiliated_keywords<'s>(
|
||||
input: OrgSource<'s>,
|
||||
) -> Res<OrgSource<'s>, Vec<Keyword<'s>>> {
|
||||
let mut ret = Vec::new();
|
||||
let mut remaining = input;
|
||||
|
||||
loop {
|
||||
let result = affiliated_keyword(context, remaining);
|
||||
let result = affiliated_keyword(remaining);
|
||||
match result {
|
||||
Ok((remain, kw)) => {
|
||||
remaining = remain;
|
||||
@ -65,8 +63,8 @@ where
|
||||
{
|
||||
let mut ret = BTreeMap::new();
|
||||
for kw in input {
|
||||
let translated_name = translate_name(global_settings, kw.key);
|
||||
let keyword_type = identify_keyword_type(global_settings, translated_name.as_str());
|
||||
let translated_name = translate_name(kw.key);
|
||||
let keyword_type = identify_keyword_type(translated_name.as_str());
|
||||
match keyword_type {
|
||||
AffiliatedKeywordType::SingleString => {
|
||||
ret.insert(
|
||||
@ -151,12 +149,12 @@ where
|
||||
AffiliatedKeywords { keywords: ret }
|
||||
}
|
||||
|
||||
fn translate_name<'g, 's>(global_settings: &'g GlobalSettings<'g, 's>, name: &'s str) -> String {
|
||||
fn translate_name(name: &str) -> String {
|
||||
let name_until_optval = name
|
||||
.split_once('[')
|
||||
.map(|(before, _after)| before)
|
||||
.unwrap_or(name);
|
||||
for (src, dst) in global_settings.element_keyword_translation_alist {
|
||||
for (src, dst) in ORG_ELEMENT_KEYWORD_TRANSLATION_ALIST {
|
||||
if name_until_optval.eq_ignore_ascii_case(src) {
|
||||
return dst.to_lowercase();
|
||||
}
|
||||
@ -171,20 +169,15 @@ enum AffiliatedKeywordType {
|
||||
ObjectTree,
|
||||
}
|
||||
|
||||
fn identify_keyword_type<'g, 's>(
|
||||
global_settings: &'g GlobalSettings<'g, 's>,
|
||||
name: &'s str,
|
||||
) -> AffiliatedKeywordType {
|
||||
fn identify_keyword_type(name: &str) -> AffiliatedKeywordType {
|
||||
let is_multiple = ["CAPTION", "HEADER"]
|
||||
.into_iter()
|
||||
.any(|candidate| name.eq_ignore_ascii_case(candidate))
|
||||
|| name.to_lowercase().starts_with("attr_");
|
||||
let is_parsed = global_settings
|
||||
.element_parsed_keywords
|
||||
let is_parsed = ORG_ELEMENT_PARSED_KEYWORDS
|
||||
.iter()
|
||||
.any(|candidate| name.eq_ignore_ascii_case(candidate));
|
||||
let can_have_optval = global_settings
|
||||
.element_dual_keywords
|
||||
let can_have_optval = ORG_ELEMENT_DUAL_KEYWORDS
|
||||
.iter()
|
||||
.any(|candidate| name.eq_ignore_ascii_case(candidate));
|
||||
match (is_multiple, is_parsed, can_have_optval) {
|
||||
|
@ -59,8 +59,7 @@ fn _element<'b, 'g, 'r, 's>(
|
||||
) -> Res<OrgSource<'s>, Element<'s>> {
|
||||
#[cfg(feature = "event_count")]
|
||||
record_event(EventType::ElementStart, input);
|
||||
let (post_affiliated_keywords_input, affiliated_keywords) =
|
||||
affiliated_keywords(context, input)?;
|
||||
let (post_affiliated_keywords_input, affiliated_keywords) = affiliated_keywords(input)?;
|
||||
|
||||
let mut affiliated_keywords = affiliated_keywords.into_iter();
|
||||
|
||||
@ -277,8 +276,7 @@ fn _detect_element<'b, 'g, 'r, 's>(
|
||||
input: OrgSource<'s>,
|
||||
can_be_paragraph: bool,
|
||||
) -> Res<OrgSource<'s>, ()> {
|
||||
let (post_affiliated_keywords_input, affiliated_keywords) =
|
||||
affiliated_keywords(context, input)?;
|
||||
let (post_affiliated_keywords_input, affiliated_keywords) = affiliated_keywords(input)?;
|
||||
|
||||
let mut affiliated_keywords = affiliated_keywords.into_iter();
|
||||
|
||||
|
@ -84,7 +84,10 @@ fn in_buffer_settings_key<'s>(input: OrgSource<'s>) -> Res<OrgSource<'s>, OrgSou
|
||||
))(input)
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "tracing", tracing::instrument(level = "debug"))]
|
||||
#[cfg_attr(
|
||||
feature = "tracing",
|
||||
tracing::instrument(level = "debug", skip(original_settings))
|
||||
)]
|
||||
pub(crate) fn apply_in_buffer_settings<'g, 's, 'sf>(
|
||||
keywords: Vec<Keyword<'sf>>,
|
||||
original_settings: &'g GlobalSettings<'g, 's>,
|
||||
|
@ -21,7 +21,8 @@ use super::org_source::OrgSource;
|
||||
use super::util::get_consumed;
|
||||
use super::util::maybe_consume_trailing_whitespace_if_not_exiting;
|
||||
use super::util::org_line_ending;
|
||||
use crate::context::bind_context;
|
||||
use crate::context::constants::ORG_ELEMENT_AFFILIATED_KEYWORDS;
|
||||
use crate::context::constants::ORG_ELEMENT_DUAL_KEYWORDS;
|
||||
use crate::context::RefContext;
|
||||
use crate::error::CustomError;
|
||||
use crate::error::Res;
|
||||
@ -98,11 +99,8 @@ where
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||
pub(crate) fn affiliated_keyword<'b, 'g, 'r, 's>(
|
||||
context: RefContext<'b, 'g, 'r, 's>,
|
||||
input: OrgSource<'s>,
|
||||
) -> Res<OrgSource<'s>, Keyword<'s>> {
|
||||
filtered_keyword(bind_context!(affiliated_key, context))(input)
|
||||
pub(crate) fn affiliated_keyword<'s>(input: OrgSource<'s>) -> Res<OrgSource<'s>, Keyword<'s>> {
|
||||
filtered_keyword(affiliated_key)(input)
|
||||
}
|
||||
|
||||
#[cfg_attr(
|
||||
@ -137,24 +135,18 @@ fn regular_keyword_key<'s>(input: OrgSource<'s>) -> Res<OrgSource<'s>, OrgSource
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||
fn affiliated_key<'b, 'g, 'r, 's>(
|
||||
context: RefContext<'b, 'g, 'r, 's>,
|
||||
input: OrgSource<'s>,
|
||||
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||
element!(dual_affiliated_key, context, input);
|
||||
element!(plain_affiliated_key, context, input);
|
||||
fn affiliated_key<'s>(input: OrgSource<'s>) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||
element!(dual_affiliated_key, input);
|
||||
element!(plain_affiliated_key, input);
|
||||
element!(export_keyword, input);
|
||||
Err(nom::Err::Error(CustomError::Static("No affiliated key.")))
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||
fn plain_affiliated_key<'b, 'g, 'r, 's>(
|
||||
context: RefContext<'b, 'g, 'r, 's>,
|
||||
input: OrgSource<'s>,
|
||||
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||
for keyword in context.get_global_settings().element_affiliated_keywords {
|
||||
fn plain_affiliated_key<'s>(input: OrgSource<'s>) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||
for keyword in ORG_ELEMENT_AFFILIATED_KEYWORDS {
|
||||
let result = map(
|
||||
tuple((tag_no_case::<_, _, CustomError>(*keyword), peek(tag(":")))),
|
||||
tuple((tag_no_case::<_, _, CustomError>(keyword), peek(tag(":")))),
|
||||
|(key, _)| key,
|
||||
)(input);
|
||||
if let Ok((remaining, ent)) = result {
|
||||
@ -166,13 +158,10 @@ fn plain_affiliated_key<'b, 'g, 'r, 's>(
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||
fn dual_affiliated_key<'b, 'g, 'r, 's>(
|
||||
context: RefContext<'b, 'g, 'r, 's>,
|
||||
input: OrgSource<'s>,
|
||||
) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||
for keyword in context.get_global_settings().element_dual_keywords {
|
||||
fn dual_affiliated_key<'s>(input: OrgSource<'s>) -> Res<OrgSource<'s>, OrgSource<'s>> {
|
||||
for keyword in ORG_ELEMENT_DUAL_KEYWORDS {
|
||||
let result = recognize(tuple((
|
||||
tag_no_case::<_, _, CustomError>(*keyword),
|
||||
tag_no_case::<_, _, CustomError>(keyword),
|
||||
tag("["),
|
||||
optval,
|
||||
tag("]"),
|
||||
@ -232,19 +221,12 @@ mod tests {
|
||||
use test::Bencher;
|
||||
|
||||
use super::*;
|
||||
use crate::context::Context;
|
||||
use crate::context::ContextElement;
|
||||
use crate::context::GlobalSettings;
|
||||
use crate::context::List;
|
||||
use crate::parser::OrgSource;
|
||||
|
||||
#[bench]
|
||||
fn bench_affiliated_keyword(b: &mut Bencher) {
|
||||
let input = OrgSource::new("#+CAPTION[*foo*]: bar *baz*");
|
||||
let global_settings = GlobalSettings::default();
|
||||
let initial_context = ContextElement::document_context();
|
||||
let initial_context = Context::new(&global_settings, List::new(&initial_context));
|
||||
|
||||
b.iter(|| assert!(affiliated_keyword(&initial_context, input).is_ok()));
|
||||
b.iter(|| assert!(affiliated_keyword(input).is_ok()));
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user