aboutsummaryrefslogtreecommitdiff
path: root/parse_wiki_text/src/link.rs
diff options
context:
space:
mode:
Diffstat (limited to 'parse_wiki_text/src/link.rs')
-rw-r--r--parse_wiki_text/src/link.rs196
1 files changed, 196 insertions, 0 deletions
diff --git a/parse_wiki_text/src/link.rs b/parse_wiki_text/src/link.rs
new file mode 100644
index 0000000..24b3ba5
--- /dev/null
+++ b/parse_wiki_text/src/link.rs
@@ -0,0 +1,196 @@
+// Copyright 2019 Fredrik Portström <https://portstrom.com>
+// This is free software distributed under the terms specified in
+// the file LICENSE at the top-level directory of this distribution.
+
+pub fn parse_link_end<'a>(
+ state: &mut crate::State<'a>,
+ configuration: &crate::Configuration,
+ start_position: usize,
+ nodes: Vec<crate::Node<'a>>,
+ namespace: Option<crate::Namespace>,
+ target: &'a str,
+) {
+ let inner_end_position = state.skip_whitespace_backwards(state.scan_position);
+ state.flush(inner_end_position);
+ state.scan_position += 2;
+ state.flushed_position = state.scan_position;
+ let mut text = std::mem::replace(&mut state.nodes, nodes);
+ let end = state.scan_position;
+ let start = start_position;
+ state.nodes.push(match namespace {
+ None => {
+ let mut trail_end_position = end;
+ for character in state.wiki_text[end..].chars() {
+ if !configuration.link_trail_character_set.contains(&character) {
+ break;
+ }
+ trail_end_position += character.len_utf8();
+ }
+ if trail_end_position > end {
+ text.push(crate::Node::Text {
+ end: trail_end_position,
+ start: end,
+ value: &state.wiki_text[end..trail_end_position],
+ });
+ }
+ crate::Node::Link {
+ end: trail_end_position,
+ start,
+ target,
+ text,
+ }
+ }
+ Some(crate::Namespace::Category) => crate::Node::Category {
+ end,
+ ordinal: text,
+ start,
+ target,
+ },
+ Some(crate::Namespace::File) => crate::Node::Image {
+ end,
+ start,
+ target,
+ text,
+ },
+ });
+}
+
+pub fn parse_link_start(state: &mut crate::State, configuration: &crate::Configuration) {
+ if match state.stack.last() {
+ Some(crate::OpenNode {
+ type_: crate::OpenNodeType::Link { namespace, .. },
+ ..
+ }) => *namespace != Some(crate::Namespace::File),
+ _ => false,
+ } {
+ let open_node = state.stack.pop().unwrap();
+ state.warnings.push(crate::Warning {
+ end: state.scan_position,
+ message: crate::WarningMessage::InvalidLinkSyntax,
+ start: open_node.start,
+ });
+ state.rewind(open_node.nodes, open_node.start);
+ return;
+ }
+ let mut target_end_position;
+ let target_start_position = state.skip_whitespace_forwards(state.scan_position + 2);
+ let namespace = match configuration
+ .namespaces
+ .find(&state.wiki_text[target_start_position..])
+ {
+ Err(match_length) => {
+ target_end_position = match_length + target_start_position;
+ None
+ }
+ Ok((match_length, namespace)) => {
+ target_end_position = match_length + target_start_position;
+ Some(namespace)
+ }
+ };
+ loop {
+ match state.get_byte(target_end_position) {
+ None | Some(b'\n') | Some(b'[') | Some(b'{') | Some(b'}') => {
+ parse_unexpected_end(state, target_end_position);
+ break;
+ }
+ Some(b']') => {
+ parse_end(
+ state,
+ configuration,
+ target_start_position,
+ target_end_position,
+ namespace,
+ );
+ break;
+ }
+ Some(b'|') => {
+ state.push_open_node(
+ crate::OpenNodeType::Link {
+ namespace,
+ target: &state.wiki_text[target_start_position..target_end_position],
+ },
+ target_end_position + 1,
+ );
+ break;
+ }
+ _ => target_end_position += 1,
+ }
+ }
+}
+
+fn parse_end(
+ state: &mut crate::State,
+ configuration: &crate::Configuration,
+ target_start_position: usize,
+ target_end_position: usize,
+ namespace: Option<crate::Namespace>,
+) {
+ if state.get_byte(target_end_position + 1) != Some(b']') {
+ parse_unexpected_end(state, target_end_position);
+ return;
+ }
+ let start_position = state.scan_position;
+ state.flush(start_position);
+ let trail_start_position = target_end_position + 2;
+ let mut trail_end_position = trail_start_position;
+ match namespace {
+ Some(crate::Namespace::Category) => {
+ state.nodes.push(crate::Node::Category {
+ end: trail_end_position,
+ ordinal: vec![],
+ start: state.scan_position,
+ target: state.wiki_text[target_start_position..target_end_position].trim_right(),
+ });
+ }
+ Some(crate::Namespace::File) => {
+ state.nodes.push(crate::Node::Image {
+ end: trail_end_position,
+ start: state.scan_position,
+ target: state.wiki_text[target_start_position..target_end_position].trim_right(),
+ text: vec![],
+ });
+ }
+ None => {
+ for character in state.wiki_text[trail_start_position..].chars() {
+ if !configuration.link_trail_character_set.contains(&character) {
+ break;
+ }
+ trail_end_position += character.len_utf8();
+ }
+ let target_text = crate::Node::Text {
+ end: target_end_position,
+ start: target_start_position,
+ value: &state.wiki_text[target_start_position..target_end_position],
+ };
+ let text = if trail_end_position > trail_start_position {
+ vec![
+ target_text,
+ crate::Node::Text {
+ end: trail_end_position,
+ start: trail_start_position,
+ value: &state.wiki_text[trail_start_position..trail_end_position],
+ },
+ ]
+ } else {
+ vec![target_text]
+ };
+ state.nodes.push(crate::Node::Link {
+ end: trail_end_position,
+ start: state.scan_position,
+ target: &state.wiki_text[target_start_position..target_end_position].trim_right(),
+ text,
+ });
+ }
+ }
+ state.flushed_position = trail_end_position;
+ state.scan_position = trail_end_position;
+}
+
+fn parse_unexpected_end(state: &mut crate::State, target_end_position: usize) {
+ state.warnings.push(crate::Warning {
+ end: target_end_position,
+ message: crate::WarningMessage::InvalidLinkSyntax,
+ start: state.scan_position,
+ });
+ state.scan_position += 1;
+}