mirror of
https://github.com/storytold/gridcraft.git
synced 2026-11-05 10:08:59 +00:00
#3166: a web page opens after a leading comment and keeps its non-breaking spaces
Addresses CodeRabbit review on #3223: - "Skip leading HTML comments before the prefix check": a page starting with an exporter's <!-- comment --> was read as CSV text. Complete leading comments are now skipped before looking for the page's start. - "Preserve nonbreaking spaces in HTML text imports": split_whitespace turned New York into "New York". The decoded cell text is used as is (ordinary whitespace is already collapsed), so the non-breaking spaces stay, as Excel keeps them. Test: a_web_page_table_opens_after_a_leading_comment_and_keeps_nonbreaking_spaces. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
e23994b7cb
commit
48c52e14af
2 files changed
+23
-2
No files matched your search
+11
-2
@@ -357,7 +357,15 @@ fn part_too_large_message(name: &str, part: &str, size: u64) -> String {
|
||||
fn read_html_table(name: &str, kind: Option<FileKind>, bytes: &[u8], csv_as_text: bool) -> Option<Result<(Workbook, Vec<String>)>> {
|
||||
// Decoded as a CSV is (BOM, UTF-8, else Windows-1252/1256), so a legacy page keeps its letters.
|
||||
let text = gridcraft_xlsx::decode_text(bytes);
|
||||
let head: String = text.trim_start_matches('\u{feff}').trim_start().chars().take(16).collect::<String>().to_ascii_lowercase();
|
||||
// Comments an exporter writes before the page (`<!-- ... -->`) don't make it something else.
|
||||
let mut rest = text.trim_start_matches('\u{feff}').trim_start();
|
||||
while let Some(after) = rest.strip_prefix("<!--") {
|
||||
match after.find("-->").and_then(|end| after.get(end + 3..)) {
|
||||
Some(more) => rest = more.trim_start(),
|
||||
None => break,
|
||||
}
|
||||
}
|
||||
let head: String = rest.chars().take(16).collect::<String>().to_ascii_lowercase();
|
||||
if !["<!doctype html", "<html", "<table", "<head", "<body", "<meta"].iter().any(|t| head.starts_with(t)) {
|
||||
return None;
|
||||
}
|
||||
@@ -375,7 +383,8 @@ fn read_html_table(name: &str, kind: Option<FileKind>, bytes: &[u8], csv_as_text
|
||||
// cell keeps the text it shows.
|
||||
let field = match cell.num.filter(|_| !csv_as_text) {
|
||||
Some(n) => gridcraft_core::number_to_text(n),
|
||||
None => cell.text.split_whitespace().collect::<Vec<_>>().join(" "),
|
||||
// Whitespace is already collapsed; non-breaking spaces stay, as in Excel.
|
||||
None => cell.text.clone(),
|
||||
};
|
||||
if field.contains(['\t', '\n', '\r', '"']) { format!("\"{}\"", field.replace('"', "\"\"")) } else { field }
|
||||
})
|
||||
|
||||
@@ -656,3 +656,15 @@ fn a_web_page_table_keeps_its_characters_text_and_header_formats() {
|
||||
let (wb, _) = open_bytes_with("menu.xls", &page, None, true).unwrap();
|
||||
assert_eq!(wb.sheet(0).unwrap().value(CellRef::parse("B2").unwrap()), gridcraft_core::Value::text("4,50"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_web_page_table_opens_after_a_leading_comment_and_keeps_nonbreaking_spaces() {
|
||||
// An exporter's comment before <html> still makes a web page; ` ` stays a non-breaking
|
||||
// space, as Excel keeps it, while ordinary whitespace collapses.
|
||||
let page = "<!-- exported by a web app -->\n<html><body><table><tr><td>New York</td><td>a \n b</td></tr></table></body></html>";
|
||||
let (wb, warnings) = open_bytes("cities.xls", page.as_bytes()).unwrap();
|
||||
assert!(warnings.first().is_some_and(|w| w.contains("is a web page (HTML)")), "{warnings:?}");
|
||||
let sh = wb.sheet(0).unwrap();
|
||||
assert_eq!(sh.value(CellRef::parse("A1").unwrap()), gridcraft_core::Value::text("New\u{a0}\u{a0}York"));
|
||||
assert_eq!(sh.value(CellRef::parse("B1").unwrap()), gridcraft_core::Value::text("a b"));
|
||||
}
|
||||
Reference in new issue
Block a user