diff options
| author | Andreu Botella | 2019-11-07 00:32:46 +0100 |
|---|---|---|
| committer | Philipp A | 2019-11-07 09:27:38 +0100 |
| commit | 5387291c1a2d4cfd0e5acdad26dcc7e33329d39a (patch) | |
| tree | 76df86d6b05af4d9dc2d7e036c1011b848f15f48 /src/parser/conversion/inline.rs | |
| parent | 10cc972f2e4b99e6d3082970ee6982bfee5211c0 (diff) | |
| download | rust-rst-5387291c1a2d4cfd0e5acdad26dcc7e33329d39a.tar.bz2 | |
Updating the parser to recognize most hyperlink references.
Diffstat (limited to 'src/parser/conversion/inline.rs')
| -rw-r--r-- | src/parser/conversion/inline.rs | 106 |
1 files changed, 96 insertions, 10 deletions
diff --git a/src/parser/conversion/inline.rs b/src/parser/conversion/inline.rs index 50a6258..c51b2d9 100644 --- a/src/parser/conversion/inline.rs +++ b/src/parser/conversion/inline.rs @@ -1,5 +1,6 @@ use failure::Error; use pest::iterators::Pair; +use url::Url; use crate::document_tree::{ ExtraAttributes, @@ -20,31 +21,116 @@ use super::whitespace_normalize_name; pub fn convert_inline(pair: Pair<Rule>) -> Result<c::TextOrInlineElement, Error> { Ok(match pair.as_rule() { Rule::str => pair.as_str().into(), - Rule::reference => convert_reference(pair)?.into(), + Rule::reference => convert_reference(pair)?, Rule::substitution_ref => convert_substitution(pair)?.into(), rule => unimplemented!("unknown rule {:?}", rule), }) } -fn convert_reference(pair: Pair<Rule>) -> Result<e::Reference, Error> { +fn convert_reference(pair: Pair<Rule>) -> Result<c::TextOrInlineElement, Error> { let name; - let refuri = None; + let refuri; let refid; - let refname = vec![]; + let mut refname = vec![]; + let mut children: Vec<c::TextOrInlineElement> = vec![]; let concrete = pair.into_inner().next().unwrap(); match concrete.as_rule() { Rule::reference_target => { let rt_inner = concrete.into_inner().next().unwrap(); // reference_target_uq or target_name_qu - refid = Some(rt_inner.as_str().into()); - name = Some(rt_inner.as_str().into()); + match rt_inner.as_rule() { + Rule::reference_target_uq => { + refid = None; + name = Some(rt_inner.as_str().into()); + refuri = None; + refname.push(rt_inner.as_str().into()); + children.push(rt_inner.as_str().into()); + }, + Rule::reference_target_qu => { + let (text, reference) = { + let mut text = None; + let mut reference = None; + for inner in rt_inner.clone().into_inner() { + match inner.as_rule() { + Rule::reference_text => text = Some(inner), + Rule::reference_bracketed => reference = Some(inner), + _ => unreachable!() + } + } + (text, reference) + }; + let trimmed_text = match (&text, &reference) { + (Some(text), None) => text.as_str(), + (_, Some(reference)) => { + text + .map(|text| text.as_str().trim_end_matches(|ch| " \n\r".contains(ch))) + .filter(|text| !text.is_empty()) + .unwrap_or_else(|| reference.clone().into_inner().next().unwrap().as_str()) + } + (None, None) => unreachable!() + }; + refid = None; + name = Some(trimmed_text.into()); + refuri = if let Some(reference) = reference { + let inner = reference.into_inner().next().unwrap(); + match inner.as_rule() { + Rule::url => if let Ok(url) = Url::parse(inner.as_str()) { + Some(url.into()) + } else { + unimplemented!("reference to a relative URL") + }, + Rule::target_name_qu => { + refname.push(inner.as_str().into()); + None + }, + Rule::relative_reference => unimplemented!("reference to a relative URL"), + _ => unreachable!() + } + } else { + refname.push(trimmed_text.into()); + None + }; + children.push(trimmed_text.into()); + }, + _ => unreachable!() + } }, Rule::reference_explicit => unimplemented!("explicit reference"), - Rule::reference_auto => unimplemented!("auto reference"), + Rule::reference_auto => { + let rt_inner = concrete.into_inner().next().unwrap(); + match rt_inner.as_rule() { + Rule::url_auto => match Url::parse(rt_inner.as_str()) { + Ok(url) => { + refuri = Some(url.into()); + name = None; + refid = None; + children.push(rt_inner.as_str().into()); + }, + // if our parser got a URL wrong, return it as a string + Err(_) => return Ok(rt_inner.as_str().into()) + }, + Rule::email => { + let mailto_url = String::from("mailto:") + rt_inner.as_str(); + match Url::parse(&mailto_url) { + Ok(url) => { + refuri = Some(url.into()); + name = None; + refid = None; + children.push(rt_inner.as_str().into()); + }, + // if our parser got a URL wrong, return it as a string + Err(_) => return Ok(rt_inner.as_str().into()) + } + }, + _ => unreachable!() + } + }, _ => unreachable!(), }; - Ok(e::Reference::with_extra( - a::Reference { name, refuri, refid, refname } - )) + Ok(e::Reference::new( + Default::default(), + a::Reference { name, refuri, refid, refname }, + children + ).into()) } fn convert_substitution(pair: Pair<Rule>) -> Result<e::SubstitutionReference, Error> { |
