From 8898ff33b925b148ade2e901e45c61726b2f484b Mon Sep 17 00:00:00 2001 From: Sebastian Schneider Date: Tue, 12 Dec 2023 17:25:38 +0100 Subject: [PATCH 01/14] Fix Panicing --- render/src/umi/mod.rs | 59 ++++++++++++++++++++-------------------- render/src/umi/render.rs | 51 ++++++---------------------------- 2 files changed, 39 insertions(+), 71 deletions(-) diff --git a/render/src/umi/mod.rs b/render/src/umi/mod.rs index 1742aeed..4daf667c 100644 --- a/render/src/umi/mod.rs +++ b/render/src/umi/mod.rs @@ -7,6 +7,7 @@ use unimarkup_commons::config::Config; use unimarkup_commons::lexer::{ symbol::SymbolKind, token::{iterator::TokenIterator, lex_str, TokenKind}, + position::Position, }; use unimarkup_inline::{ element::Inline, @@ -95,7 +96,7 @@ impl Umi { // Row 1: Config sheet.set_value(1, 0, 0); sheet.set_value(1, 2, "config"); - sheet.set_value(1, 4, serde_yaml::to_string(&self.config).unwrap()); + sheet.set_value(1, 4, serde_yaml::to_string(&self.config).unwrap_or_default()); for element in &self.elements { let row = element.position + 2; @@ -134,19 +135,19 @@ impl Umi { fn read_row(&mut self, line: usize) -> Block { let mut current_line = self.elements[line].clone(); let attributes: HashMap = - serde_json::from_str(¤t_line.attributes).unwrap(); + serde_json::from_str(¤t_line.attributes).unwrap_or_default(); match current_line.kind.as_str() { "Heading" => { let heading = Heading { id: current_line.id.clone(), level: unimarkup_parser::elements::atomic::HeadingLevel::try_from( - attributes.get("level").unwrap().as_str(), + attributes.get("level").unwrap_or(&String::from("#")).as_str(), ) .unwrap(), content: self.read_inlines(current_line.content.clone()), attributes: (attributes.get("attributes").cloned()).filter(|s| !s.is_empty()), - start: serde_json::from_str(attributes.get("start").unwrap()).unwrap(), - end: serde_json::from_str(attributes.get("end").unwrap()).unwrap(), + start: Position::new(1, 1), + end: Position::new(1, 1), }; Block::Heading(heading) } @@ -161,23 +162,23 @@ impl Umi { content: current_line.content.clone(), data_lang: attributes.get("data_lang").cloned(), attributes: attributes.get("attributes").cloned(), - implicit_closed: attributes.get("implicit_closed").unwrap().parse().unwrap(), - tick_len: attributes.get("tick_len").unwrap().parse().unwrap(), - start: serde_json::from_str(attributes.get("start").unwrap()).unwrap(), - end: serde_json::from_str(attributes.get("end").unwrap()).unwrap(), + implicit_closed: attributes.get("implicit_closed").unwrap_or(&String::new()).parse().unwrap_or_default(), + tick_len: attributes.get("tick_len").unwrap_or(&String::new()).parse().unwrap_or_default(), + start: Position::new(1, 1), + end: Position::new(1, 1), }; Block::VerbatimBlock(verbatim) } "BulletList" => { let mut bullet_list = BulletList { entries: vec![], - start: serde_json::from_str(attributes.get("start").unwrap()).unwrap(), - end: serde_json::from_str(attributes.get("end").unwrap()).unwrap(), + start: Position::new(1, 1), + end: Position::new(1, 1), }; let bullet_list_depth = current_line.depth; let mut current_line_index = line + 1; - current_line = self.fetch_next_line(current_line_index).unwrap(); + current_line = self.fetch_next_line(current_line_index).unwrap_or_default(); while current_line.depth > bullet_list_depth { if current_line.depth == bullet_list_depth + 1 { @@ -185,7 +186,7 @@ impl Umi { let block = self.read_row(current_line_index); let bullet_list_entry = match block { Block::BulletListEntry(block) => block, - _ => panic!(), + _ => break, }; bullet_list.entries.append(&mut vec![bullet_list_entry]); } else { @@ -197,7 +198,7 @@ impl Umi { if fetched.is_none() { break; } - current_line = fetched.unwrap(); + current_line = fetched.unwrap_or_default(); } Block::BulletList(bullet_list) @@ -205,19 +206,19 @@ impl Umi { "BulletListEntry" => { let mut bullet_list_entry = BulletListEntry { keyword: TokenKind::from(SymbolKind::from( - attributes.get("keyword").unwrap().as_str(), + attributes.get("keyword").unwrap_or(&String::from('-')).as_str(), )) .try_into() .unwrap(), - heading: self.read_inlines(attributes.get("heading").unwrap().to_string()), + heading: self.read_inlines(attributes.get("heading").unwrap_or(&String::new()).to_string()), body: vec![], - start: serde_json::from_str(attributes.get("start").unwrap()).unwrap(), - end: serde_json::from_str(attributes.get("end").unwrap()).unwrap(), + start: Position::new(1, 1), + end: Position::new(1, 1), }; let bullet_list_entry_depth = current_line.depth; let mut current_line_index = line + 1; - current_line = self.fetch_next_line(current_line_index).unwrap(); + current_line = self.fetch_next_line(current_line_index).unwrap_or_default(); while current_line.depth > bullet_list_entry_depth { if current_line.depth == bullet_list_entry_depth + 1 { @@ -234,7 +235,7 @@ impl Umi { if fetched.is_none() { break; } - current_line = fetched.unwrap(); + current_line = fetched.unwrap_or_default(); } Block::BulletListEntry(bullet_list_entry) @@ -247,38 +248,38 @@ impl Umi { self.elements.clear(); debug_assert!(!self.ods.is_empty()); - let wb: WorkBook = read_ods_buf(&self.ods).unwrap(); + let wb: WorkBook = read_ods_buf(&self.ods).unwrap_or_default(); let sheet = wb.sheet(0); let rows = sheet.used_grid_size().0; for row_index in 2..rows { self.elements.push(UmiRow::new( - sheet.cell(row_index, 0).unwrap().value.as_u8_opt().unwrap(), + sheet.cell(row_index, 0).unwrap_or_default().value.as_u8_opt().unwrap_or(0), sheet .cell(row_index, 1) - .unwrap() + .unwrap_or_default() .value .as_str_opt() .unwrap_or_default() .to_string(), sheet .cell(row_index, 2) - .unwrap() + .unwrap_or_default() .value .as_str_opt() .unwrap_or_default() .to_string(), - sheet.cell(row_index, 3).unwrap().value.as_u8_opt().unwrap(), + sheet.cell(row_index, 3).unwrap_or_default().value.as_u8_opt().unwrap_or(0), sheet .cell(row_index, 4) - .unwrap() + .unwrap_or_default() .value .as_str_opt() .unwrap_or_default() .to_string(), sheet .cell(row_index, 5) - .unwrap() + .unwrap_or_default() .value .as_str_opt() .unwrap_or_default() @@ -299,13 +300,13 @@ impl Umi { config.preamble = serde_yaml::from_str( sheet .cell(1, 4) - .unwrap() + .unwrap_or_default() .value .as_cow_str_or("") .to_string() .as_str(), ) - .unwrap(); + .unwrap_or_default(); Document { blocks: um, diff --git a/render/src/umi/render.rs b/render/src/umi/render.rs index 4c2f31b1..b045da83 100644 --- a/render/src/umi/render.rs +++ b/render/src/umi/render.rs @@ -44,7 +44,7 @@ impl Renderer for UmiRenderer { let content = self.render_inlines(¶graph.content, context)?; let hashmap: HashMap = HashMap::new(); - let attributes = serde_json::to_string(&hashmap).unwrap(); + let attributes = serde_json::to_string(&hashmap).unwrap_or(String::from("{}")); let paragraph = UmiRow::new( self.pos, @@ -82,15 +82,7 @@ impl Renderer for UmiRenderer { String::from("implicit_closed"), verbatim.implicit_closed.to_string(), ); - hashmap.insert( - String::from("start"), - serde_json::to_string(&verbatim.start).unwrap(), - ); - hashmap.insert( - String::from("end"), - serde_json::to_string(&verbatim.end).unwrap(), - ); - let attributes = serde_json::to_string(&hashmap).unwrap(); + let attributes = serde_json::to_string(&hashmap).unwrap_or(String::from("{}")); let verbatim = UmiRow::new( self.pos, @@ -120,15 +112,7 @@ impl Renderer for UmiRenderer { heading.attributes.clone().unwrap_or_default(), ); hashmap.insert(String::from("level"), heading.level.as_str().to_string()); - hashmap.insert( - String::from("start"), - serde_json::to_string(&heading.start).unwrap(), - ); - hashmap.insert( - String::from("end"), - serde_json::to_string(&heading.end).unwrap(), - ); - let attributes = serde_json::to_string(&hashmap).unwrap(); + let attributes = serde_json::to_string(&hashmap).unwrap_or(String::from("{}")); let content = self.render_inlines(&heading.content, context)?; @@ -154,16 +138,8 @@ impl Renderer for UmiRenderer { bullet_list: &unimarkup_parser::elements::indents::BulletList, context: &Context, ) -> Result { - let mut hashmap: HashMap = HashMap::new(); - hashmap.insert( - String::from("start"), - serde_json::to_string(&bullet_list.start).unwrap(), - ); - hashmap.insert( - String::from("end"), - serde_json::to_string(&bullet_list.end).unwrap(), - ); - let attributes = serde_json::to_string(&hashmap).unwrap(); + let hashmap: HashMap = HashMap::new(); + let attributes = serde_json::to_string(&hashmap).unwrap_or(String::from("{}")); let bullet_list_heading = UmiRow::new( self.pos, @@ -202,20 +178,12 @@ impl Renderer for UmiRenderer { ); hashmap.insert( String::from("heading"), - self.render_inlines(&bullet_list_entry.heading, context) - .unwrap() + self.render_inlines(&bullet_list_entry.heading, context)? .elements[0] .content .clone(), ); - hashmap.insert( - String::from("start"), - serde_json::to_string(&bullet_list_entry.start).unwrap(), - ); - hashmap.insert( - String::from("end"), - serde_json::to_string(&bullet_list_entry.end).unwrap(), - ); + let attributes = serde_json::to_string(&hashmap).unwrap_or(String::from("{}")); let mut entry = Umi::with_um( vec![UmiRow::new( self.pos, @@ -224,12 +192,11 @@ impl Renderer for UmiRenderer { .variant_str() .to_string(), self.depth, - self.render_inlines(&bullet_list_entry.heading, context) - .unwrap() + self.render_inlines(&bullet_list_entry.heading, context)? .elements[0] .content .clone(), - serde_json::to_string(&hashmap).unwrap(), + attributes, )], context.get_config().clone(), context.get_lang().to_string(), From 6733654b8870745626cb938fd4e76be1617904ee Mon Sep 17 00:00:00 2001 From: Sebastian Schneider Date: Wed, 13 Dec 2023 15:30:18 +0100 Subject: [PATCH 02/14] Add Type Column --- render/src/umi/mod.rs | 77 +++++++++++++++++++++++++++++----------- render/src/umi/render.rs | 34 +++++++++--------- 2 files changed, 72 insertions(+), 39 deletions(-) diff --git a/render/src/umi/mod.rs b/render/src/umi/mod.rs index 4daf667c..e6dfc1d4 100644 --- a/render/src/umi/mod.rs +++ b/render/src/umi/mod.rs @@ -5,9 +5,9 @@ use crate::render::OutputFormat; use spreadsheet_ods::{read_ods_buf, write_ods_buf_uncompressed, Sheet, WorkBook}; use unimarkup_commons::config::Config; use unimarkup_commons::lexer::{ + position::Position, symbol::SymbolKind, token::{iterator::TokenIterator, lex_str, TokenKind}, - position::Position, }; use unimarkup_inline::{ element::Inline, @@ -30,6 +30,7 @@ pub struct UmiRow { position: u8, id: String, kind: String, + typ: String, depth: u8, content: String, attributes: String, @@ -40,6 +41,7 @@ impl UmiRow { position: u8, id: String, kind: String, + typ: String, depth: u8, content: String, attributes: String, @@ -48,6 +50,7 @@ impl UmiRow { position, id, kind, + typ, depth, content, attributes, @@ -81,31 +84,37 @@ impl Umi { sheet.set_value(0, 0, "position"); sheet.set_value(0, 1, "id"); sheet.set_value(0, 2, "kind"); - sheet.set_value(0, 3, "depth"); + sheet.set_value(0, 3, "type"); + sheet.set_value(0, 4, "depth"); sheet.set_value( 0, - 4, + 5, String::from("content-") + self.lang.to_string().as_str(), ); sheet.set_value( 0, - 5, + 6, String::from("attributes-") + self.lang.to_string().as_str(), ); // Row 1: Config sheet.set_value(1, 0, 0); sheet.set_value(1, 2, "config"); - sheet.set_value(1, 4, serde_yaml::to_string(&self.config).unwrap_or_default()); + sheet.set_value( + 1, + 4, + serde_yaml::to_string(&self.config).unwrap_or_default(), + ); for element in &self.elements { let row = element.position + 2; sheet.set_value(row.into(), 0, element.position + 1); sheet.set_value(row.into(), 1, element.id.clone()); sheet.set_value(row.into(), 2, element.kind.clone()); - sheet.set_value(row.into(), 3, element.depth); - sheet.set_value(row.into(), 4, element.content.clone()); - sheet.set_value(row.into(), 5, element.attributes.clone()); + sheet.set_value(row.into(), 3, element.typ.clone()); + sheet.set_value(row.into(), 4, element.depth); + sheet.set_value(row.into(), 5, element.content.clone()); + sheet.set_value(row.into(), 6, element.attributes.clone()); } wb.push_sheet(sheet); @@ -134,18 +143,18 @@ impl Umi { fn read_row(&mut self, line: usize) -> Block { let mut current_line = self.elements[line].clone(); - let attributes: HashMap = - serde_json::from_str(¤t_line.attributes).unwrap_or_default(); + let typ: HashMap = + serde_json::from_str(¤t_line.typ).unwrap_or_default(); match current_line.kind.as_str() { "Heading" => { let heading = Heading { id: current_line.id.clone(), level: unimarkup_parser::elements::atomic::HeadingLevel::try_from( - attributes.get("level").unwrap_or(&String::from("#")).as_str(), + typ.get("level").unwrap_or(&String::from("#")).as_str(), ) .unwrap(), content: self.read_inlines(current_line.content.clone()), - attributes: (attributes.get("attributes").cloned()).filter(|s| !s.is_empty()), + attributes: Some(current_line.attributes), start: Position::new(1, 1), end: Position::new(1, 1), }; @@ -160,10 +169,18 @@ impl Umi { "VerbatimBlock" => { let verbatim = VerbatimBlock { content: current_line.content.clone(), - data_lang: attributes.get("data_lang").cloned(), - attributes: attributes.get("attributes").cloned(), - implicit_closed: attributes.get("implicit_closed").unwrap_or(&String::new()).parse().unwrap_or_default(), - tick_len: attributes.get("tick_len").unwrap_or(&String::new()).parse().unwrap_or_default(), + data_lang: typ.get("data_lang").cloned(), + attributes: Some(current_line.attributes), + implicit_closed: typ + .get("implicit_closed") + .unwrap_or(&String::new()) + .parse() + .unwrap_or_default(), + tick_len: typ + .get("tick_len") + .unwrap_or(&String::new()) + .parse() + .unwrap_or_default(), start: Position::new(1, 1), end: Position::new(1, 1), }; @@ -206,11 +223,12 @@ impl Umi { "BulletListEntry" => { let mut bullet_list_entry = BulletListEntry { keyword: TokenKind::from(SymbolKind::from( - attributes.get("keyword").unwrap_or(&String::from('-')).as_str(), + typ.get("keyword").unwrap_or(&String::from('-')).as_str(), )) .try_into() .unwrap(), - heading: self.read_inlines(attributes.get("heading").unwrap_or(&String::new()).to_string()), + heading: self + .read_inlines(typ.get("heading").unwrap_or(&String::new()).to_string()), body: vec![], start: Position::new(1, 1), end: Position::new(1, 1), @@ -254,7 +272,12 @@ impl Umi { for row_index in 2..rows { self.elements.push(UmiRow::new( - sheet.cell(row_index, 0).unwrap_or_default().value.as_u8_opt().unwrap_or(0), + sheet + .cell(row_index, 0) + .unwrap_or_default() + .value + .as_u8_opt() + .unwrap_or(0), sheet .cell(row_index, 1) .unwrap_or_default() @@ -269,14 +292,19 @@ impl Umi { .as_str_opt() .unwrap_or_default() .to_string(), - sheet.cell(row_index, 3).unwrap_or_default().value.as_u8_opt().unwrap_or(0), sheet - .cell(row_index, 4) + .cell(row_index, 3) .unwrap_or_default() .value .as_str_opt() .unwrap_or_default() .to_string(), + sheet + .cell(row_index, 4) + .unwrap_or_default() + .value + .as_u8_opt() + .unwrap_or(0), sheet .cell(row_index, 5) .unwrap_or_default() @@ -284,6 +312,13 @@ impl Umi { .as_str_opt() .unwrap_or_default() .to_string(), + sheet + .cell(row_index, 6) + .unwrap_or_default() + .value + .as_str_opt() + .unwrap_or_default() + .to_string(), )) } diff --git a/render/src/umi/render.rs b/render/src/umi/render.rs index b045da83..7d89a494 100644 --- a/render/src/umi/render.rs +++ b/render/src/umi/render.rs @@ -44,15 +44,16 @@ impl Renderer for UmiRenderer { let content = self.render_inlines(¶graph.content, context)?; let hashmap: HashMap = HashMap::new(); - let attributes = serde_json::to_string(&hashmap).unwrap_or(String::from("{}")); + let typ = serde_json::to_string(&hashmap).unwrap_or(String::from("{}")); let paragraph = UmiRow::new( self.pos, String::new(), String::from(Block::Paragraph(paragraph.to_owned()).variant_str()), + typ, self.depth, content.elements[0].content.clone(), - attributes, + String::new(), ); self.pos += 1; @@ -73,24 +74,21 @@ impl Renderer for UmiRenderer { String::from("data_lang"), verbatim.data_lang.clone().unwrap_or_default(), ); - hashmap.insert( - String::from("attributes"), - verbatim.attributes.clone().unwrap_or_default(), - ); hashmap.insert(String::from("tick_len"), verbatim.tick_len.to_string()); hashmap.insert( String::from("implicit_closed"), verbatim.implicit_closed.to_string(), ); - let attributes = serde_json::to_string(&hashmap).unwrap_or(String::from("{}")); + let typ = serde_json::to_string(&hashmap).unwrap_or(String::from("{}")); let verbatim = UmiRow::new( self.pos, String::new(), String::from("VerbatimBlock"), + typ, self.depth, verbatim.content.clone(), - attributes, + verbatim.attributes.clone().unwrap_or_default(), ); self.pos += 1; @@ -107,12 +105,8 @@ impl Renderer for UmiRenderer { context: &Context, ) -> Result { let mut hashmap: HashMap = HashMap::new(); - hashmap.insert( - String::from("attributes"), - heading.attributes.clone().unwrap_or_default(), - ); hashmap.insert(String::from("level"), heading.level.as_str().to_string()); - let attributes = serde_json::to_string(&hashmap).unwrap_or(String::from("{}")); + let typ = serde_json::to_string(&hashmap).unwrap_or(String::from("{}")); let content = self.render_inlines(&heading.content, context)?; @@ -120,9 +114,10 @@ impl Renderer for UmiRenderer { self.pos, heading.id.clone(), String::from("Heading"), + typ, self.depth, content.elements[0].content.clone(), - attributes, + heading.attributes.clone().unwrap_or_default(), ); self.pos += 1; @@ -139,15 +134,16 @@ impl Renderer for UmiRenderer { context: &Context, ) -> Result { let hashmap: HashMap = HashMap::new(); - let attributes = serde_json::to_string(&hashmap).unwrap_or(String::from("{}")); + let typ = serde_json::to_string(&hashmap).unwrap_or(String::from("{}")); let bullet_list_heading = UmiRow::new( self.pos, String::new(), String::from("BulletList"), + typ, self.depth, String::new(), - attributes, + String::new(), ); self.pos += 1; @@ -183,7 +179,7 @@ impl Renderer for UmiRenderer { .content .clone(), ); - let attributes = serde_json::to_string(&hashmap).unwrap_or(String::from("{}")); + let typ = serde_json::to_string(&hashmap).unwrap_or(String::from("{}")); let mut entry = Umi::with_um( vec![UmiRow::new( self.pos, @@ -191,12 +187,13 @@ impl Renderer for UmiRenderer { Block::BulletListEntry(bullet_list_entry.to_owned()) .variant_str() .to_string(), + typ, self.depth, self.render_inlines(&bullet_list_entry.heading, context)? .elements[0] .content .clone(), - attributes, + String::new(), )], context.get_config().clone(), context.get_lang().to_string(), @@ -229,6 +226,7 @@ impl Renderer for UmiRenderer { self.pos, String::new(), String::from("Inline"), + String::new(), self.depth, res, String::new(), From 194ec73cbdbbe00f52bdbdc29c4fd50a42486e06 Mon Sep 17 00:00:00 2001 From: Sebastian Schneider Date: Sat, 16 Dec 2023 14:01:14 +0100 Subject: [PATCH 03/14] Change Error-Handling and Properties --- cli/tests/umi.rs | 2 +- render/src/umi/mod.rs | 73 +++++++++++++++++++++++----------------- render/src/umi/render.rs | 20 +++++------ 3 files changed, 54 insertions(+), 41 deletions(-) diff --git a/cli/tests/umi.rs b/cli/tests/umi.rs index 14d04cda..7e57a69f 100644 --- a/cli/tests/umi.rs +++ b/cli/tests/umi.rs @@ -21,7 +21,7 @@ fn umi_loop() { let mut umi = um.render_umi().unwrap(); let workbook = umi.create_workbook(); - let looped_doc = workbook.create_um(); + let looped_doc = workbook.create_um().map_err(|_| panic!()).unwrap(); assert_eq!( looped_doc.blocks.len(), diff --git a/render/src/umi/mod.rs b/render/src/umi/mod.rs index e6dfc1d4..fe8505fb 100644 --- a/render/src/umi/mod.rs +++ b/render/src/umi/mod.rs @@ -13,6 +13,7 @@ use unimarkup_inline::{ element::Inline, parser::{parse_inlines, InlineContext}, }; +use unimarkup_parser::log_id::ParserError; use unimarkup_parser::{ document::Document, elements::{ @@ -30,7 +31,7 @@ pub struct UmiRow { position: u8, id: String, kind: String, - typ: String, + properties: String, depth: u8, content: String, attributes: String, @@ -41,7 +42,7 @@ impl UmiRow { position: u8, id: String, kind: String, - typ: String, + properties: String, depth: u8, content: String, attributes: String, @@ -50,7 +51,7 @@ impl UmiRow { position, id, kind, - typ, + properties, depth, content, attributes, @@ -84,7 +85,7 @@ impl Umi { sheet.set_value(0, 0, "position"); sheet.set_value(0, 1, "id"); sheet.set_value(0, 2, "kind"); - sheet.set_value(0, 3, "type"); + sheet.set_value(0, 3, "properties"); sheet.set_value(0, 4, "depth"); sheet.set_value( 0, @@ -111,7 +112,7 @@ impl Umi { sheet.set_value(row.into(), 0, element.position + 1); sheet.set_value(row.into(), 1, element.id.clone()); sheet.set_value(row.into(), 2, element.kind.clone()); - sheet.set_value(row.into(), 3, element.typ.clone()); + sheet.set_value(row.into(), 3, element.properties.clone()); sheet.set_value(row.into(), 4, element.depth); sheet.set_value(row.into(), 5, element.content.clone()); sheet.set_value(row.into(), 6, element.attributes.clone()); @@ -141,50 +142,54 @@ impl Umi { } } - fn read_row(&mut self, line: usize) -> Block { + fn read_row(&mut self, line: usize) -> Result { let mut current_line = self.elements[line].clone(); - let typ: HashMap = - serde_json::from_str(¤t_line.typ).unwrap_or_default(); + let properties: HashMap = + serde_json::from_str(¤t_line.properties).unwrap_or_default(); match current_line.kind.as_str() { "Heading" => { let heading = Heading { id: current_line.id.clone(), level: unimarkup_parser::elements::atomic::HeadingLevel::try_from( - typ.get("level").unwrap_or(&String::from("#")).as_str(), + properties + .get("level") + .ok_or(ParserError::NoUnimarkupDetected)? + .as_str(), ) - .unwrap(), + .ok() + .ok_or(ParserError::NoUnimarkupDetected)?, content: self.read_inlines(current_line.content.clone()), attributes: Some(current_line.attributes), start: Position::new(1, 1), end: Position::new(1, 1), }; - Block::Heading(heading) + Ok(Block::Heading(heading)) } "Paragraph" => { let paragraph = Paragraph { content: self.read_inlines(current_line.content.clone()), }; - Block::Paragraph(paragraph) + Ok(Block::Paragraph(paragraph)) } "VerbatimBlock" => { let verbatim = VerbatimBlock { content: current_line.content.clone(), - data_lang: typ.get("data_lang").cloned(), + data_lang: properties.get("data_lang").cloned(), attributes: Some(current_line.attributes), - implicit_closed: typ + implicit_closed: properties .get("implicit_closed") - .unwrap_or(&String::new()) + .ok_or(ParserError::NoUnimarkupDetected)? .parse() .unwrap_or_default(), - tick_len: typ + tick_len: properties .get("tick_len") - .unwrap_or(&String::new()) + .ok_or(ParserError::NoUnimarkupDetected)? .parse() .unwrap_or_default(), start: Position::new(1, 1), end: Position::new(1, 1), }; - Block::VerbatimBlock(verbatim) + Ok(Block::VerbatimBlock(verbatim)) } "BulletList" => { let mut bullet_list = BulletList { @@ -202,7 +207,7 @@ impl Umi { // Append Element to Bullet List let block = self.read_row(current_line_index); let bullet_list_entry = match block { - Block::BulletListEntry(block) => block, + Ok(Block::BulletListEntry(block)) => block, _ => break, }; bullet_list.entries.append(&mut vec![bullet_list_entry]); @@ -218,17 +223,25 @@ impl Umi { current_line = fetched.unwrap_or_default(); } - Block::BulletList(bullet_list) + Ok(Block::BulletList(bullet_list)) } "BulletListEntry" => { let mut bullet_list_entry = BulletListEntry { keyword: TokenKind::from(SymbolKind::from( - typ.get("keyword").unwrap_or(&String::from('-')).as_str(), + properties + .get("keyword") + .ok_or(ParserError::NoUnimarkupDetected)? + .as_str(), )) .try_into() - .unwrap(), - heading: self - .read_inlines(typ.get("heading").unwrap_or(&String::new()).to_string()), + .ok() + .ok_or(ParserError::NoUnimarkupDetected)?, + heading: self.read_inlines( + properties + .get("heading") + .ok_or(ParserError::NoUnimarkupDetected)? + .to_string(), + ), body: vec![], start: Position::new(1, 1), end: Position::new(1, 1), @@ -241,7 +254,7 @@ impl Umi { while current_line.depth > bullet_list_entry_depth { if current_line.depth == bullet_list_entry_depth + 1 { // Append Element to Bullet List Entry Body - let block = self.read_row(current_line_index); + let block = self.read_row(current_line_index)?; bullet_list_entry.body.append(&mut vec![block]); } else { break; @@ -256,13 +269,13 @@ impl Umi { current_line = fetched.unwrap_or_default(); } - Block::BulletListEntry(bullet_list_entry) + Ok(Block::BulletListEntry(bullet_list_entry)) } &_ => panic!(), } } - pub fn create_um(&mut self) -> Document { + pub fn create_um(&mut self) -> Result { self.elements.clear(); debug_assert!(!self.ods.is_empty()); @@ -327,7 +340,7 @@ impl Umi { let mut index = 0; while index < self.elements.len() { if self.elements[index].depth == 0 { - um.push(self.read_row(index)); + um.push(self.read_row(index)?); } index += 1; } @@ -343,14 +356,14 @@ impl Umi { ) .unwrap_or_default(); - Document { + Ok(Document { blocks: um, config, macros: vec![], variables: vec![], metadata: vec![], resources: vec![], - } + }) } } diff --git a/render/src/umi/render.rs b/render/src/umi/render.rs index 7d89a494..4ca4c7f5 100644 --- a/render/src/umi/render.rs +++ b/render/src/umi/render.rs @@ -44,13 +44,13 @@ impl Renderer for UmiRenderer { let content = self.render_inlines(¶graph.content, context)?; let hashmap: HashMap = HashMap::new(); - let typ = serde_json::to_string(&hashmap).unwrap_or(String::from("{}")); + let properties = serde_json::to_string(&hashmap).unwrap_or(String::from("{}")); let paragraph = UmiRow::new( self.pos, String::new(), String::from(Block::Paragraph(paragraph.to_owned()).variant_str()), - typ, + properties, self.depth, content.elements[0].content.clone(), String::new(), @@ -79,13 +79,13 @@ impl Renderer for UmiRenderer { String::from("implicit_closed"), verbatim.implicit_closed.to_string(), ); - let typ = serde_json::to_string(&hashmap).unwrap_or(String::from("{}")); + let properties = serde_json::to_string(&hashmap).unwrap_or(String::from("{}")); let verbatim = UmiRow::new( self.pos, String::new(), String::from("VerbatimBlock"), - typ, + properties, self.depth, verbatim.content.clone(), verbatim.attributes.clone().unwrap_or_default(), @@ -106,7 +106,7 @@ impl Renderer for UmiRenderer { ) -> Result { let mut hashmap: HashMap = HashMap::new(); hashmap.insert(String::from("level"), heading.level.as_str().to_string()); - let typ = serde_json::to_string(&hashmap).unwrap_or(String::from("{}")); + let properties = serde_json::to_string(&hashmap).unwrap_or(String::from("{}")); let content = self.render_inlines(&heading.content, context)?; @@ -114,7 +114,7 @@ impl Renderer for UmiRenderer { self.pos, heading.id.clone(), String::from("Heading"), - typ, + properties, self.depth, content.elements[0].content.clone(), heading.attributes.clone().unwrap_or_default(), @@ -134,13 +134,13 @@ impl Renderer for UmiRenderer { context: &Context, ) -> Result { let hashmap: HashMap = HashMap::new(); - let typ = serde_json::to_string(&hashmap).unwrap_or(String::from("{}")); + let properties = serde_json::to_string(&hashmap).unwrap_or(String::from("{}")); let bullet_list_heading = UmiRow::new( self.pos, String::new(), String::from("BulletList"), - typ, + properties, self.depth, String::new(), String::new(), @@ -179,7 +179,7 @@ impl Renderer for UmiRenderer { .content .clone(), ); - let typ = serde_json::to_string(&hashmap).unwrap_or(String::from("{}")); + let properties = serde_json::to_string(&hashmap).unwrap_or(String::from("{}")); let mut entry = Umi::with_um( vec![UmiRow::new( self.pos, @@ -187,7 +187,7 @@ impl Renderer for UmiRenderer { Block::BulletListEntry(bullet_list_entry.to_owned()) .variant_str() .to_string(), - typ, + properties, self.depth, self.render_inlines(&bullet_list_entry.heading, context)? .elements[0] From 076adb3115387c9fbcc4ff3030fe9e71eeb009dc Mon Sep 17 00:00:00 2001 From: Sebastian Schneider Date: Wed, 20 Dec 2023 14:15:35 +0100 Subject: [PATCH 04/14] Add Specific Errors for umi Parsing --- render/src/log_id.rs | 15 +++++++++ render/src/umi/mod.rs | 73 +++++++++++++++++++++++++++++-------------- 2 files changed, 65 insertions(+), 23 deletions(-) diff --git a/render/src/log_id.rs b/render/src/log_id.rs index 61228ee6..52056f49 100644 --- a/render/src/log_id.rs +++ b/render/src/log_id.rs @@ -9,3 +9,18 @@ pub enum RenderError { #[error("Output format `append()` failed. See log: '{}: {}'", .0.event_id, .0.entry_id)] BadAppend(FinalizedEvent), } + +#[derive(Debug, Clone, ErrLogId, Error, PartialEq, Eq)] +pub enum ParserError { + #[error("The UMI Parser failed to parse the kind at Position {}.", .0)] + UnknownKind(u8), + + #[error("The UMI Parser failed to parse Property {} from Element at Position {}.", (.0).0, (.0).1)] + MissingProperty((String, u8)), + + #[error("The UMI Parser failed to parse Property Value {} from Element at Position {}.", (.0).0, (.0).1)] + InvalidPropertyValue((String, u8)), + + #[error("The UMI Parser failed to parse the corresponding document.")] + NoUnimarkupDetected, +} diff --git a/render/src/umi/mod.rs b/render/src/umi/mod.rs index fe8505fb..9415e3a7 100644 --- a/render/src/umi/mod.rs +++ b/render/src/umi/mod.rs @@ -1,9 +1,12 @@ use std::collections::HashMap; +use std::path::PathBuf; use crate::render::OutputFormat; +use crate::log_id::ParserError; use spreadsheet_ods::{read_ods_buf, write_ods_buf_uncompressed, Sheet, WorkBook}; -use unimarkup_commons::config::Config; +use unimarkup_commons::config::output::Output; +use unimarkup_commons::config::{Config, MergingConfig}; use unimarkup_commons::lexer::{ position::Position, symbol::SymbolKind, @@ -13,7 +16,6 @@ use unimarkup_inline::{ element::Inline, parser::{parse_inlines, InlineContext}, }; -use unimarkup_parser::log_id::ParserError; use unimarkup_parser::{ document::Document, elements::{ @@ -100,11 +102,11 @@ impl Umi { // Row 1: Config sheet.set_value(1, 0, 0); - sheet.set_value(1, 2, "config"); + sheet.set_value(1, 2, "Preamble"); sheet.set_value( 1, 4, - serde_yaml::to_string(&self.config).unwrap_or_default(), + serde_yaml::to_string(&self.config.preamble).unwrap_or_default(), ); for element in &self.elements { @@ -153,11 +155,17 @@ impl Umi { level: unimarkup_parser::elements::atomic::HeadingLevel::try_from( properties .get("level") - .ok_or(ParserError::NoUnimarkupDetected)? + .ok_or(ParserError::MissingProperty(( + "level".into(), + current_line.position, + )))? .as_str(), ) .ok() - .ok_or(ParserError::NoUnimarkupDetected)?, + .ok_or(ParserError::InvalidPropertyValue(( + "level".into(), + current_line.position, + )))?, content: self.read_inlines(current_line.content.clone()), attributes: Some(current_line.attributes), start: Position::new(1, 1), @@ -178,12 +186,18 @@ impl Umi { attributes: Some(current_line.attributes), implicit_closed: properties .get("implicit_closed") - .ok_or(ParserError::NoUnimarkupDetected)? + .ok_or(ParserError::MissingProperty(( + "implicit_closed".into(), + current_line.position, + )))? .parse() .unwrap_or_default(), tick_len: properties .get("tick_len") - .ok_or(ParserError::NoUnimarkupDetected)? + .ok_or(ParserError::MissingProperty(( + "tick_len".into(), + current_line.position, + )))? .parse() .unwrap_or_default(), start: Position::new(1, 1), @@ -230,16 +244,25 @@ impl Umi { keyword: TokenKind::from(SymbolKind::from( properties .get("keyword") - .ok_or(ParserError::NoUnimarkupDetected)? + .ok_or(ParserError::MissingProperty(( + "keyword".into(), + current_line.position, + )))? .as_str(), )) .try_into() .ok() - .ok_or(ParserError::NoUnimarkupDetected)?, + .ok_or(ParserError::InvalidPropertyValue(( + "keyword".into(), + current_line.position, + )))?, heading: self.read_inlines( properties .get("heading") - .ok_or(ParserError::NoUnimarkupDetected)? + .ok_or(ParserError::MissingProperty(( + "heading".into(), + current_line.position, + )))? .to_string(), ), body: vec![], @@ -271,7 +294,7 @@ impl Umi { Ok(Block::BulletListEntry(bullet_list_entry)) } - &_ => panic!(), + &_ => Err(ParserError::UnknownKind(current_line.position)), } } @@ -344,17 +367,21 @@ impl Umi { } index += 1; } - let mut config = self.config.clone(); - config.preamble = serde_yaml::from_str( - sheet - .cell(1, 4) - .unwrap_or_default() - .value - .as_cow_str_or("") - .to_string() - .as_str(), - ) - .unwrap_or_default(); + let config = Config { + preamble: serde_yaml::from_str( + sheet + .cell(1, 4) + .unwrap_or_default() + .value + .as_cow_str_or("") + .to_string() + .as_str(), + ) + .unwrap_or_default(), + output: Output::default(), + input: PathBuf::default(), + merging: MergingConfig::default(), + }; Ok(Document { blocks: um, From 5c60ef49a1067d112ca75f41f0c19ba9cc3d271d Mon Sep 17 00:00:00 2001 From: Sebastian Schneider Date: Mon, 25 Dec 2023 18:22:34 +0100 Subject: [PATCH 05/14] Add Test Case for Supported UMI --- cli/tests/umi.rs | 136 +++++++++++++++++++++++++++++++++++++++--- render/src/umi/mod.rs | 30 +++++----- 2 files changed, 144 insertions(+), 22 deletions(-) diff --git a/cli/tests/umi.rs b/cli/tests/umi.rs index 7e57a69f..0950756e 100644 --- a/cli/tests/umi.rs +++ b/cli/tests/umi.rs @@ -1,6 +1,11 @@ use std::path::PathBuf; -use unimarkup_core::{commons::config::Config, Unimarkup}; +use unimarkup_core::{ + commons::config::Config, + inline::element::{Inline, InlineElement}, + parser::{document::Document, elements::blocks::Block}, + Unimarkup, +}; fn compile_um(config: Config) -> Option { let source = std::fs::read_to_string(&config.input).ok()?; @@ -8,8 +13,125 @@ fn compile_um(config: Config) -> Option { Some(Unimarkup::parse(&source, config)) } +fn equals_inlines_output(input: &Vec, output: &Vec) -> bool { + assert_eq!( + input.len(), + output.len(), + "Parsed Inlines does not have the same number of elements" + ); + + let mut i = 0; + while i < output.len() { + assert_eq!( + input[i].as_unimarkup(), + output[i].as_unimarkup(), + "Inline contains wrong content" + ); + i += 1; + } + true +} + +fn equals_blocks_output(input: &Vec, output: &Vec) -> bool { + assert_eq!( + input.len(), + output.len(), + "Parsed Blocks does not have the same length as the input" + ); + + let mut i = 0; + while i < input.len() { + assert_eq!( + input[i].variant_str(), + output[i].variant_str(), + "Blocks did not match up at Index" + ); + let block_in = input[i].clone(); + let block_out = output[i].clone(); + match (block_in, block_out) { + (Block::Heading(block_in), Block::Heading(block_out)) => { + assert_eq!(block_in.id, block_out.id, "Heading ids do not match!"); + assert_eq!( + block_in.level, block_out.level, + "Heading Levels do not match!" + ); + assert!(equals_inlines_output(&block_in.content, &block_out.content)); + assert_eq!( + block_in.attributes, block_out.attributes, + "Heading Attributes do not match!" + ); + } + (Block::Paragraph(block_in), Block::Paragraph(block_out)) => { + assert!(equals_inlines_output(&block_in.content, &block_out.content)); + } + (Block::VerbatimBlock(block_in), Block::VerbatimBlock(block_out)) => { + assert_eq!( + block_in.content, block_out.content, + "Verbatim Content does not match" + ); + assert_eq!( + block_in.data_lang, block_out.data_lang, + "Verbatim Data_Lang does not match" + ); + assert_eq!( + block_in.attributes, block_out.attributes, + "Verbatim Attributes do not match" + ); + assert_eq!( + block_in.implicit_closed, block_out.implicit_closed, + "Verbatim Implicit_Closed does not match" + ); + assert_eq!( + block_in.tick_len, block_out.tick_len, + "Verbatim Tick-Len does not match" + ); + } + (Block::BulletList(block_in), Block::BulletList(block_out)) => { + assert_eq!( + block_in.entries.len(), + block_out.entries.len(), + "Bullet List entry count does not match" + ); + + let mut j = 0; + while j < block_in.entries.len() { + assert_eq!( + block_in.entries[j].keyword, block_out.entries[j].keyword, + "Bullet List Entry Keyword does not match" + ); + assert!(equals_inlines_output( + &block_in.entries[j].heading, + &block_out.entries[j].heading + )); + assert!(equals_blocks_output( + &block_in.entries[j].body, + &block_out.entries[j].body + )); + j += 1; + } + } + _ => return false, + } + + i += 1; + } + + true +} + +fn equals_umi_output(input: &Document, output: &Document) -> bool { + /* + assert_eq!( + input.config, output.config, + "Parsed UMI Config differs from original Config" + ); + */ + + equals_blocks_output(&input.blocks, &output.blocks) +} + #[test] -fn umi_loop() { +fn umi_supported() { let mut config = Config::default(); let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR")) .canonicalize() @@ -21,11 +143,11 @@ fn umi_loop() { let mut umi = um.render_umi().unwrap(); let workbook = umi.create_workbook(); - let looped_doc = workbook.create_um().map_err(|_| panic!()).unwrap(); + let looped_doc = &workbook.create_um().map_err(|_| panic!()).unwrap(); + let input = um.get_document(); - assert_eq!( - looped_doc.blocks.len(), - um.get_document().blocks.len(), - "Parsed UMI file differs from original UM." + assert!( + equals_umi_output(input, looped_doc), + "Output does not equal the Input" ); } diff --git a/render/src/umi/mod.rs b/render/src/umi/mod.rs index 9415e3a7..7aa78192 100644 --- a/render/src/umi/mod.rs +++ b/render/src/umi/mod.rs @@ -4,7 +4,9 @@ use std::path::PathBuf; use crate::render::OutputFormat; use crate::log_id::ParserError; -use spreadsheet_ods::{read_ods_buf, write_ods_buf_uncompressed, Sheet, WorkBook}; +use spreadsheet_ods::{ + read_ods_buf, write_ods_buf_uncompressed, Sheet, Value, ValueType, WorkBook, +}; use unimarkup_commons::config::output::Output; use unimarkup_commons::config::{Config, MergingConfig}; use unimarkup_commons::lexer::{ @@ -28,6 +30,14 @@ use unimarkup_parser::{ pub mod render; +fn unpack_content_safe(value: Value) -> String { + if value.value_type() == ValueType::Text { + value.as_str_or("").into() + } else { + value.as_cow_str_or("").into() + } +} + #[derive(Debug, Default, Clone)] pub struct UmiRow { position: u8, @@ -105,7 +115,7 @@ impl Umi { sheet.set_value(1, 2, "Preamble"); sheet.set_value( 1, - 4, + 5, serde_yaml::to_string(&self.config.preamble).unwrap_or_default(), ); @@ -167,7 +177,7 @@ impl Umi { current_line.position, )))?, content: self.read_inlines(current_line.content.clone()), - attributes: Some(current_line.attributes), + attributes: Some(current_line.attributes).filter(|s| !s.is_empty()), start: Position::new(1, 1), end: Position::new(1, 1), }; @@ -183,7 +193,7 @@ impl Umi { let verbatim = VerbatimBlock { content: current_line.content.clone(), data_lang: properties.get("data_lang").cloned(), - attributes: Some(current_line.attributes), + attributes: Some(current_line.attributes).filter(|s| !s.is_empty()), implicit_closed: properties .get("implicit_closed") .ok_or(ParserError::MissingProperty(( @@ -225,8 +235,6 @@ impl Umi { _ => break, }; bullet_list.entries.append(&mut vec![bullet_list_entry]); - } else { - break; } current_line_index += 1; @@ -279,8 +287,6 @@ impl Umi { // Append Element to Bullet List Entry Body let block = self.read_row(current_line_index)?; bullet_list_entry.body.append(&mut vec![block]); - } else { - break; } current_line_index += 1; @@ -341,13 +347,7 @@ impl Umi { .value .as_u8_opt() .unwrap_or(0), - sheet - .cell(row_index, 5) - .unwrap_or_default() - .value - .as_str_opt() - .unwrap_or_default() - .to_string(), + unpack_content_safe(sheet.cell(row_index, 5).unwrap_or_default().value), sheet .cell(row_index, 6) .unwrap_or_default() From 21c097fa8d9c176e720ca758ffbd4d270c526d85 Mon Sep 17 00:00:00 2001 From: Sebastian Schneider Date: Fri, 12 Jan 2024 13:53:00 +0100 Subject: [PATCH 06/14] Prevent Parsing of Default Values for Serde --- commons/src/config/preamble.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/commons/src/config/preamble.rs b/commons/src/config/preamble.rs index 779024b2..a3374db4 100644 --- a/commons/src/config/preamble.rs +++ b/commons/src/config/preamble.rs @@ -54,6 +54,7 @@ pub struct I18n { #[arg(long, value_parser = parse_to_hashset::, required = false, default_value = "")] #[serde(with = "locale::serde::multiple", default)] + #[serde(skip_serializing_if = "HashSet::is_empty")] pub output_langs: HashSet, } @@ -72,9 +73,11 @@ impl ConfigFns for I18n { #[derive(Args, Default, Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct RenderConfig { #[arg(long = "ignore-file", value_parser = parse_ignore_file, required = false, default_value = "")] + #[serde(skip_serializing_if = "HashSet::is_empty")] #[serde(default)] pub ignore: HashSet, #[arg(long, value_parser = parse_parameter, required = false, default_value = "")] + #[serde(skip_serializing_if = "HashMap::is_empty")] #[serde(default)] pub parameter: HashMap, #[arg(long)] @@ -103,8 +106,11 @@ impl ConfigFns for RenderConfig { #[derive(Args, Default, Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct Citedata { #[arg(long = "citation-style")] + #[serde(skip_serializing_if = "Option::is_none")] + #[serde(default)] pub style: Option, #[arg(long, value_parser = parse_to_hashset::, required = false, default_value = "")] + #[serde(skip_serializing_if = "HashSet::is_empty")] #[serde(default)] pub references: HashSet, } @@ -141,15 +147,23 @@ impl ConfigFns for Citedata { #[derive(Args, Default, Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct Metadata { #[arg(long)] + #[serde(skip_serializing_if = "Option::is_none")] + #[serde(default)] pub title: Option, #[arg(long, value_parser = parse_to_hashset::, required = false, default_value = "")] + #[serde(skip_serializing_if = "HashSet::is_empty")] #[serde(default)] pub authors: HashSet, #[arg(long)] + #[serde(skip_serializing_if = "Option::is_none")] + #[serde(default)] pub description: Option, #[arg(long)] + #[serde(skip_serializing_if = "Option::is_none")] + #[serde(default)] pub base: Option, #[arg(long, value_parser = parse_to_hashset::, required = false, default_value = "")] + #[serde(skip_serializing_if = "HashSet::is_empty")] #[serde(default)] pub fonts: HashSet, } From 197a1c3ae09f618186981acc21c53903c65f2fdf Mon Sep 17 00:00:00 2001 From: Sebastian Schneider Date: Fri, 19 Jan 2024 10:28:34 +0100 Subject: [PATCH 07/14] Parse Input File Path --- cli/tests/umi.rs | 2 -- render/src/umi/mod.rs | 26 ++++++++++++++++++++++++-- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/cli/tests/umi.rs b/cli/tests/umi.rs index 0950756e..f4ac5437 100644 --- a/cli/tests/umi.rs +++ b/cli/tests/umi.rs @@ -120,12 +120,10 @@ fn equals_blocks_output(input: &Vec, output: &Vec) -> bool { } fn equals_umi_output(input: &Document, output: &Document) -> bool { - /* assert_eq!( input.config, output.config, "Parsed UMI Config differs from original Config" ); - */ equals_blocks_output(&input.blocks, &output.blocks) } diff --git a/render/src/umi/mod.rs b/render/src/umi/mod.rs index 7aa78192..50be8ee4 100644 --- a/render/src/umi/mod.rs +++ b/render/src/umi/mod.rs @@ -110,9 +110,17 @@ impl Umi { String::from("attributes-") + self.lang.to_string().as_str(), ); - // Row 1: Config + let mut hashmap: HashMap = HashMap::new(); + hashmap.insert( + String::from("input_path"), + self.config.input.to_str().unwrap_or_default().to_string(), + ); + let properties = serde_json::to_string(&hashmap).unwrap_or(String::from("{}")); + + // Row 1: Preamble + Input File sheet.set_value(1, 0, 0); sheet.set_value(1, 2, "Preamble"); + sheet.set_value(1, 3, properties); sheet.set_value( 1, 5, @@ -367,6 +375,20 @@ impl Umi { } index += 1; } + + let hash_map_input: HashMap = serde_json::from_str( + sheet + .cell(1, 3) + .unwrap_or_default() + .value + .as_str_opt() + .unwrap_or_default(), + ) + .unwrap_or_default(); + + let input_path: PathBuf = + PathBuf::from(hash_map_input.get("input_path").unwrap_or(&String::new())); + let config = Config { preamble: serde_yaml::from_str( sheet @@ -379,7 +401,7 @@ impl Umi { ) .unwrap_or_default(), output: Output::default(), - input: PathBuf::default(), + input: input_path, merging: MergingConfig::default(), }; From bee173f6fa5b8e102e982133d92c69f911efdd9e Mon Sep 17 00:00:00 2001 From: Sebastian Schneider Date: Fri, 19 Jan 2024 11:54:31 +0100 Subject: [PATCH 08/14] Implement initial parsing for .umi => .html --- cli/src/compiler.rs | 18 +++++++++++------- cli/tests/umi.rs | 5 ++++- core/src/lib.rs | 11 +++++++++-- render/src/umi/mod.rs | 20 ++++++++++++-------- 4 files changed, 36 insertions(+), 18 deletions(-) diff --git a/cli/src/compiler.rs b/cli/src/compiler.rs index f16481ad..2746cfb0 100644 --- a/cli/src/compiler.rs +++ b/cli/src/compiler.rs @@ -1,6 +1,7 @@ //! Entry module for unimarkup-rs. use std::{ + ffi::OsStr, fs, path::{Path, PathBuf}, }; @@ -23,13 +24,16 @@ use crate::log_id::{GeneralError, GeneralInfo}; /// /// Returns a [`GeneralError`] if error occurs during compilation. pub fn compile(config: Config) -> Result<(), GeneralError> { - let source = fs::read_to_string(&config.input).map_err(|error| { - pipe!( - GeneralError::FileRead, - format!("Could not read file: '{:?}'", &config.input), - add: AddonKind::Info(format!("Cause: {}", error)) - ) - })?; + let source: String = match config.input.extension().and_then(OsStr::to_str) { + Some("umi") => unsafe { String::from_utf8_unchecked(fs::read(&config.input).unwrap()) }, + _ => fs::read_to_string(&config.input).map_err(|error| { + pipe!( + GeneralError::FileRead, + format!("Could not read file: '{:?}'", &config.input), + add: AddonKind::Info(format!("Cause: {}", error)) + ) + })?, + }; let out_path = { if let Some(ref out_file) = config.output.file { diff --git a/cli/tests/umi.rs b/cli/tests/umi.rs index f4ac5437..1163737c 100644 --- a/cli/tests/umi.rs +++ b/cli/tests/umi.rs @@ -4,6 +4,7 @@ use unimarkup_core::{ commons::config::Config, inline::element::{Inline, InlineElement}, parser::{document::Document, elements::blocks::Block}, + render::umi::Umi, Unimarkup, }; @@ -141,7 +142,9 @@ fn umi_supported() { let mut umi = um.render_umi().unwrap(); let workbook = umi.create_workbook(); - let looped_doc = &workbook.create_um().map_err(|_| panic!()).unwrap(); + let looped_doc = &Umi::create_um(workbook.to_string().as_str(), &mut workbook.config) + .map_err(|_| panic!()) + .unwrap(); let input = um.get_document(); assert!( diff --git a/core/src/lib.rs b/core/src/lib.rs index a680059e..cde2eeb2 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -1,3 +1,5 @@ +use std::ffi::OsStr; + pub use unimarkup_commons as commons; pub use unimarkup_inline as inline; pub use unimarkup_parser as parser; @@ -25,8 +27,13 @@ impl Unimarkup { /// * `um_content` - String containing Unimarkup elements. /// * `config` - Unimarkup configuration to be used on top of preambles. pub fn parse(um_content: &str, mut config: Config) -> Self { - Unimarkup { - doc: parser::parse_unimarkup(um_content, &mut config), + match config.input.extension().and_then(OsStr::to_str) { + Some("umi") => Unimarkup { + doc: Umi::create_um(um_content, &mut config).unwrap(), + }, + _ => Unimarkup { + doc: parser::parse_unimarkup(um_content, &mut config), + }, } } diff --git a/render/src/umi/mod.rs b/render/src/umi/mod.rs index 50be8ee4..38155499 100644 --- a/render/src/umi/mod.rs +++ b/render/src/umi/mod.rs @@ -312,16 +312,20 @@ impl Umi { } } - pub fn create_um(&mut self) -> Result { - self.elements.clear(); - debug_assert!(!self.ods.is_empty()); + pub fn create_um(um_content: &str, config: &mut Config) -> Result { + let mut umi = Umi::with_um( + vec![], + config.clone(), + config.preamble.i18n.lang.to_string().to_owned(), + ); + umi.ods = um_content.into(); - let wb: WorkBook = read_ods_buf(&self.ods).unwrap_or_default(); + let wb: WorkBook = read_ods_buf(&umi.ods).unwrap_or_default(); let sheet = wb.sheet(0); let rows = sheet.used_grid_size().0; for row_index in 2..rows { - self.elements.push(UmiRow::new( + umi.elements.push(UmiRow::new( sheet .cell(row_index, 0) .unwrap_or_default() @@ -369,9 +373,9 @@ impl Umi { let mut um: Vec = vec![]; let mut index = 0; - while index < self.elements.len() { - if self.elements[index].depth == 0 { - um.push(self.read_row(index)?); + while index < umi.elements.len() { + if umi.elements[index].depth == 0 { + um.push(umi.read_row(index)?); } index += 1; } From ab69504653e5502ad56d43fed9fcbdff871b6d35 Mon Sep 17 00:00:00 2001 From: Sebastian Schneider Date: Tue, 23 Jan 2024 11:21:53 +0100 Subject: [PATCH 09/14] Implement Reviewed Changes --- cli/tests/umi.rs | 45 ++++++++++----------------- render/src/log_id.rs | 9 ++++-- render/src/umi/mod.rs | 67 +++++++++++++++++++++------------------- render/src/umi/render.rs | 7 ----- 4 files changed, 57 insertions(+), 71 deletions(-) diff --git a/cli/tests/umi.rs b/cli/tests/umi.rs index 1163737c..9e25908a 100644 --- a/cli/tests/umi.rs +++ b/cli/tests/umi.rs @@ -1,3 +1,4 @@ +use std::iter::zip; use std::path::PathBuf; use unimarkup_core::{ @@ -21,14 +22,12 @@ fn equals_inlines_output(input: &Vec, output: &Vec) -> bool { "Parsed Inlines does not have the same number of elements" ); - let mut i = 0; - while i < output.len() { + for (in_elem, out_elem) in zip(input.iter(), output.iter()) { assert_eq!( - input[i].as_unimarkup(), - output[i].as_unimarkup(), + in_elem.as_unimarkup(), + out_elem.as_unimarkup(), "Inline contains wrong content" - ); - i += 1; + ) } true } @@ -40,15 +39,14 @@ fn equals_blocks_output(input: &Vec, output: &Vec) -> bool { "Parsed Blocks does not have the same length as the input" ); - let mut i = 0; - while i < input.len() { + for (in_elem, out_elem) in zip(input.iter(), output.iter()) { assert_eq!( - input[i].variant_str(), - output[i].variant_str(), + in_elem.variant_str(), + out_elem.variant_str(), "Blocks did not match up at Index" ); - let block_in = input[i].clone(); - let block_out = output[i].clone(); + let block_in = in_elem.clone(); + let block_out = out_elem.clone(); match (block_in, block_out) { (Block::Heading(block_in), Block::Heading(block_out)) => { assert_eq!(block_in.id, block_out.id, "Heading ids do not match!"); @@ -94,27 +92,18 @@ fn equals_blocks_output(input: &Vec, output: &Vec) -> bool { "Bullet List entry count does not match" ); - let mut j = 0; - while j < block_in.entries.len() { + for (in_entry, out_entry) in zip(block_in.entries.iter(), block_out.entries.iter()) + { assert_eq!( - block_in.entries[j].keyword, block_out.entries[j].keyword, + in_entry.keyword, out_entry.keyword, "Bullet List Entry Keyword does not match" ); - assert!(equals_inlines_output( - &block_in.entries[j].heading, - &block_out.entries[j].heading - )); - assert!(equals_blocks_output( - &block_in.entries[j].body, - &block_out.entries[j].body - )); - j += 1; + assert!(equals_inlines_output(&in_entry.heading, &out_entry.heading)); + assert!(equals_blocks_output(&in_entry.body, &out_entry.body)); } } _ => return false, } - - i += 1; } true @@ -142,9 +131,7 @@ fn umi_supported() { let mut umi = um.render_umi().unwrap(); let workbook = umi.create_workbook(); - let looped_doc = &Umi::create_um(workbook.to_string().as_str(), &mut workbook.config) - .map_err(|_| panic!()) - .unwrap(); + let looped_doc = &Umi::create_um(workbook.to_string().as_str(), &mut workbook.config).unwrap(); let input = um.get_document(); assert!( diff --git a/render/src/log_id.rs b/render/src/log_id.rs index 52056f49..c048764c 100644 --- a/render/src/log_id.rs +++ b/render/src/log_id.rs @@ -11,8 +11,8 @@ pub enum RenderError { } #[derive(Debug, Clone, ErrLogId, Error, PartialEq, Eq)] -pub enum ParserError { - #[error("The UMI Parser failed to parse the kind at Position {}.", .0)] +pub enum UmiParserError { + #[error("The UMI Parser failed to parse the Element Kind at Position {}.", .0)] UnknownKind(u8), #[error("The UMI Parser failed to parse Property {} from Element at Position {}.", (.0).0, (.0).1)] @@ -21,6 +21,9 @@ pub enum ParserError { #[error("The UMI Parser failed to parse Property Value {} from Element at Position {}.", (.0).0, (.0).1)] InvalidPropertyValue((String, u8)), - #[error("The UMI Parser failed to parse the corresponding document.")] + #[error("The UMI Parser failed to parse the corresponding Document.")] NoUnimarkupDetected, + + #[error("The UMI Parser failed to parse the Element at Position {}, because it has not Parent Element wwith Depth 0.", .0)] + MissingParentElement(u8), } diff --git a/render/src/umi/mod.rs b/render/src/umi/mod.rs index 38155499..954e6c05 100644 --- a/render/src/umi/mod.rs +++ b/render/src/umi/mod.rs @@ -3,7 +3,7 @@ use std::path::PathBuf; use crate::render::OutputFormat; -use crate::log_id::ParserError; +use crate::log_id::UmiParserError; use spreadsheet_ods::{ read_ods_buf, write_ods_buf_uncompressed, Sheet, Value, ValueType, WorkBook, }; @@ -162,7 +162,7 @@ impl Umi { } } - fn read_row(&mut self, line: usize) -> Result { + fn read_row(&mut self, line: usize) -> Result { let mut current_line = self.elements[line].clone(); let properties: HashMap = serde_json::from_str(¤t_line.properties).unwrap_or_default(); @@ -173,21 +173,21 @@ impl Umi { level: unimarkup_parser::elements::atomic::HeadingLevel::try_from( properties .get("level") - .ok_or(ParserError::MissingProperty(( + .ok_or(UmiParserError::MissingProperty(( "level".into(), current_line.position, )))? .as_str(), ) .ok() - .ok_or(ParserError::InvalidPropertyValue(( + .ok_or(UmiParserError::InvalidPropertyValue(( "level".into(), current_line.position, )))?, content: self.read_inlines(current_line.content.clone()), attributes: Some(current_line.attributes).filter(|s| !s.is_empty()), - start: Position::new(1, 1), - end: Position::new(1, 1), + start: Position::new(1, 1), // Fallback in case content has been changed manually in .umi + end: Position::new(1, 1), // Fallback in case content has been changed manually in .umi }; Ok(Block::Heading(heading)) } @@ -199,12 +199,12 @@ impl Umi { } "VerbatimBlock" => { let verbatim = VerbatimBlock { - content: current_line.content.clone(), + content: current_line.content.clone(), // TODO: use inline parser, but only allow 'logic' and plain text data_lang: properties.get("data_lang").cloned(), attributes: Some(current_line.attributes).filter(|s| !s.is_empty()), implicit_closed: properties .get("implicit_closed") - .ok_or(ParserError::MissingProperty(( + .ok_or(UmiParserError::MissingProperty(( "implicit_closed".into(), current_line.position, )))? @@ -212,22 +212,22 @@ impl Umi { .unwrap_or_default(), tick_len: properties .get("tick_len") - .ok_or(ParserError::MissingProperty(( + .ok_or(UmiParserError::MissingProperty(( "tick_len".into(), current_line.position, )))? .parse() .unwrap_or_default(), - start: Position::new(1, 1), - end: Position::new(1, 1), + start: Position::new(1, 1), // Fallback in case content has been changed manually in .umi + end: Position::new(1, 1), // Fallback in case content has been changed manually in .umi }; Ok(Block::VerbatimBlock(verbatim)) } "BulletList" => { let mut bullet_list = BulletList { entries: vec![], - start: Position::new(1, 1), - end: Position::new(1, 1), + start: Position::new(1, 1), // Fallback in case content has been changed manually in .umi + end: Position::new(1, 1), // Fallback in case content has been changed manually in .umi }; let bullet_list_depth = current_line.depth; @@ -246,11 +246,10 @@ impl Umi { } current_line_index += 1; - let fetched = self.fetch_next_line(current_line_index); - if fetched.is_none() { + let Some(fetched) = self.fetch_next_line(current_line_index) else { break; - } - current_line = fetched.unwrap_or_default(); + }; + current_line = fetched; } Ok(Block::BulletList(bullet_list)) @@ -260,7 +259,7 @@ impl Umi { keyword: TokenKind::from(SymbolKind::from( properties .get("keyword") - .ok_or(ParserError::MissingProperty(( + .ok_or(UmiParserError::MissingProperty(( "keyword".into(), current_line.position, )))? @@ -268,22 +267,14 @@ impl Umi { )) .try_into() .ok() - .ok_or(ParserError::InvalidPropertyValue(( + .ok_or(UmiParserError::InvalidPropertyValue(( "keyword".into(), current_line.position, )))?, - heading: self.read_inlines( - properties - .get("heading") - .ok_or(ParserError::MissingProperty(( - "heading".into(), - current_line.position, - )))? - .to_string(), - ), + heading: self.read_inlines(current_line.content.clone()), body: vec![], - start: Position::new(1, 1), - end: Position::new(1, 1), + start: Position::new(1, 1), // Fallback in case content has been changed manually in .umi + end: Position::new(1, 1), // Fallback in case content has been changed manually in .umi }; let bullet_list_entry_depth = current_line.depth; @@ -308,11 +299,11 @@ impl Umi { Ok(Block::BulletListEntry(bullet_list_entry)) } - &_ => Err(ParserError::UnknownKind(current_line.position)), + &_ => Err(UmiParserError::UnknownKind(current_line.position)), } } - pub fn create_um(um_content: &str, config: &mut Config) -> Result { + pub fn create_um(um_content: &str, config: &mut Config) -> Result { let mut umi = Umi::with_um( vec![], config.clone(), @@ -320,18 +311,23 @@ impl Umi { ); umi.ods = um_content.into(); + //let mut language_content_index = 5; + //let mut language_attributes_index = 5; + let wb: WorkBook = read_ods_buf(&umi.ods).unwrap_or_default(); let sheet = wb.sheet(0); let rows = sheet.used_grid_size().0; for row_index in 2..rows { umi.elements.push(UmiRow::new( + // position sheet .cell(row_index, 0) .unwrap_or_default() .value .as_u8_opt() .unwrap_or(0), + // id sheet .cell(row_index, 1) .unwrap_or_default() @@ -339,6 +335,7 @@ impl Umi { .as_str_opt() .unwrap_or_default() .to_string(), + // kind sheet .cell(row_index, 2) .unwrap_or_default() @@ -346,6 +343,7 @@ impl Umi { .as_str_opt() .unwrap_or_default() .to_string(), + // properties sheet .cell(row_index, 3) .unwrap_or_default() @@ -353,13 +351,16 @@ impl Umi { .as_str_opt() .unwrap_or_default() .to_string(), + // depth sheet .cell(row_index, 4) .unwrap_or_default() .value .as_u8_opt() .unwrap_or(0), + // content unpack_content_safe(sheet.cell(row_index, 5).unwrap_or_default().value), + // attributes sheet .cell(row_index, 6) .unwrap_or_default() @@ -376,6 +377,8 @@ impl Umi { while index < umi.elements.len() { if umi.elements[index].depth == 0 { um.push(umi.read_row(index)?); + } else { + // TODO Warn if a proper parent element is missing } index += 1; } diff --git a/render/src/umi/render.rs b/render/src/umi/render.rs index 4ca4c7f5..1ec258ae 100644 --- a/render/src/umi/render.rs +++ b/render/src/umi/render.rs @@ -172,13 +172,6 @@ impl Renderer for UmiRenderer { String::from("keyword"), bullet_list_entry.keyword.as_str().to_string(), ); - hashmap.insert( - String::from("heading"), - self.render_inlines(&bullet_list_entry.heading, context)? - .elements[0] - .content - .clone(), - ); let properties = serde_json::to_string(&hashmap).unwrap_or(String::from("{}")); let mut entry = Umi::with_um( vec![UmiRow::new( From 1d408d150bf64236f18f46ccb838ccb34f2a9994 Mon Sep 17 00:00:00 2001 From: Sebastian Schneider Date: Tue, 23 Jan 2024 12:22:55 +0100 Subject: [PATCH 10/14] Add Localization --- render/src/umi/mod.rs | 127 ++++++++++++++++++++++++++++-------------- 1 file changed, 84 insertions(+), 43 deletions(-) diff --git a/render/src/umi/mod.rs b/render/src/umi/mod.rs index 954e6c05..96418b76 100644 --- a/render/src/umi/mod.rs +++ b/render/src/umi/mod.rs @@ -7,8 +7,7 @@ use crate::log_id::UmiParserError; use spreadsheet_ods::{ read_ods_buf, write_ods_buf_uncompressed, Sheet, Value, ValueType, WorkBook, }; -use unimarkup_commons::config::output::Output; -use unimarkup_commons::config::{Config, MergingConfig}; +use unimarkup_commons::config::Config; use unimarkup_commons::lexer::{ position::Position, symbol::SymbolKind, @@ -38,6 +37,37 @@ fn unpack_content_safe(value: Value) -> String { } } +fn retrieve_localised_content(sheet: &Sheet, row_index: u32, col_index: u32) -> String { + let content_localised = + unpack_content_safe(sheet.cell(row_index, col_index).unwrap_or_default().value); + if content_localised.is_empty() { + unpack_content_safe(sheet.cell(row_index, 5).unwrap_or_default().value) + } else { + content_localised + } +} + +fn retrieve_localised_attributes(sheet: &Sheet, row_index: u32, col_index: u32) -> String { + let attributes_localised = sheet + .cell(row_index, col_index) + .unwrap_or_default() + .value + .as_str_opt() + .unwrap_or_default() + .to_string(); + if attributes_localised.is_empty() { + sheet + .cell(row_index, 6) + .unwrap_or_default() + .value + .as_str_opt() + .unwrap_or_default() + .to_string() + } else { + attributes_localised + } +} + #[derive(Debug, Default, Clone)] pub struct UmiRow { position: u8, @@ -311,13 +341,59 @@ impl Umi { ); umi.ods = um_content.into(); - //let mut language_content_index = 5; - //let mut language_attributes_index = 5; - let wb: WorkBook = read_ods_buf(&umi.ods).unwrap_or_default(); let sheet = wb.sheet(0); let rows = sheet.used_grid_size().0; + // Load Stored Config Values from Sheet + let hash_map_input: HashMap = serde_json::from_str( + sheet + .cell(1, 3) + .unwrap_or_default() + .value + .as_str_opt() + .unwrap_or_default(), + ) + .unwrap_or_default(); + let input_path: PathBuf = + PathBuf::from(hash_map_input.get("input_path").unwrap_or(&String::new())); + + umi.config.preamble = serde_yaml::from_str( + sheet + .cell(1, 4) + .unwrap_or_default() + .value + .as_cow_str_or("") + .to_string() + .as_str(), + ) + .unwrap_or_default(); + umi.config.input = input_path; + + // Determine the correct column for parsing Locale Content and Attributes + let mut index = 5; + let mut localised_content_index = 0; + let mut localised_attributes_index = 0; + loop { + let next = sheet + .cell(0, index) + .unwrap_or_default() + .value + .as_str_opt() + .unwrap_or_default() + .to_string(); + if next.is_empty() { + break; + } + if next == (String::from("content-") + umi.lang.as_str()) { + localised_content_index = index; + } + if next == (String::from("attributes-") + umi.lang.as_str()) { + localised_attributes_index = index; + } + index += 1; + } + for row_index in 2..rows { umi.elements.push(UmiRow::new( // position @@ -359,15 +435,9 @@ impl Umi { .as_u8_opt() .unwrap_or(0), // content - unpack_content_safe(sheet.cell(row_index, 5).unwrap_or_default().value), + retrieve_localised_content(sheet, row_index, localised_content_index), // attributes - sheet - .cell(row_index, 6) - .unwrap_or_default() - .value - .as_str_opt() - .unwrap_or_default() - .to_string(), + retrieve_localised_attributes(sheet, row_index, localised_attributes_index), )) } @@ -383,38 +453,9 @@ impl Umi { index += 1; } - let hash_map_input: HashMap = serde_json::from_str( - sheet - .cell(1, 3) - .unwrap_or_default() - .value - .as_str_opt() - .unwrap_or_default(), - ) - .unwrap_or_default(); - - let input_path: PathBuf = - PathBuf::from(hash_map_input.get("input_path").unwrap_or(&String::new())); - - let config = Config { - preamble: serde_yaml::from_str( - sheet - .cell(1, 4) - .unwrap_or_default() - .value - .as_cow_str_or("") - .to_string() - .as_str(), - ) - .unwrap_or_default(), - output: Output::default(), - input: input_path, - merging: MergingConfig::default(), - }; - Ok(Document { blocks: um, - config, + config: umi.config.clone(), macros: vec![], variables: vec![], metadata: vec![], From f4f5e187b3f063c4fdd18395a502d355bec0021f Mon Sep 17 00:00:00 2001 From: Sebastian Schneider Date: Wed, 24 Jan 2024 12:31:52 +0100 Subject: [PATCH 11/14] Add Constants for Default Columns --- render/src/umi/mod.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/render/src/umi/mod.rs b/render/src/umi/mod.rs index 96418b76..2c257a45 100644 --- a/render/src/umi/mod.rs +++ b/render/src/umi/mod.rs @@ -37,11 +37,14 @@ fn unpack_content_safe(value: Value) -> String { } } +const DEFAULT_CONTENT_COLUMN: u32 = 5; +const DEFAULT_ATTRIBUTES_COLUMN: u32 = 6; + fn retrieve_localised_content(sheet: &Sheet, row_index: u32, col_index: u32) -> String { let content_localised = unpack_content_safe(sheet.cell(row_index, col_index).unwrap_or_default().value); if content_localised.is_empty() { - unpack_content_safe(sheet.cell(row_index, 5).unwrap_or_default().value) + unpack_content_safe(sheet.cell(row_index, DEFAULT_CONTENT_COLUMN).unwrap_or_default().value) } else { content_localised } @@ -57,7 +60,7 @@ fn retrieve_localised_attributes(sheet: &Sheet, row_index: u32, col_index: u32) .to_string(); if attributes_localised.is_empty() { sheet - .cell(row_index, 6) + .cell(row_index, DEFAULT_ATTRIBUTES_COLUMN) .unwrap_or_default() .value .as_str_opt() @@ -382,7 +385,7 @@ impl Umi { .as_str_opt() .unwrap_or_default() .to_string(); - if next.is_empty() { + if (localised_content_index != 0 && localised_attributes_index != 0) || next.is_empty() { break; } if next == (String::from("content-") + umi.lang.as_str()) { From 39d86c53c906b571e9ffec720062ac799938bffb Mon Sep 17 00:00:00 2001 From: Sebastian Schneider Date: Wed, 24 Jan 2024 12:36:37 +0100 Subject: [PATCH 12/14] Generalize Column matching --- render/src/umi/mod.rs | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/render/src/umi/mod.rs b/render/src/umi/mod.rs index 2c257a45..8b4b95bc 100644 --- a/render/src/umi/mod.rs +++ b/render/src/umi/mod.rs @@ -44,7 +44,12 @@ fn retrieve_localised_content(sheet: &Sheet, row_index: u32, col_index: u32) -> let content_localised = unpack_content_safe(sheet.cell(row_index, col_index).unwrap_or_default().value); if content_localised.is_empty() { - unpack_content_safe(sheet.cell(row_index, DEFAULT_CONTENT_COLUMN).unwrap_or_default().value) + unpack_content_safe( + sheet + .cell(row_index, DEFAULT_CONTENT_COLUMN) + .unwrap_or_default() + .value, + ) } else { content_localised } @@ -385,13 +390,14 @@ impl Umi { .as_str_opt() .unwrap_or_default() .to_string(); - if (localised_content_index != 0 && localised_attributes_index != 0) || next.is_empty() { + if (localised_content_index != 0 && localised_attributes_index != 0) || next.is_empty() + { break; } - if next == (String::from("content-") + umi.lang.as_str()) { + if next.to_lowercase() == (String::from("content-") + umi.lang.as_str()) { localised_content_index = index; } - if next == (String::from("attributes-") + umi.lang.as_str()) { + if next.to_lowercase() == (String::from("attributes-") + umi.lang.as_str()) { localised_attributes_index = index; } index += 1; From acbb8a49ac9fcae1b3d3d972a7b5844d8d6aa066 Mon Sep 17 00:00:00 2001 From: Sebastian Schneider Date: Wed, 24 Jan 2024 16:04:20 +0100 Subject: [PATCH 13/14] Rework Pattern Matching to avoid mismatches --- render/src/umi/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/render/src/umi/mod.rs b/render/src/umi/mod.rs index 8b4b95bc..477350b2 100644 --- a/render/src/umi/mod.rs +++ b/render/src/umi/mod.rs @@ -394,10 +394,10 @@ impl Umi { { break; } - if next.to_lowercase() == (String::from("content-") + umi.lang.as_str()) { + if next == (String::from("content-") + umi.lang.as_str()) { localised_content_index = index; } - if next.to_lowercase() == (String::from("attributes-") + umi.lang.as_str()) { + if next == (String::from("attributes-") + umi.lang.as_str()) { localised_attributes_index = index; } index += 1; From 60987916a0a44614f7331b7e7d834706375f8057 Mon Sep 17 00:00:00 2001 From: Sebastian Schneider <65763422+SeppFS@users.noreply.github.com> Date: Mon, 29 Jan 2024 13:50:53 +0100 Subject: [PATCH 14/14] Use const for Index Initialisation Co-authored-by: Manuel Hatzl <49341624+mhatzl@users.noreply.github.com> --- render/src/umi/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/render/src/umi/mod.rs b/render/src/umi/mod.rs index 477350b2..0b09beb1 100644 --- a/render/src/umi/mod.rs +++ b/render/src/umi/mod.rs @@ -379,7 +379,7 @@ impl Umi { umi.config.input = input_path; // Determine the correct column for parsing Locale Content and Attributes - let mut index = 5; + let mut index = DEFAULT_CONTENT_COLUMN; let mut localised_content_index = 0; let mut localised_attributes_index = 0; loop {