diff options
author | Titus Wormer <tituswormer@gmail.com> | 2022-06-29 16:14:32 +0200 |
---|---|---|
committer | Titus Wormer <tituswormer@gmail.com> | 2022-06-29 16:14:32 +0200 |
commit | fa37356074c1bc3a0f74b6f6a22e038b7842ff4d (patch) | |
tree | 6e91262eb1d10acf08bae36fc1902e64e8178366 /src/compiler.rs | |
parent | a1a66ce2a848458a7e0cdaf110ceeffb7b8943a2 (diff) | |
download | markdown-rs-fa37356074c1bc3a0f74b6f6a22e038b7842ff4d.tar.gz markdown-rs-fa37356074c1bc3a0f74b6f6a22e038b7842ff4d.tar.bz2 markdown-rs-fa37356074c1bc3a0f74b6f6a22e038b7842ff4d.zip |
Add support for compiling definitions
Diffstat (limited to '')
-rw-r--r-- | src/compiler.rs | 248 |
1 files changed, 196 insertions, 52 deletions
diff --git a/src/compiler.rs b/src/compiler.rs index bc31a15..3dd6ae4 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -83,7 +83,7 @@ struct Media { /// tags are ignored. label: Option<String>, /// To do. - // reference_id: String, + reference_id: Option<String>, /// The destination (url). /// Interpreted string content. destination: Option<String>, @@ -92,6 +92,17 @@ struct Media { title: Option<String>, } +/// Representation of a definition. +#[derive(Debug)] +struct Definition { + /// The destination (url). + /// Interpreted string content. + destination: Option<String>, + /// The title. + /// Interpreted string content. + title: Option<String>, +} + /// To do. #[derive(Debug, Clone, PartialEq)] struct DefinitionInfo { @@ -227,6 +238,7 @@ struct CompileContext<'a> { pub code_fenced_fences_count: Option<usize>, pub character_reference_kind: Option<CharacterReferenceKind>, pub media_stack: Vec<Media>, + pub definitions: HashMap<String, Definition>, /// Fields used to influance the current compilation. pub slurp_one_line_ending: bool, pub ignore_encode: bool, @@ -260,6 +272,7 @@ impl<'a> CompileContext<'a> { code_fenced_fences_count: None, character_reference_kind: None, media_stack: vec![], + definitions: HashMap::new(), slurp_one_line_ending: false, ignore_encode: false, last_was_tag: false, @@ -279,6 +292,7 @@ impl<'a> CompileContext<'a> { index: 0, } } + /// Push a buffer. pub fn buffer(&mut self) { self.buffers.push(vec![]); @@ -362,9 +376,9 @@ impl<'a> CompileContext<'a> { #[allow(clippy::too_many_lines)] pub fn compile(events: &[Event], codes: &[Code], options: &Options) -> String { // let mut slurp_all_line_endings = false; - let mut definition: Option<DefinitionInfo> = None; let mut index = 0; let mut line_ending_inferred: Option<LineEnding> = None; + // To do: actually do a compile pass, so that `buffer`, `resume`, etc can be used. while index < events.len() { let event = &events[index]; @@ -378,24 +392,7 @@ pub fn compile(events: &[Event], codes: &[Code], options: &Options) -> String { { let codes = codes_from_span(codes, &from_exit_event(events, index)); line_ending_inferred = Some(LineEnding::from_code(*codes.first().unwrap())); - } - - if event.event_type == EventType::Enter { - if event.token_type == TokenType::Definition { - definition = Some(DefinitionInfo { - id: None, - destination: None, - title: None, - }); - } - } else if event.token_type == TokenType::Definition { - definition = None; - } else if event.token_type == TokenType::DefinitionLabelString - || event.token_type == TokenType::DefinitionDestinationString - || event.token_type == TokenType::DefinitionTitleString - { - let slice = serialize(codes, &from_exit_event(events, index), false); - println!("set: {:?} {:?}", slice, definition); + break; } index += 1; @@ -412,7 +409,6 @@ pub fn compile(events: &[Event], codes: &[Code], options: &Options) -> String { let mut enter_map: Map = HashMap::new(); enter_map.insert(TokenType::CodeFencedFenceInfo, on_enter_buffer); enter_map.insert(TokenType::CodeFencedFenceMeta, on_enter_buffer); - enter_map.insert(TokenType::Definition, on_enter_buffer); enter_map.insert(TokenType::HeadingAtxText, on_enter_buffer); enter_map.insert(TokenType::HeadingSetextText, on_enter_buffer); enter_map.insert(TokenType::Label, on_enter_buffer); @@ -430,11 +426,22 @@ pub fn compile(events: &[Event], codes: &[Code], options: &Options) -> String { on_enter_destination_string, ); enter_map.insert(TokenType::Paragraph, on_enter_paragraph); + enter_map.insert(TokenType::Definition, on_enter_definition); + enter_map.insert( + TokenType::DefinitionDestinationString, + on_enter_definition_destination_string, + ); + enter_map.insert(TokenType::DefinitionLabelString, on_enter_buffer); + enter_map.insert(TokenType::DefinitionTitleString, on_enter_buffer); let mut exit_map: Map = HashMap::new(); exit_map.insert(TokenType::Label, on_exit_label); exit_map.insert(TokenType::LabelText, on_exit_label_text); exit_map.insert( + TokenType::ReferenceString, + on_exit_reference_destination_string, + ); + exit_map.insert( TokenType::ResourceDestinationString, on_exit_resource_destination_string, ); @@ -477,7 +484,6 @@ pub fn compile(events: &[Event], codes: &[Code], options: &Options) -> String { exit_map.insert(TokenType::CodeFlowChunk, on_exit_code_flow_chunk); exit_map.insert(TokenType::CodeText, on_exit_code_text); exit_map.insert(TokenType::CodeTextLineEnding, on_exit_code_text_line_ending); - exit_map.insert(TokenType::Definition, on_exit_definition); exit_map.insert(TokenType::HardBreakEscape, on_exit_break); exit_map.insert(TokenType::HardBreakTrailing, on_exit_break); exit_map.insert(TokenType::HeadingAtx, on_exit_heading_atx); @@ -495,11 +501,21 @@ pub fn compile(events: &[Event], codes: &[Code], options: &Options) -> String { exit_map.insert(TokenType::LineEnding, on_exit_line_ending); exit_map.insert(TokenType::Paragraph, on_exit_paragraph); exit_map.insert(TokenType::ThematicBreak, on_exit_thematic_break); + exit_map.insert(TokenType::Definition, on_exit_definition); + exit_map.insert( + TokenType::DefinitionDestinationString, + on_exit_definition_destination_string, + ); + exit_map.insert( + TokenType::DefinitionLabelString, + on_exit_definition_label_string, + ); + exit_map.insert( + TokenType::DefinitionTitleString, + on_exit_definition_title_string, + ); - let mut index = 0; - let mut context = CompileContext::new(events, codes, options, line_ending_default); - - while index < events.len() { + let handle = |context: &mut CompileContext, index: usize| { let event = &events[index]; context.index = index; @@ -508,14 +524,67 @@ pub fn compile(events: &[Event], codes: &[Code], options: &Options) -> String { } else { &exit_map }; + + println!( + "handle {:?}:{:?} ({:?})", + event.event_type, event.token_type, index + ); + if let Some(func) = map.get(&event.token_type) { - func(&mut context, event); + func(context, event); + } + }; + + let mut context = CompileContext::new(events, codes, options, line_ending_default); + let mut definition_indices: Vec<(usize, usize)> = vec![]; + let mut index = 0; + let mut definition_inside = false; + + while index < events.len() { + let event = &events[index]; + + if definition_inside { + handle(&mut context, index); + } + + if event.token_type == TokenType::Definition { + if event.event_type == EventType::Enter { + handle(&mut context, index); // also handle start. + definition_inside = true; + definition_indices.push((index, index)); + } else { + definition_inside = false; + definition_indices.last_mut().unwrap().1 = index; + } } index += 1; } - assert!(context.buffers.len() == 1, "expected 1 final buffer"); + println!("xxx: {:?}", definition_indices); + + index = 0; + let jump_default = (events.len(), events.len()); + let mut definition_index = 0; + let mut jump = definition_indices + .get(definition_index) + .unwrap_or(&jump_default); + + while index < events.len() { + if index == jump.0 { + println!("jump {:?}", jump); + index = jump.1 + 1; + definition_index += 1; + jump = definition_indices + .get(definition_index) + .unwrap_or(&jump_default); + } else { + handle(&mut context, index); + index += 1; + } + } + + assert_eq!(context.buffers.len(), 1, "expected 1 final buffer"); context .buffers .get(0) @@ -564,7 +633,7 @@ fn on_enter_image(context: &mut CompileContext, _event: &Event) { image: true, label_id: None, label: None, - // reference_id: "".to_string(), + reference_id: None, destination: None, title: None, }); @@ -576,7 +645,7 @@ fn on_enter_link(context: &mut CompileContext, _event: &Event) { image: false, label_id: None, label: None, - // reference_id: "".to_string(), + reference_id: None, destination: None, title: None, }); @@ -614,6 +683,15 @@ fn on_exit_label_text(context: &mut CompileContext, _event: &Event) { )); } +fn on_exit_reference_destination_string(context: &mut CompileContext, _event: &Event) { + let media = context.media_stack.last_mut().unwrap(); + media.reference_id = Some(serialize( + context.codes, + &from_exit_event(context.events, context.index), + false, + )); +} + fn on_exit_resource_destination_string(context: &mut CompileContext, _event: &Event) { let buf = context.resume(); let media = context.media_stack.last_mut().unwrap(); @@ -628,25 +706,43 @@ fn on_exit_resource_title_string(context: &mut CompileContext, _event: &Event) { } fn on_exit_media(context: &mut CompileContext, _event: &Event) { - // let mut is_in_image = false; - // let mut index = 0; + let mut is_in_image = false; + let mut index = 0; // Skip current. - // while index < (media_stack.len() - 1) { - // if media_stack[index].image { - // is_in_image = true; - // break; - // } - // index += 1; - // } + while index < (context.media_stack.len() - 1) { + if context.media_stack[index].image { + is_in_image = true; + break; + } + index += 1; + } - // tags = is_in_image; + // context.tags = is_in_image; let media = context.media_stack.pop().unwrap(); - println!("media: {:?}", media); + let id = media.reference_id.or(media.label_id); let label = media.label.unwrap(); - // To do: get from definition. - let destination = media.destination.unwrap_or_else(|| "".to_string()); - let title = if let Some(title) = media.title { + let definition = id.and_then(|id| context.definitions.get(&id)); + let destination = if let Some(definition) = definition { + &definition.destination + } else { + &media.destination + }; + let title = if let Some(definition) = definition { + &definition.title + } else { + &media.title + }; + + println!("media: {:?} {:?}", destination, title); + + let destination = if let Some(destination) = destination { + destination.clone() + } else { + "".to_string() + }; + + let title = if let Some(title) = title { format!(" title=\"{}\"", title) } else { "".to_string() @@ -700,11 +796,9 @@ fn on_exit_autolink_protocol(context: &mut CompileContext, _event: &Event) { &from_exit_event(context.events, context.index), false, ); - let href = sanitize_uri(slice.as_str(), &context.protocol_href); - println!("xxx: {:?} {:?}", href, &context.protocol_href); context.push(format!( "<a href=\"{}\">{}</a>", - href, + sanitize_uri(slice.as_str(), &context.protocol_href), context.encode_opt(&slice) )); } @@ -836,11 +930,6 @@ fn on_exit_code_text_line_ending(context: &mut CompileContext, _event: &Event) { context.push(" ".to_string()); } -fn on_exit_definition(context: &mut CompileContext, _event: &Event) { - context.resume(); - context.slurp_one_line_ending = true; -} - fn on_exit_break(context: &mut CompileContext, _event: &Event) { context.push("<br />".to_string()); } @@ -929,3 +1018,58 @@ fn on_exit_paragraph(context: &mut CompileContext, _event: &Event) { fn on_exit_thematic_break(context: &mut CompileContext, _event: &Event) { context.push("<hr />".to_string()); } + +fn on_enter_definition(context: &mut CompileContext, _event: &Event) { + context.buffer(); + context.media_stack.push(Media { + image: false, + label: None, + label_id: None, + reference_id: None, + destination: None, + title: None, + }); +} + +fn on_enter_definition_destination_string(context: &mut CompileContext, _event: &Event) { + context.buffer(); + context.ignore_encode = true; +} + +fn on_exit_definition_destination_string(context: &mut CompileContext, _event: &Event) { + let buf = context.resume(); + let definition = context.media_stack.last_mut().unwrap(); + definition.destination = Some(buf); + context.ignore_encode = false; +} + +fn on_exit_definition_label_string(context: &mut CompileContext, _event: &Event) { + // Discard label, use the source content instead. + context.resume(); + let definition = context.media_stack.last_mut().unwrap(); + // To do: put this on `reference_id` instead? + definition.label_id = Some(serialize( + context.codes, + &from_exit_event(context.events, context.index), + false, + )); +} + +fn on_exit_definition_title_string(context: &mut CompileContext, _event: &Event) { + let buf = context.resume(); + let definition = context.media_stack.last_mut().unwrap(); + definition.title = Some(buf); +} + +fn on_exit_definition(context: &mut CompileContext, _event: &Event) { + let definition = context.media_stack.pop().unwrap(); + let label_id = definition.label_id.unwrap(); + let destination = definition.destination; + let title = definition.title; + + context.resume(); + context + .definitions + .insert(label_id, Definition { destination, title }); + context.slurp_one_line_ending = true; +} |