use nom::branch::alt; use nom::bytes::complete::is_not; use nom::bytes::complete::tag_no_case; use nom::character::complete::anychar; use nom::character::complete::space1; use nom::combinator::map; use nom::multi::many0; use nom::multi::many_till; use nom::multi::separated_list0; use super::keyword::filtered_keyword; use super::keyword_todo::todo_keywords; use super::OrgSource; use crate::context::HeadlineLevelFilter; use crate::error::Res; use crate::types::Keyword; use crate::GlobalSettings; #[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))] pub(crate) fn scan_for_in_buffer_settings<'s>( input: OrgSource<'s>, ) -> Res, Vec>> { // TODO: Optimization idea: since this is slicing the OrgSource at each character, it might be more efficient to do a parser that uses a search function like take_until, and wrap it in a function similar to consumed but returning the input along with the normal output, then pass all of that into a verify that confirms we were at the start of a line using the input we just returned. let keywords = many0(map( many_till(anychar, filtered_keyword(in_buffer_settings_key)), |(_, kw)| kw, ))(input); keywords } #[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))] fn in_buffer_settings_key<'s>(input: OrgSource<'s>) -> Res, OrgSource<'s>> { alt(( tag_no_case("archive"), tag_no_case("category"), tag_no_case("columns"), tag_no_case("filetags"), tag_no_case("link"), tag_no_case("priorities"), tag_no_case("property"), tag_no_case("seq_todo"), tag_no_case("setupfile"), tag_no_case("startup"), tag_no_case("tags"), tag_no_case("todo"), tag_no_case("typ_todo"), ))(input) } pub(crate) fn apply_in_buffer_settings<'g, 's, 'sf>( keywords: Vec>, original_settings: &'g GlobalSettings<'g, 's>, ) -> Result, String> { let mut new_settings = original_settings.clone(); // Todo Keywords for kw in keywords.iter().filter(|kw| { kw.key.eq_ignore_ascii_case("todo") || kw.key.eq_ignore_ascii_case("seq_todo") || kw.key.eq_ignore_ascii_case("typ_todo") }) { let (_, (in_progress_words, complete_words)) = todo_keywords(kw.value).map_err(|err| err.to_string())?; new_settings .in_progress_todo_keywords .extend(in_progress_words.into_iter().map(str::to_string)); new_settings .complete_todo_keywords .extend(complete_words.into_iter().map(str::to_string)); } // Startup settings for kw in keywords .iter() .filter(|kw| kw.key.eq_ignore_ascii_case("startup")) { let (_remaining, settings) = separated_list0(space1::<&str, nom::error::Error<_>>, is_not(" \t"))(kw.value) .map_err(|err: nom::Err<_>| err.to_string())?; if settings.contains(&"odd") { new_settings.odd_levels_only = HeadlineLevelFilter::Odd; } } Ok(new_settings) }