diff options
| author | 2022-07-08 17:18:13 +0200 | |
|---|---|---|
| committer | 2022-07-08 17:18:13 +0200 | |
| commit | ac3cfc8253e3d3761c65b3c9db5c990f5b07f161 (patch) | |
| tree | ec04296d3822349e8d306b2d06919c701e3fd3b7 | |
| parent | f5b6e828d5f3b698b150ba4a0831b61574c6cc3b (diff) | |
| download | markdown-rs-ac3cfc8253e3d3761c65b3c9db5c990f5b07f161.tar.gz markdown-rs-ac3cfc8253e3d3761c65b3c9db5c990f5b07f161.tar.bz2 markdown-rs-ac3cfc8253e3d3761c65b3c9db5c990f5b07f161.zip  | |
Add improved container enter/exit mechanism
Diffstat (limited to '')
| -rw-r--r-- | src/content/document.rs | 188 | ||||
| -rw-r--r-- | tests/code_fenced.rs | 8 | ||||
| -rw-r--r-- | tests/html_flow.rs | 11 | 
3 files changed, 131 insertions, 76 deletions
diff --git a/src/content/document.rs b/src/content/document.rs index 2934890..ad7ffc0 100644 --- a/src/content/document.rs +++ b/src/content/document.rs @@ -25,10 +25,10 @@ use std::collections::HashSet;  struct DocumentInfo {      continued: usize, +    containers_begin_index: usize, +    inject: Vec<(Vec<Event>, Vec<Event>)>,      stack: Vec<String>,      next: Box<StateFn>, -    last_line_ending_index: Option<usize>, -    map: EditMap,  }  /// Turn `codes` as the document content type into events. @@ -71,10 +71,10 @@ pub fn document(parse_state: &mut ParseState, point: Point, index: usize) -> Vec  fn start(tokenizer: &mut Tokenizer, code: Code) -> StateFnResult {      let info = DocumentInfo {          continued: 0, +        inject: vec![], +        containers_begin_index: 0,          stack: vec![],          next: Box::new(flow), -        last_line_ending_index: None, -        map: EditMap::new(),      };      before(tokenizer, code, info)  } @@ -101,6 +101,7 @@ fn before(tokenizer: &mut Tokenizer, code: Code, info: DocumentInfo) -> StateFnR          };          // To do: state? +        println!("check existing: {:?}", name);          tokenizer.attempt(cont, move |ok| {              if ok { @@ -111,6 +112,7 @@ fn before(tokenizer: &mut Tokenizer, code: Code, info: DocumentInfo) -> StateFnR          })(tokenizer, code)      } else {          // Done. +        println!("check new:");          check_new_containers(tokenizer, code, info)      }  } @@ -155,7 +157,7 @@ fn document_continue(      //   assert(point, 'could not find previous flow chunk')      let size = info.continued; -    info = exit_containers(tokenizer, info, size); +    info = exit_containers(tokenizer, info, size, true);      //   // Fix positions.      //   let index = indexBeforeExits @@ -207,7 +209,7 @@ fn check_new_containers(          // start.          if tokenizer.concrete {              println!("  concrete!"); -            return flow_start(tokenizer, code, info); +            return there_is_no_new_container(tokenizer, code, info);          }          println!("  to do: interrupt ({:?})?", tokenizer.interrupt); @@ -238,23 +240,29 @@ fn there_is_a_new_container(  ) -> StateFnResult {      println!("there_is_a_new_container");      let size = info.continued; -    info = exit_containers(tokenizer, info, size); +    info = exit_containers(tokenizer, info, size, true); +    println!("add to stack: {:?}", name);      info.stack.push(name);      info.continued += 1;      document_continued(tokenizer, code, info)  }  /// Exit open containers. -fn exit_containers(tokenizer: &mut Tokenizer, mut info: DocumentInfo, size: usize) -> DocumentInfo { +fn exit_containers( +    tokenizer: &mut Tokenizer, +    mut info: DocumentInfo, +    size: usize, +    before: bool, +) -> DocumentInfo { +    let mut exits: Vec<Event> = vec![]; +      if info.stack.len() > size { +        // To do: inject these somewhere? Fix positions?          println!("closing flow. To do: are these resulting exits okay?"); -        let index_before = tokenizer.events.len();          let result = tokenizer.flush(info.next);          info.next = Box::new(flow); // This is weird but Rust needs a function there.          assert!(matches!(result.0, State::Ok));          assert!(result.1.is_none()); -        let shift = tokenizer.events.len() - index_before; -        info.last_line_ending_index = info.last_line_ending_index.map(|d| d + shift);      }      while info.stack.len() > size { @@ -267,22 +275,7 @@ fn exit_containers(tokenizer: &mut Tokenizer, mut info: DocumentInfo, size: usiz              unreachable!("todo: cont {:?}", name)          }; -        // To do: improve below code. -        let insert_index = if let Some(index) = info.last_line_ending_index { -            index -        } else { -            tokenizer.events.len() -        }; -        let eol_point = if let Some(index) = info.last_line_ending_index { -            tokenizer.events[index].point.clone() -        } else { -            tokenizer.point.clone() -        }; -        let eol_index = if let Some(index) = info.last_line_ending_index { -            tokenizer.events[index].index -        } else { -            tokenizer.index -        }; +        println!("creating exit for `{:?}`", name);          let token_types = end(); @@ -290,42 +283,42 @@ fn exit_containers(tokenizer: &mut Tokenizer, mut info: DocumentInfo, size: usiz          while index < token_types.len() {              let token_type = &token_types[index]; -            println!("injected exit for `{:?}`", token_type); - -            info.map.add( -                insert_index, -                0, -                vec![Event { -                    event_type: EventType::Exit, -                    token_type: token_type.clone(), -                    point: eol_point.clone(), -                    index: eol_index, -                    previous: None, -                    next: None, -                    content_type: None, -                }], -            ); +            exits.push(Event { +                event_type: EventType::Exit, +                token_type: token_type.clone(), +                // To do: fix position later. +                point: tokenizer.point.clone(), +                index: tokenizer.index, +                previous: None, +                next: None, +                content_type: None, +            });              let mut stack_index = tokenizer.stack.len(); +            let mut found = false;              while stack_index > 0 {                  stack_index -= 1;                  if tokenizer.stack[stack_index] == *token_type { +                    tokenizer.stack.remove(stack_index); +                    found = true;                      break;                  }              } -            assert_eq!( -                tokenizer.stack[stack_index], *token_type, -                "expected token type" -            ); -            tokenizer.stack.remove(stack_index); - +            assert!(found, "expected to find container token to exit");              index += 1;          }      } +    if !exits.is_empty() { +        let index = info.inject.len() - 1 - (if before { 1 } else { 0 }); +        info.inject[index].1.append(&mut exits); +    } + +    // println!("exits: {:?} {:?}", info.inject, exits); +      info  } @@ -386,15 +379,27 @@ fn container_continue(  }  fn flow_start(tokenizer: &mut Tokenizer, code: Code, mut info: DocumentInfo) -> StateFnResult { -    println!("flow_start {:?}", code); +    let containers = tokenizer +        .events +        .drain(info.containers_begin_index..) +        .collect::<Vec<_>>(); +    info.inject.push((containers, vec![])); + +    // Exit containers.      let size = info.continued; -    info = exit_containers(tokenizer, info, size); +    info = exit_containers(tokenizer, info, size, true); + +    // Define start. +    let point = tokenizer.point.clone(); +    tokenizer.define_skip(&point);      let state = info.next;      info.next = Box::new(flow); // This is weird but Rust needs a function there. +    println!("flow_start:before");      tokenizer.go_until(state, eof_eol, move |(state, remainder)| { +        println!("flow_start:after");          (              State::Fn(Box::new(move |t, c| flow_end(t, c, info, state))),              remainder, @@ -418,26 +423,77 @@ fn flow_end(      }      info.continued = 0; - -    // To do: blank lines? Other things? -    if tokenizer.events.len() > 2 -        && tokenizer.events[tokenizer.events.len() - 1].token_type == Token::LineEnding -    { -        info.last_line_ending_index = Some(tokenizer.events.len() - 2); -    } else { -        info.last_line_ending_index = None; -    } - -    println!( -        "set `last_line_ending_index` to {:?}", -        info.last_line_ending_index -    ); +    info.containers_begin_index = tokenizer.events.len();      match result {          State::Ok => {              println!("State::Ok"); -            info = exit_containers(tokenizer, info, 0); -            tokenizer.events = info.map.consume(&mut tokenizer.events); +            info = exit_containers(tokenizer, info, 0, false); +            // println!("document:inject: {:?}", info.inject); + +            let mut map = EditMap::new(); +            let mut line_index = 0; +            let mut index = 0; + +            let add = info.inject[line_index].0.clone(); +            println!("add enters at start: {:?}", add); +            map.add(0, 0, add); + +            while index < tokenizer.events.len() { +                let event = &tokenizer.events[index]; + +                if event.token_type == Token::LineEnding +                    || event.token_type == Token::BlankLineEnding +                { +                    println!("eol: {:?}", event.point); +                    if event.event_type == EventType::Enter { +                        let mut add = info.inject[line_index].1.clone(); +                        let mut deep_index = 0; +                        while deep_index < add.len() { +                            add[deep_index].point = event.point.clone(); +                            add[deep_index].index = event.index; +                            deep_index += 1; +                        } +                        println!("add exits before: {:?}", add); +                        map.add(index, 0, add); +                    } else { +                        line_index += 1; +                        let add = info.inject[line_index].0.clone(); +                        println!("add enters after: {:?}", add); +                        map.add(index + 1, 0, add); +                    } +                } + +                index += 1; +            } + +            let mut add = info.inject[line_index].1.clone(); +            let mut deep_index = 0; +            while deep_index < add.len() { +                add[deep_index].point = tokenizer.point.clone(); +                add[deep_index].index = tokenizer.index; +                deep_index += 1; +            } +            println!("add exits at end: {:?}", add); +            map.add(index, 0, add); + +            tokenizer.events = map.consume(&mut tokenizer.events); +            let mut index = 0; +            println!("document:inject:ends: {:?}", tokenizer.events.len()); +            while index < tokenizer.events.len() { +                let event = &tokenizer.events[index]; +                println!( +                    "ev: {:?} {:?} {:?} {:?} {:?} {:?}", +                    index, +                    event.event_type, +                    event.token_type, +                    event.content_type, +                    event.previous, +                    event.next +                ); +                index += 1; +            } +              (State::Ok, Some(vec![code]))          }          State::Nok => unreachable!("handle nok in `flow`?"), diff --git a/tests/code_fenced.rs b/tests/code_fenced.rs index 29ef62a..780a78f 100644 --- a/tests/code_fenced.rs +++ b/tests/code_fenced.rs @@ -57,7 +57,7 @@ fn code_fenced() {          "should support an eof somewhere in content"      ); -    // To do: blockquote (some bug). +    // To do: blockquote (fix exits, fix compiler).      // assert_eq!(      //     micromark("> ```\n> aaa\n\nbbb"),      //     "<blockquote>\n<pre><code>aaa\n</code></pre>\n</blockquote>\n<p>bbb</p>", @@ -227,14 +227,14 @@ fn code_fenced() {        "should not support a closing sequence w/ too much indent, regardless of opening sequence (1)"      ); -    // To do: blockquote (some bug). +    // To do: blockquote (fix exits, fix compiler).      // assert_eq!(      //     micromark("> ```\n>\n>\n>\n\na"),      //     "<blockquote>\n<pre><code>\n\n\n</code></pre>\n</blockquote>\n<p>a</p>",      //     "should not support a closing sequence w/ too much indent, regardless of opening sequence (2)"      // ); -    // To do: blockquote (some bug, perhaps compiler). +    // To do: blockquote (fix exits, fix compiler).      // assert_eq!(      //     micromark("> ```a\nb"),      //     "<blockquote>\n<pre><code class=\"language-a\"></code></pre>\n</blockquote>\n<p>b</p>", @@ -247,7 +247,7 @@ fn code_fenced() {          "should not support lazyness (2)"      ); -    // To do: blockquote (some bug, also compiler). +    // To do: blockquote (fix exits, fix compiler).      // assert_eq!(      //     micromark("> ```a\n```"),      //     "<blockquote>\n<pre><code class=\"language-a\"></code></pre>\n</blockquote>\n<pre><code></code></pre>\n", diff --git a/tests/html_flow.rs b/tests/html_flow.rs index 71e7bbe..757f2f3 100644 --- a/tests/html_flow.rs +++ b/tests/html_flow.rs @@ -552,12 +552,11 @@ okay.",          "should include everything ’till a blank line"      ); -    // To do: blockquote (some bug). -    // assert_eq!( -    //     micromark_with_options("> <div>\n> foo\n\nbar", DANGER), -    //     "<blockquote>\n<div>\nfoo\n</blockquote>\n<p>bar</p>", -    //     "should support basic tags w/o ending in containers (1)" -    // ); +    assert_eq!( +        micromark_with_options("> <div>\n> foo\n\nbar", DANGER), +        "<blockquote>\n<div>\nfoo\n</blockquote>\n<p>bar</p>", +        "should support basic tags w/o ending in containers (1)" +    );      // To do: list.      // assert_eq!(  | 
