aboutsummaryrefslogtreecommitdiff
path: root/parse_wiki_text/src/list.rs
diff options
context:
space:
mode:
Diffstat (limited to 'parse_wiki_text/src/list.rs')
-rw-r--r--parse_wiki_text/src/list.rs221
1 files changed, 221 insertions, 0 deletions
diff --git a/parse_wiki_text/src/list.rs b/parse_wiki_text/src/list.rs
new file mode 100644
index 0000000..653c4df
--- /dev/null
+++ b/parse_wiki_text/src/list.rs
@@ -0,0 +1,221 @@
+// 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_list_end_of_line(state: &mut crate::State) {
+ let item_end_position = state.skip_whitespace_backwards(state.scan_position);
+ state.flush(item_end_position);
+ state.scan_position += 1;
+ let mut level = 0;
+ for open_node in &state.stack {
+ match open_node.type_ {
+ crate::OpenNodeType::Table { .. } | crate::OpenNodeType::Tag { .. } => level += 1,
+ _ => break,
+ }
+ }
+ let start_level = level;
+ let mut term_level = None;
+ while level < state.stack.len() {
+ match (
+ &state.stack[level].type_,
+ state.get_byte(state.scan_position),
+ ) {
+ (crate::OpenNodeType::DefinitionList { .. }, Some(b':'))
+ | (crate::OpenNodeType::OrderedList { .. }, Some(b'#'))
+ | (crate::OpenNodeType::UnorderedList { .. }, Some(b'*')) => {
+ level += 1;
+ state.scan_position += 1;
+ }
+ (crate::OpenNodeType::DefinitionList { .. }, Some(b';')) => {
+ if term_level.is_none() {
+ term_level = Some(level);
+ }
+ level += 1;
+ state.scan_position += 1;
+ }
+ _ => break,
+ }
+ }
+ if let Some(term_level) = term_level {
+ if level < state.stack.len()
+ || match state.get_byte(state.scan_position) {
+ Some(b'#') | Some(b'*') | Some(b':') | Some(b';') => true,
+ _ => false,
+ }
+ {
+ state.scan_position -= level - term_level;
+ level = term_level;
+ state.warnings.push(crate::Warning {
+ end: state.scan_position,
+ message: crate::WarningMessage::DefinitionTermContinuation,
+ start: state.scan_position - 1,
+ });
+ }
+ }
+ while level < state.stack.len() {
+ let open_node = state.stack.pop().unwrap();
+ let node = match open_node.type_ {
+ crate::OpenNodeType::DefinitionList { mut items } => {
+ {
+ let item_index = items.len() - 1;
+ let last_item = &mut items[item_index];
+ last_item.end = item_end_position;
+ last_item.nodes = std::mem::replace(&mut state.nodes, open_node.nodes);
+ }
+ crate::Node::DefinitionList {
+ end: item_end_position,
+ items,
+ start: open_node.start,
+ }
+ }
+ crate::OpenNodeType::OrderedList { mut items } => {
+ {
+ let item_index = items.len() - 1;
+ let last_item = &mut items[item_index];
+ last_item.end = item_end_position;
+ last_item.nodes = std::mem::replace(&mut state.nodes, open_node.nodes);
+ }
+ crate::Node::OrderedList {
+ end: item_end_position,
+ items,
+ start: open_node.start,
+ }
+ }
+ crate::OpenNodeType::UnorderedList { mut items } => {
+ {
+ let item_index = items.len() - 1;
+ let last_item = &mut items[item_index];
+ last_item.end = item_end_position;
+ last_item.nodes = std::mem::replace(&mut state.nodes, open_node.nodes);
+ }
+ crate::Node::UnorderedList {
+ end: item_end_position,
+ items,
+ start: open_node.start,
+ }
+ }
+ _ => unreachable!(),
+ };
+ state.nodes.push(node);
+ }
+ state.flushed_position = state.scan_position;
+ if parse_list_item_start(state) {
+ while parse_list_item_start(state) {}
+ skip_spaces(state);
+ } else if level > start_level {
+ match state.stack.get_mut(level - 1) {
+ Some(crate::OpenNode {
+ type_: crate::OpenNodeType::DefinitionList { items },
+ ..
+ }) => {
+ {
+ let item_index = items.len() - 1;
+ let last_item = &mut items[item_index];
+ last_item.end = item_end_position;
+ last_item.nodes = std::mem::replace(&mut state.nodes, vec![]);
+ }
+ items.push(crate::DefinitionListItem {
+ end: 0,
+ nodes: vec![],
+ start: state.scan_position - 1,
+ type_: if state
+ .wiki_text
+ .as_bytes()
+ .get(state.scan_position - 1)
+ .cloned()
+ == Some(b';')
+ {
+ crate::DefinitionListItemType::Term
+ } else {
+ crate::DefinitionListItemType::Details
+ },
+ });
+ }
+ Some(crate::OpenNode {
+ type_: crate::OpenNodeType::OrderedList { items },
+ ..
+ }) => {
+ {
+ let item_index = items.len() - 1;
+ let last_item = &mut items[item_index];
+ last_item.end = item_end_position;
+ last_item.nodes = std::mem::replace(&mut state.nodes, vec![]);
+ };
+ items.push(crate::ListItem {
+ end: 0,
+ nodes: vec![],
+ start: state.scan_position - 1,
+ });
+ }
+ Some(crate::OpenNode {
+ type_: crate::OpenNodeType::UnorderedList { items },
+ ..
+ }) => {
+ {
+ let item_index = items.len() - 1;
+ let last_item = &mut items[item_index];
+ last_item.end = item_end_position;
+ last_item.nodes = std::mem::replace(&mut state.nodes, vec![]);
+ };
+ items.push(crate::ListItem {
+ end: 0,
+ nodes: vec![],
+ start: state.scan_position - 1,
+ });
+ }
+ _ => unreachable!(),
+ }
+ skip_spaces(state);
+ } else {
+ state.skip_empty_lines();
+ }
+}
+
+pub fn parse_list_item_start(state: &mut crate::State) -> bool {
+ let open_node_type = match state.get_byte(state.scan_position) {
+ Some(b'#') => crate::OpenNodeType::OrderedList {
+ items: vec![crate::ListItem {
+ end: 0,
+ nodes: vec![],
+ start: state.scan_position + 1,
+ }],
+ },
+ Some(b'*') => crate::OpenNodeType::UnorderedList {
+ items: vec![crate::ListItem {
+ end: 0,
+ nodes: vec![],
+ start: state.scan_position + 1,
+ }],
+ },
+ Some(b':') => crate::OpenNodeType::DefinitionList {
+ items: vec![crate::DefinitionListItem {
+ end: 0,
+ nodes: vec![],
+ start: state.scan_position + 1,
+ type_: crate::DefinitionListItemType::Details,
+ }],
+ },
+ Some(b';') => crate::OpenNodeType::DefinitionList {
+ items: vec![crate::DefinitionListItem {
+ end: 0,
+ nodes: vec![],
+ start: state.scan_position + 1,
+ type_: crate::DefinitionListItemType::Term,
+ }],
+ },
+ _ => return false,
+ };
+ let position = state.scan_position + 1;
+ state.push_open_node(open_node_type, position);
+ true
+}
+
+pub fn skip_spaces(state: &mut crate::State) {
+ while match state.get_byte(state.scan_position) {
+ Some(b'\t') | Some(b' ') => true,
+ _ => false,
+ } {
+ state.scan_position += 1;
+ }
+ state.flushed_position = state.scan_position;
+}