fix: quote CSV fields only when required

This commit is contained in:
Valdemar Lorenzen
2026-10-21 10:35:43 +02:00
parent c533e71ecc
commit 138490eecd
4 changed files with 27 additions and 9 deletions
+21 -6
View File
@@ -677,6 +677,10 @@ fn append_record<'a>(
if index > 0 {
output.push(',');
}
if !value.contains([',', '"', '\r', '\n']) {
output.push_str(value);
continue;
}
output.push('"');
for character in value.chars() {
if character == '"' {
@@ -755,6 +759,17 @@ fn moved_index(selected: Option<usize>, count: usize, delta: isize) -> Option<us
mod tests {
use super::moved_index;
#[test]
fn csv_quotes_only_fields_with_delimiters_quotes_or_line_breaks() {
let mut output = String::new();
super::append_record(
&mut output,
["42", "00123", "界", "", "a,b", "a\"b", "a\rb", "a\nb"].into_iter(),
false,
);
assert_eq!(output, "42,00123,界,,\"a,b\",\"a\"\"b\",\"a\rb\",\"a\nb\"\r\n");
}
#[test]
fn rectangular_selection_copies_full_cells_and_resets_on_data_changes() -> crate::Result<()> {
use super::{App, Focus};
@@ -799,14 +814,14 @@ mod tests {
);
assert_eq!(
app.selection_text(true, false).as_deref(),
Some("\"b\",\"c\"\r\n\"a|b\",\"say \"\"hi\"\",界\"\r\n\"NULL\",\"<&>\\tail\"\r\n")
Some("b,c\r\na|b,\"say \"\"hi\"\",界\"\r\nNULL,<&>\\tail\r\n")
);
assert_eq!(
app.selection_text(false, false).as_deref(),
Some("\"a|b\",\"say \"\"hi\"\",界\"\r\n\"NULL\",\"<&>\\tail\"\r\n")
Some("a|b,\"say \"\"hi\"\",界\"\r\nNULL,<&>\\tail\r\n")
);
assert!(app.handle_rows_command(KeyEvent::new(KeyCode::Esc, KeyModifiers::NONE)));
assert_eq!(app.selection_text(false, false).as_deref(), Some("\"a|b\"\r\n"));
assert_eq!(app.selection_text(false, false).as_deref(), Some("a|b\r\n"));
// A prefix cancels on focus changes rather than capturing a later key.
app.handle_rows_command(key('y'));
assert!(!app.handle_rows_command(KeyEvent::new(KeyCode::Tab, KeyModifiers::NONE)));
@@ -814,7 +829,7 @@ mod tests {
app.handle_rows_command(key('v'));
app.handle_key(key('n'));
assert!(app.selection_anchor.is_none());
assert_eq!(app.selection_text(false, false).as_deref(), Some("\"101\"\r\n"));
assert_eq!(app.selection_text(false, false).as_deref(), Some("101\r\n"));
app.handle_rows_command(key('v'));
app.handle_key(key('s'));
assert!(app.selection_anchor.is_none());
@@ -824,11 +839,11 @@ mod tests {
app.query.value = "SELECT 42 AS answer".into();
app.execute_query();
assert!(app.selection_anchor.is_none());
assert_eq!(app.selection_text(true, false).as_deref(), Some("\"answer\"\r\n\"42\"\r\n"));
assert_eq!(app.selection_text(true, false).as_deref(), Some("answer\r\n42\r\n"));
app.handle_rows_command(key('v'));
app.query.value = "SELECT missing FROM nowhere".into();
app.execute_query();
assert_eq!(app.selection_text(false, false).as_deref(), Some("\"42\"\r\n"));
assert_eq!(app.selection_text(false, false).as_deref(), Some("42\r\n"));
assert!(app.selection_anchor.is_some());
app.open_relation(Some(0));
assert!(app.selection_anchor.is_none());