Handle orgifying text in regular link path and raw-link.
This commit is contained in:
parent
51748afd41
commit
d126488891
@ -4,6 +4,9 @@
|
|||||||
|
|
||||||
[[((baz)]]
|
[[((baz)]]
|
||||||
|
|
||||||
|
[[(lo
|
||||||
|
rem)]]
|
||||||
|
|
||||||
# These become fuzzy
|
# These become fuzzy
|
||||||
[[(foo) ]]
|
[[(foo) ]]
|
||||||
[[ (foo)]]
|
[[ (foo)]]
|
||||||
|
@ -1 +1,4 @@
|
|||||||
[[#foo]]
|
[[#foo]]
|
||||||
|
|
||||||
|
[[#fo
|
||||||
|
o]]
|
||||||
|
@ -1 +1,4 @@
|
|||||||
[[file:simple.org]]
|
[[file:simple.org]]
|
||||||
|
|
||||||
|
[[file:simp
|
||||||
|
le.org]]
|
||||||
|
@ -1 +1,4 @@
|
|||||||
[[elisp.org]]
|
[[elisp.org]]
|
||||||
|
|
||||||
|
[[eli
|
||||||
|
sp.org]]
|
||||||
|
@ -1 +1,4 @@
|
|||||||
[[id:83986bdf-987c-465d-8851-44cb4c02a86c]]
|
[[id:83986bdf-987c-465d-8851-44cb4c02a86c]]
|
||||||
|
|
||||||
|
[[id:83986bdf-987c-465d
|
||||||
|
-8851-44cb4c02a86c]]
|
||||||
|
@ -1 +1,4 @@
|
|||||||
[[shell:foo]]
|
[[shell:foo]]
|
||||||
|
|
||||||
|
[[shell:fo
|
||||||
|
o]]
|
||||||
|
@ -2,7 +2,9 @@ use std::fmt::Debug;
|
|||||||
|
|
||||||
use super::diff::DiffStatus;
|
use super::diff::DiffStatus;
|
||||||
use super::sexp::Token;
|
use super::sexp::Token;
|
||||||
|
use super::util::get_property;
|
||||||
use super::util::get_property_quoted_string;
|
use super::util::get_property_quoted_string;
|
||||||
|
use super::util::get_property_unquoted_atom;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(crate) enum EmacsField<'s> {
|
pub(crate) enum EmacsField<'s> {
|
||||||
@ -32,6 +34,28 @@ pub(crate) fn compare_identity() -> () {
|
|||||||
()
|
()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Assert that the emacs value is always nil or absent.
|
||||||
|
///
|
||||||
|
/// This is usually used for fields which, in my testing, are always nil. Using this compare function instead of simply doing a compare_noop will enable us to be alerted when we finally come across an org-mode document that has a value other than nil for the property.
|
||||||
|
pub(crate) fn compare_property_always_nil<'b, 's, 'x, R, RG>(
|
||||||
|
emacs: &'b Token<'s>,
|
||||||
|
_rust_node: R,
|
||||||
|
emacs_field: &'x str,
|
||||||
|
_rust_value_getter: RG,
|
||||||
|
) -> Result<Option<(DiffStatus, Option<String>)>, Box<dyn std::error::Error>> {
|
||||||
|
let value = get_property(emacs, emacs_field)?;
|
||||||
|
if value.is_some() {
|
||||||
|
let this_status = DiffStatus::Bad;
|
||||||
|
let message = Some(format!(
|
||||||
|
"{} was expected to always be nil: {:?}",
|
||||||
|
emacs_field, value
|
||||||
|
));
|
||||||
|
Ok(Some((this_status, message)))
|
||||||
|
} else {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn compare_property_quoted_string<'b, 's, 'x, R, RG: Fn(R) -> Option<&'s str>>(
|
pub(crate) fn compare_property_quoted_string<'b, 's, 'x, R, RG: Fn(R) -> Option<&'s str>>(
|
||||||
emacs: &'b Token<'s>,
|
emacs: &'b Token<'s>,
|
||||||
rust_node: R,
|
rust_node: R,
|
||||||
@ -40,7 +64,47 @@ pub(crate) fn compare_property_quoted_string<'b, 's, 'x, R, RG: Fn(R) -> Option<
|
|||||||
) -> Result<Option<(DiffStatus, Option<String>)>, Box<dyn std::error::Error>> {
|
) -> Result<Option<(DiffStatus, Option<String>)>, Box<dyn std::error::Error>> {
|
||||||
let value = get_property_quoted_string(emacs, emacs_field)?;
|
let value = get_property_quoted_string(emacs, emacs_field)?;
|
||||||
let rust_value = rust_value_getter(rust_node);
|
let rust_value = rust_value_getter(rust_node);
|
||||||
if !rust_value.eq(&value.as_ref().map(String::as_str)) {
|
if rust_value != value.as_ref().map(String::as_str) {
|
||||||
|
let this_status = DiffStatus::Bad;
|
||||||
|
let message = Some(format!(
|
||||||
|
"{} mismatch (emacs != rust) {:?} != {:?}",
|
||||||
|
emacs_field, value, rust_value
|
||||||
|
));
|
||||||
|
Ok(Some((this_status, message)))
|
||||||
|
} else {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn compare_property_quoted_string_owned<'b, 's, 'x, R, RG: Fn(R) -> Option<String>>(
|
||||||
|
emacs: &'b Token<'s>,
|
||||||
|
rust_node: R,
|
||||||
|
emacs_field: &'x str,
|
||||||
|
rust_value_getter: RG,
|
||||||
|
) -> Result<Option<(DiffStatus, Option<String>)>, Box<dyn std::error::Error>> {
|
||||||
|
let value = get_property_quoted_string(emacs, emacs_field)?;
|
||||||
|
let rust_value = rust_value_getter(rust_node);
|
||||||
|
if rust_value != value {
|
||||||
|
let this_status = DiffStatus::Bad;
|
||||||
|
let message = Some(format!(
|
||||||
|
"{} mismatch (emacs != rust) {:?} != {:?}",
|
||||||
|
emacs_field, value, rust_value
|
||||||
|
));
|
||||||
|
Ok(Some((this_status, message)))
|
||||||
|
} else {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn compare_property_unquoted_atom<'b, 's, 'x, R, RG: Fn(R) -> Option<&'s str>>(
|
||||||
|
emacs: &'b Token<'s>,
|
||||||
|
rust_node: R,
|
||||||
|
emacs_field: &'x str,
|
||||||
|
rust_value_getter: RG,
|
||||||
|
) -> Result<Option<(DiffStatus, Option<String>)>, Box<dyn std::error::Error>> {
|
||||||
|
let value = get_property_unquoted_atom(emacs, emacs_field)?;
|
||||||
|
let rust_value = rust_value_getter(rust_node);
|
||||||
|
if rust_value != value {
|
||||||
let this_status = DiffStatus::Bad;
|
let this_status = DiffStatus::Bad;
|
||||||
let message = Some(format!(
|
let message = Some(format!(
|
||||||
"{} mismatch (emacs != rust) {:?} != {:?}",
|
"{} mismatch (emacs != rust) {:?} != {:?}",
|
||||||
|
@ -4,8 +4,10 @@ use std::collections::BTreeSet;
|
|||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
|
||||||
use super::compare_field::compare_identity;
|
use super::compare_field::compare_identity;
|
||||||
use super::compare_field::compare_noop;
|
use super::compare_field::compare_property_always_nil;
|
||||||
use super::compare_field::compare_property_quoted_string;
|
use super::compare_field::compare_property_quoted_string;
|
||||||
|
use super::compare_field::compare_property_quoted_string_owned;
|
||||||
|
use super::compare_field::compare_property_unquoted_atom;
|
||||||
use super::elisp_fact::ElispFact;
|
use super::elisp_fact::ElispFact;
|
||||||
use super::elisp_fact::GetElispFact;
|
use super::elisp_fact::GetElispFact;
|
||||||
use super::sexp::unquote;
|
use super::sexp::unquote;
|
||||||
@ -2783,28 +2785,28 @@ fn compare_regular_link<'b, 's>(
|
|||||||
),
|
),
|
||||||
(
|
(
|
||||||
EmacsField::Required(":path"),
|
EmacsField::Required(":path"),
|
||||||
|r| Some(r.path),
|
|r| Some(r.get_path()),
|
||||||
compare_property_quoted_string
|
compare_property_quoted_string_owned
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
EmacsField::Required(":format"),
|
EmacsField::Required(":format"),
|
||||||
compare_identity,
|
|_| Some("bracket"),
|
||||||
compare_noop
|
compare_property_unquoted_atom
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
EmacsField::Required(":raw-link"),
|
EmacsField::Required(":raw-link"),
|
||||||
|r| Some(r.raw_link),
|
|r| Some(r.get_raw_link()),
|
||||||
compare_property_quoted_string
|
compare_property_quoted_string_owned
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
EmacsField::Required(":application"),
|
EmacsField::Required(":application"),
|
||||||
compare_identity,
|
compare_identity,
|
||||||
compare_noop
|
compare_property_always_nil
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
EmacsField::Required(":search-option"),
|
EmacsField::Required(":search-option"),
|
||||||
compare_identity,
|
compare_identity,
|
||||||
compare_noop
|
compare_property_always_nil
|
||||||
)
|
)
|
||||||
)? {
|
)? {
|
||||||
this_status = new_status;
|
this_status = new_status;
|
||||||
|
@ -2,6 +2,7 @@ use nom::branch::alt;
|
|||||||
use nom::bytes::complete::escaped;
|
use nom::bytes::complete::escaped;
|
||||||
use nom::bytes::complete::tag;
|
use nom::bytes::complete::tag;
|
||||||
use nom::bytes::complete::take_till1;
|
use nom::bytes::complete::take_till1;
|
||||||
|
use nom::bytes::complete::take_until;
|
||||||
use nom::character::complete::anychar;
|
use nom::character::complete::anychar;
|
||||||
use nom::combinator::consumed;
|
use nom::combinator::consumed;
|
||||||
use nom::combinator::eof;
|
use nom::combinator::eof;
|
||||||
@ -116,6 +117,7 @@ fn parse_path_reg<'s>(input: OrgSource<'s>) -> Res<OrgSource<'s>, PathReg<'s>> {
|
|||||||
id_path_reg,
|
id_path_reg,
|
||||||
custom_id_path_reg,
|
custom_id_path_reg,
|
||||||
code_ref_path_reg,
|
code_ref_path_reg,
|
||||||
|
protocol_path_reg,
|
||||||
fuzzy_path_reg,
|
fuzzy_path_reg,
|
||||||
))(input)
|
))(input)
|
||||||
}
|
}
|
||||||
@ -172,6 +174,19 @@ fn code_ref_path_reg<'s>(input: OrgSource<'s>) -> Res<OrgSource<'s>, PathReg<'s>
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn protocol_path_reg<'s>(input: OrgSource<'s>) -> Res<OrgSource<'s>, PathReg<'s>> {
|
||||||
|
let (remaining, (raw_link, (protocol, _, path))) =
|
||||||
|
consumed(tuple((take_until(":"), tag(":"), rest)))(input)?;
|
||||||
|
Ok((
|
||||||
|
remaining,
|
||||||
|
PathReg {
|
||||||
|
link_type: LinkType::Protocol(protocol.into()),
|
||||||
|
path: path.into(),
|
||||||
|
raw_link: raw_link.into(),
|
||||||
|
},
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
fn fuzzy_path_reg<'s>(input: OrgSource<'s>) -> Res<OrgSource<'s>, PathReg<'s>> {
|
fn fuzzy_path_reg<'s>(input: OrgSource<'s>) -> Res<OrgSource<'s>, PathReg<'s>> {
|
||||||
let (remaining, body) = rest(input)?;
|
let (remaining, body) = rest(input)?;
|
||||||
Ok((
|
Ok((
|
||||||
|
@ -648,3 +648,45 @@ pub enum LinkType<'s> {
|
|||||||
CodeRef,
|
CodeRef,
|
||||||
Fuzzy,
|
Fuzzy,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
enum ParserState {
|
||||||
|
Normal,
|
||||||
|
InWhitespace,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Org-mode treats multiple consecutive whitespace characters as a single space. This function performs that transformation.
|
||||||
|
///
|
||||||
|
/// Example: `orgify_text("foo \t\n bar") == "foo bar"`
|
||||||
|
pub(crate) fn orgify_text<'s>(raw_text: &'s str) -> String {
|
||||||
|
let mut ret = String::with_capacity(raw_text.len());
|
||||||
|
let mut state = ParserState::Normal;
|
||||||
|
for c in raw_text.chars() {
|
||||||
|
state = match (&state, c) {
|
||||||
|
(ParserState::Normal, _) if " \t\r\n".contains(c) => {
|
||||||
|
ret.push(' ');
|
||||||
|
ParserState::InWhitespace
|
||||||
|
}
|
||||||
|
(ParserState::InWhitespace, _) if " \t\r\n".contains(c) => ParserState::InWhitespace,
|
||||||
|
(ParserState::Normal, _) => {
|
||||||
|
ret.push(c);
|
||||||
|
ParserState::Normal
|
||||||
|
}
|
||||||
|
(ParserState::InWhitespace, _) => {
|
||||||
|
ret.push(c);
|
||||||
|
ParserState::Normal
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'s> RegularLink<'s> {
|
||||||
|
pub fn get_raw_link(&self) -> String {
|
||||||
|
orgify_text(self.raw_link)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_path(&self) -> String {
|
||||||
|
orgify_text(self.path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user