1
0
Fork 0
mirror of https://github.com/lise-henry/crowbook synced 2024-05-27 13:06:15 +02:00

Remove warnings

This commit is contained in:
Elisabeth Henry 2023-08-05 02:48:08 +02:00
parent 6b0f4b7637
commit 487864ffbb
5 changed files with 195 additions and 483 deletions

View File

@ -33,7 +33,6 @@ output.html:path # {output_html}
output.html.dir:path # {output_html_dir}
output.tex:path # {output_tex}
output.pdf:path # {output_pdf}
output.odt:path # {output_odt}
output.html.if:path # {output_if}
output.base_path:path:\"\" # {output_base_path}
@ -201,6 +200,8 @@ proofread.repetitions.fuzzy:bool:true # {removed}
proofread.repetitions.fuzzy.threshold:float:0.2 # {removed}
proofread.repetitions.ignore_proper:bool:true # {removed}
proofread.repetitions.threshold:float:2.0 # {removed}
output.odt:path # {removed}
",
metadata = lformat!("Metadata"),
metadata2 = lformat!("Additional metadata"),
@ -236,7 +237,6 @@ proofread.repetitions.threshold:float:2.0 # {removed}
output_html = lformat!("Output file name for HTML rendering"),
output_tex = lformat!("Output file name for LaTeX rendering"),
output_pdf = lformat!("Output file name for PDF rendering"),
output_odt = lformat!("Output file name for ODT rendering"),
output_if = lformat!("Output file name for HTML (interactive fiction) rendering"),
output_html_dir = lformat!("Output directory name for HTML rendering"),
output_base_path = lformat!("Directory where those output files will we written"),
@ -835,7 +835,6 @@ impl BookOptions {
| "output.html.dir"
| "output.pdf"
| "output.tex"
| "output.odt"
| "output.proofread.html"
| "output.proofread.html.dir"
| "output.proofread.pdf"

View File

@ -28,7 +28,6 @@ use crate::syntax::Syntax;
use crate::token::Data;
use crate::token::Token;
use crate::text_view;
use crate::misc;
use std::borrow::Cow;
use std::convert::{AsMut, AsRef};

View File

@ -145,8 +145,6 @@ mod html_single;
mod lang;
mod latex;
mod number;
#[cfg(feature = "odt")]
mod odt;
mod parser;
mod renderer;
mod resource_handler;

View File

@ -1,284 +0,0 @@
use crate::book::{compile_str, Book};
use crate::book_renderer::BookRenderer;
use crate::error::Result;
use crate::number::Number;
use crate::parser::Parser;
use crate::templates::odt;
use crate::token::Token;
use crate::zipper::Zipper;
use crowbook_text_processing::escape;
use std::io::Write;
/// Rendererer for ODT
///
/// Still very experimental.
pub struct OdtRenderer<'a> {
book: &'a Book,
current_numbering: i32,
current_hide: bool,
current_chapter: i32,
automatic_styles: String,
}
impl<'a> OdtRenderer<'a> {
/// Creates a new OdtRenderer
pub fn new(book: &'a Book) -> OdtRenderer {
OdtRenderer {
book,
current_chapter: 1,
current_numbering: book.options.get_i32("rendering.num_depth").unwrap(),
current_hide: false,
automatic_styles: String::from(
"
<style:style style:name=\"T1\" \
style:family=\"text\">
<style:text-properties \
fo:font-style=\"italic\" \
style:font-style-asian=\"italic\" \
style:font-style-complex=\"italic\"/>
</style:style>
\
<style:style style:name=\"T2\" \
style:family=\"text\">
<style:text-properties \
fo:font-weight=\"bold\" \
style:font-weight-asian=\"bold\" \
style:font-weight-complex=\"bold\"/>
</style:style>",
),
}
}
/// Renders a full book
///
/// This will try to generate an ODT file according to self.book options.
///
/// # Returns
/// * `Ok(s)` where `s` contains the output of the `zip` command
/// used to create the ODT file.
/// * An error if there was somel problem during either the rendering to
/// ODT format, or the generation of the ODT file itself.
pub fn render_book(&mut self, to: &mut dyn Write) -> Result<String> {
let content = self.render_content()?;
let mut zipper = Zipper::new(&self.book.options.get_path("crowbook.temp_dir").unwrap())?;
// Write template.odt there
zipper.write("template.odt", odt::ODT, false)?;
// unzip it
zipper.unzip("template.odt")?;
// Complete it with content.xml
zipper.write("content.xml", content.as_bytes(), false)?;
// Zip and copy
zipper.generate_odt(
self.book.options.get_str("crowbook.zip.command").unwrap(),
to,
)
}
/// Render content.xml
fn render_content(&mut self) -> Result<String> {
// Print a warning for the features that aren't supported in ODT.
let mut missing = vec![];
if self.book.features.image {
missing.push(lformat!("images"));
}
if self.book.features.blockquote {
missing.push(lformat!("blockquotes"));
}
if self.book.features.codeblock {
missing.push(lformat!("codeblocks"));
}
if self.book.features.ordered_list {
missing.push(lformat!("ordered lists"));
}
if self.book.features.footnote {
missing.push(lformat!("footnotes"));
}
if self.book.features.table {
missing.push(lformat!("tables"));
}
if self.book.features.superscript {
missing.push(lformat!("superscript"));
}
if self.book.features.subscript {
missing.push(lformat!("subscript"));
}
if !missing.is_empty() {
let missing = missing.join(", ");
warn!("{}", lformat!("ODT: The document uses the following features, that are not implemented for ODT output: {features}. They will be ignored in the generated document.",
features = missing));
}
let mut content = String::new();
for chapter in &self.book.chapters {
let n = chapter.number;
let v = &chapter.content;
self.current_hide = false;
match n {
Number::Unnumbered | Number::UnnumberedPart => self.current_numbering = 0,
Number::Default | Number::DefaultPart => {
self.current_numbering =
self.book.options.get_i32("rendering.num_depth").unwrap()
}
Number::Specified(n) | Number::SpecifiedPart(n) => {
self.current_numbering = self.book.options.get_i32("numbering").unwrap();
self.current_chapter = n;
}
Number::Hidden => {
self.current_numbering = 0;
self.current_hide = true;
}
}
if n.is_part() {
error!("{}", lformat!("Parts are not supported yet in ODT"));
}
for token in v {
content.push_str(&self.parse_token(token));
}
}
let template = compile_str(
odt::CONTENT,
&self.book.source,
"could not compile template for content.xml",
)?;
let data = self
.book
.get_metadata(|s| Ok(s.to_owned()))?
.insert_str("content", content)
.insert_str("automatic_styles", self.automatic_styles.clone())
.build();
let mut res: Vec<u8> = vec![];
template.render_data(&mut res, &data)?;
match String::from_utf8(res) {
Err(_) => panic!("{}", lformat!("generated content.xml was not utf-8 valid")),
Ok(res) => Ok(res),
}
}
/// Transform a vector of `Token`s to Odt format
fn render_vec(&mut self, tokens: &[Token]) -> String {
let mut res = String::new();
for token in tokens {
res.push_str(&self.parse_token(token));
}
res
}
fn parse_token(&mut self, token: &Token) -> String {
match *token {
Token::Str(ref text) => escape::html(self.book.clean(text.as_str())).into_owned(),
Token::Paragraph(ref vec) => {
format!(
"<text:p text:style-name=\"Text_20_body\">{}</text:p>\n",
self.render_vec(vec)
)
}
Token::Header(n, ref vec) => {
if n == 1 && self.current_hide {
return String::new();
}
let s = if n == 1 && self.current_numbering >= 1 {
let chapter = self.current_chapter;
self.current_chapter += 1;
let res = self
.book
.get_chapter_header(chapter, self.render_vec(vec), |s| {
Ok(self.render_vec(&Parser::new().parse_inline(s)?))
});
res.unwrap().text
} else {
self.render_vec(vec)
};
format!(
"<text:h text:style-name=\"Heading_20_{}\">\n{}</text:h>\n",
n, s
)
}
Token::Emphasis(ref vec) => {
format!(
"<text:span text:style-name=\"T1\">{}</text:span>",
self.render_vec(vec)
)
}
Token::Strong(ref vec) => {
format!(
"<text:span text:style-name=\"T2\">{}</text:span>",
self.render_vec(vec)
)
}
Token::List(ref vec) => format!("<text:list>\n{}</text:list>\n", self.render_vec(vec)),
Token::OrderedList(_, ref vec) => {
format!("<text:list>\n{}</text:list>\n", self.render_vec(vec))
}
Token::Item(ref vec) => {
format!(
"<text:list-item>\n<text:p>{}</text:p></text:list-item>",
self.render_vec(vec)
)
}
Token::Link(ref url, _, ref vec) => {
format!(
"<text:a xlink:type=\"simple\" xlink:href=\"{}\">{}</text:a>",
url,
self.render_vec(vec)
)
}
Token::Code(ref s) => {
format!(
"<text:span text:style-name=\"Preformatted_20_Text\">{}</text:span>",
s
)
}
Token::Subscript(ref vec) | Token::Superscript(ref vec) => self.render_vec(vec),
Token::BlockQuote(ref vec) => format!(
"<text:p text:style-name=\"Text_20_Body\">{}</text:p>\n",
self.render_vec(vec)
),
Token::CodeBlock(_, ref s) => {
format!("<text:p text:style-name=\"Text_20_Body\">{}</text:p>\n", s)
}
Token::SoftBreak | Token::HardBreak => String::from(" "),
Token::Rule => String::from("<text:p /><text:p>***</text:p><text:p />"),
Token::Image(_, _, _) | Token::StandaloneImage(_, _, _) => String::from(" "),
Token::Table(_, _) | Token::TableHead(_) | Token::TableRow(_) | Token::TableCell(_) => {
String::from(" ")
}
Token::FootnoteReference(..) | Token::FootnoteDefinition(..) => String::new(),
Token::Annotation(_, ref vec) => self.render_vec(vec),
Token::DescriptionList(ref v)
| Token::DescriptionItem(ref v)
| Token::DescriptionTerm(ref v)
| Token::DescriptionDetails(ref v)
| Token::Strikethrough(ref v)
| Token::TaskItem(_, ref v) => {
warn!(
"{}",
lformat!("ODT: Description list and strikethrough not handled in this output")
);
self.render_vec(v)
}
}
}
}
pub struct Odt {}
impl BookRenderer for Odt {
fn auto_path(&self, book_name: &str) -> Result<String> {
Ok(format!("{}.odt", book_name))
}
fn render(&self, book: &Book, to: &mut dyn Write) -> Result<()> {
OdtRenderer::new(book).render_book(to)?;
Ok(())
}
}

View File

@ -16,9 +16,7 @@
// along with Crowbook. If not, see <http://www.gnu.org/licenses/>.
use std::default::Default;
use std::mem;
use crate::token::Data;
use crate::token::Token;
pub fn traverse_token<F1, F2, R>(token: &Token, f: &F1, add: &F2) -> R
@ -67,210 +65,212 @@ pub fn view_as_text(tokens: &[Token]) -> String {
traverse_vec(tokens, &|s| s.to_owned(), &|s1, s2| s1 + &s2)
}
pub fn count_length(tokens: &[Token]) -> usize {
traverse_vec(tokens, &|s| s.chars().count(), &|s1, s2| s1 + s2)
}
// Should it be removed?
// pub fn count_length(tokens: &[Token]) -> usize {
// traverse_vec(tokens, &|s| s.chars().count(), &|s1, s2| s1 + s2)
// }
/// Insert an annotation at begin and end pos begin+len in the text_view
#[doc(hidden)]
pub fn insert_annotation(
tokens: &mut Vec<Token>,
annotation: &Data,
pos: usize,
length: usize,
) -> Option<usize> {
let mut pos = pos;
let mut found_left = None;
let mut found_right = None;
for (i, item) in tokens.iter_mut().enumerate() {
let recurse = match item {
Token::Str(ref s) => {
let len = s.chars().count();
if pos < len || (pos == len && found_left.is_some()) {
// We found the first element already, so now it's the right
if found_left.is_some() {
found_right = Some((i, pos));
break;
}
found_left = Some((i, pos));
pos += length;
if pos <= len {
found_right = Some((i, pos));
break;
}
}
pos -= len;
false
}
// Should it be removed ?
// #[doc(hidden)]
// pub fn insert_annotation(
// tokens: &mut Vec<Token>,
// annotation: &Data,
// pos: usize,
// length: usize,
// ) -> Option<usize> {
// let mut pos = pos;
// let mut found_left = None;
// let mut found_right = None;
// for (i, item) in tokens.iter_mut().enumerate() {
// let recurse = match item {
// Token::Str(ref s) => {
// let len = s.chars().count();
// if pos < len || (pos == len && found_left.is_some()) {
// // We found the first element already, so now it's the right
// if found_left.is_some() {
// found_right = Some((i, pos));
// break;
// }
// found_left = Some((i, pos));
// pos += length;
// if pos <= len {
// found_right = Some((i, pos));
// break;
// }
// }
// pos -= len;
// false
// }
Token::Rule | Token::SoftBreak | Token::HardBreak => {
if pos < 1 {
if found_left.is_some() {
found_right = Some((i, pos));
break;
}
found_left = Some((i, pos));
pos += length;
if pos <= 1 {
found_right = Some((i, pos));
break;
}
}
pos -= 1;
false
}
// Token::Rule | Token::SoftBreak | Token::HardBreak => {
// if pos < 1 {
// if found_left.is_some() {
// found_right = Some((i, pos));
// break;
// }
// found_left = Some((i, pos));
// pos += length;
// if pos <= 1 {
// found_right = Some((i, pos));
// break;
// }
// }
// pos -= 1;
// false
// }
_ => {
if let Some(inner) = item.inner() {
let len = count_length(inner);
// Only recurse if the two is in this subtree
if pos < len {
if found_left.is_none() {
true
} else {
warn!(
"{}",
lformat!(
"ignored annotation {:?} as it \
wasn't compatible with the \
Markdown structure",
annotation
)
);
return None;
}
} else {
pos -= len;
false
}
} else {
false
}
}
};
// _ => {
// if let Some(inner) = item.inner() {
// let len = count_length(inner);
// // Only recurse if the two is in this subtree
// if pos < len {
// if found_left.is_none() {
// true
// } else {
// warn!(
// "{}",
// lformat!(
// "ignored annotation {:?} as it \
// wasn't compatible with the \
// Markdown structure",
// annotation
// )
// );
// return None;
// }
// } else {
// pos -= len;
// false
// }
// } else {
// false
// }
// }
// };
// Moved out of the match 'thanks' to borrowcheck
if recurse {
if let Some(ref mut inner) = item.inner_mut() {
if let Some(new_pos) = insert_annotation(inner, annotation, pos, length) {
pos = new_pos;
} else {
return None;
}
}
}
}
// // Moved out of the match 'thanks' to borrowcheck
// if recurse {
// if let Some(ref mut inner) = item.inner_mut() {
// if let Some(new_pos) = insert_annotation(inner, annotation, pos, length) {
// pos = new_pos;
// } else {
// return None;
// }
// }
// }
// }
if let (Some((i, pos_left)), Some((j, pos_right))) = (found_left, found_right) {
let pos_right = pos_right;
let mut vec = vec![];
// if let (Some((i, pos_left)), Some((j, pos_right))) = (found_left, found_right) {
// let pos_right = pos_right;
// let mut vec = vec![];
// Beginning token: keep the left part in the str, put the right one in our vec
if !tokens[i].is_str() || pos_left == 0 {
// do nothing
} else {
let old_token = mem::replace(&mut tokens[i], Token::Str(String::new()));
if let Token::Str(old_str) = old_token {
let mut chars_left: Vec<char> = old_str.chars().collect();
let mut chars_right = chars_left.split_off(pos_left);
// // Beginning token: keep the left part in the str, put the right one in our vec
// if !tokens[i].is_str() || pos_left == 0 {
// // do nothing
// } else {
// let old_token = mem::replace(&mut tokens[i], Token::Str(String::new()));
// if let Token::Str(old_str) = old_token {
// let mut chars_left: Vec<char> = old_str.chars().collect();
// let mut chars_right = chars_left.split_off(pos_left);
let str_left: String = chars_left.into_iter().collect();
tokens[i] = Token::Str(str_left);
// let str_left: String = chars_left.into_iter().collect();
// tokens[i] = Token::Str(str_left);
if i == j {
// i and j are in same str, so split again
if length != chars_right.len() {
let inline_token = chars_right.split_off(length);
let inline_token = Token::Str(inline_token.into_iter().collect());
if pos_left == 0 {
tokens.insert(i, inline_token)
} else if i == tokens.len() {
tokens.push(inline_token);
} else {
tokens.insert(i + 1, inline_token);
}
}
let annot = Token::Annotation(
annotation.clone(),
vec![Token::Str(chars_right.into_iter().collect())],
);
if pos_left == 0 {
tokens.insert(i, annot)
} else if i == tokens.len() {
tokens.push(annot);
} else {
tokens.insert(i + 1, annot);
}
return None;
}
// if i == j {
// // i and j are in same str, so split again
// if length != chars_right.len() {
// let inline_token = chars_right.split_off(length);
// let inline_token = Token::Str(inline_token.into_iter().collect());
// if pos_left == 0 {
// tokens.insert(i, inline_token)
// } else if i == tokens.len() {
// tokens.push(inline_token);
// } else {
// tokens.insert(i + 1, inline_token);
// }
// }
// let annot = Token::Annotation(
// annotation.clone(),
// vec![Token::Str(chars_right.into_iter().collect())],
// );
// if pos_left == 0 {
// tokens.insert(i, annot)
// } else if i == tokens.len() {
// tokens.push(annot);
// } else {
// tokens.insert(i + 1, annot);
// }
// return None;
// }
let str_right: String = chars_right.into_iter().collect();
vec.push(Token::Str(str_right));
} else {
unreachable!();
}
}
// let str_right: String = chars_right.into_iter().collect();
// vec.push(Token::Str(str_right));
// } else {
// unreachable!();
// }
// }
// Middle tokens: remove them entirely and put them in our vec
for _ in i + 1..j {
vec.push(tokens.remove(i + 1));
}
// // Middle tokens: remove them entirely and put them in our vec
// for _ in i + 1..j {
// vec.push(tokens.remove(i + 1));
// }
// End token: keep the right part in the str, put the left one in our vec
// j is now i + 1 because all tokens in between have been removed
// unless j was equal to i to begin with
let j = if i == j || i >= tokens.len() - 1 {
i
} else {
i + 1
};
// // End token: keep the right part in the str, put the left one in our vec
// // j is now i + 1 because all tokens in between have been removed
// // unless j was equal to i to begin with
// let j = if i == j || i >= tokens.len() - 1 {
// i
// } else {
// i + 1
// };
if !tokens[j].is_str() {
// do nothing
} else {
let count = if let Token::Str(ref s) = tokens[j] {
s.chars().count()
} else {
unreachable!()
};
if count != pos_right {
let old_token = mem::replace(&mut tokens[j], Token::Rule);
if let Token::Str(old_str) = old_token {
let mut chars_left: Vec<char> = old_str.chars().collect();
let chars_right = chars_left.split_off(pos_right);
let str_left: String = chars_left.into_iter().collect();
let str_right: String = chars_right.into_iter().collect();
tokens[j] = Token::Str(str_right);
// todo: if only one token, maybe concat the strings
vec.push(Token::Str(str_left));
} else {
unreachable!();
}
}
}
let new_token = Token::Annotation(annotation.clone(), vec);
if pos_left == 0 {
tokens.insert(i, new_token);
} else if i >= tokens.len() - 1 {
tokens.push(new_token);
} else {
tokens.insert(i + 1, new_token);
}
None
} else if found_left.is_none() && found_right.is_none() {
Some(pos)
} else {
warn!(
"{}",
lformat!(
"ignored annotation {:?} as it wasn't compatible \
with the Markdown structure",
annotation
)
);
None
}
}
// if !tokens[j].is_str() {
// // do nothing
// } else {
// let count = if let Token::Str(ref s) = tokens[j] {
// s.chars().count()
// } else {
// unreachable!()
// };
// if count != pos_right {
// let old_token = mem::replace(&mut tokens[j], Token::Rule);
// if let Token::Str(old_str) = old_token {
// let mut chars_left: Vec<char> = old_str.chars().collect();
// let chars_right = chars_left.split_off(pos_right);
// let str_left: String = chars_left.into_iter().collect();
// let str_right: String = chars_right.into_iter().collect();
// tokens[j] = Token::Str(str_right);
// // todo: if only one token, maybe concat the strings
// vec.push(Token::Str(str_left));
// } else {
// unreachable!();
// }
// }
// }
// let new_token = Token::Annotation(annotation.clone(), vec);
// if pos_left == 0 {
// tokens.insert(i, new_token);
// } else if i >= tokens.len() - 1 {
// tokens.push(new_token);
// } else {
// tokens.insert(i + 1, new_token);
// }
// None
// } else if found_left.is_none() && found_right.is_none() {
// Some(pos)
// } else {
// warn!(
// "{}",
// lformat!(
// "ignored annotation {:?} as it wasn't compatible \
// with the Markdown structure",
// annotation
// )
// );
// None
// }
// }
#[test]
fn test_text_view() {