Skip to content

feat(inspector): choose the CSV escape character (doubled quote or backslash)#1944

Merged
datlechin merged 2 commits into
mainfrom
feat/1469-csv-escape-char
Jul 22, 2026
Merged

feat(inspector): choose the CSV escape character (doubled quote or backslash)#1944
datlechin merged 2 commits into
mainfrom
feat/1469-csv-escape-char

Conversation

@datlechin

Copy link
Copy Markdown
Member

Part 6 (final) toward #1469 (CSV structural editing). The escape character field, completing the Set CSV Properties dialog. Stacked on #1943 (base branch feat/1469-csv-properties).

What

  • Set CSV Properties… gains an Escape character picker: a doubled quote (the RFC 4180 default) or a backslash. Files that escape an embedded quote as \" now read and save correctly.

Why

csvmenu.cpp in Tablecruncher and DataGrip's format dialog both let you pick the escape mechanism, because real exports (notably MySQL) use backslash escaping instead of RFC 4180 quote doubling. This was the one property from #1469's dialog not yet wired.

How

  • CSVDialect gains an escapeChar field, defaulting to the quote byte (so the default is unchanged RFC 4180 behavior). It is a new stored property with a default; the existing public initializer is untouched, so this is additive to PluginKit (no version bump).
  • CSVStreamingParser (indexRows, parseRow, field) honors the escape byte inside a quoted field only when it differs from the quote byte; when they are equal the existing doubled-quote path runs unchanged, so every existing file parses exactly as before.
  • CSVWriter escapes an embedded quote (and the escape byte itself) with the escape character in backslash mode, and keeps doubling quotes in the default mode.
  • The picker choice threads through the pure CSVPropertyOptions mapping into the reload dialect.

Tests

  • Parser: backslash escape decodes \" to a quote and \\ to a backslash; the doubled-quote default is unchanged.
  • Writer: doubles quotes by default, escapes with a backslash in backslash mode.
  • CSVDialect.escapeChar defaults to the quote byte; CSVPropertyOptions maps the escape choice into the dialect.

Docs / changelog

  • docs/features/csv-inspector.mdx notes the escape-character choice.
  • CHANGELOG entry under [Unreleased].

Needs a local Xcode build to confirm compilation. PluginKit changes (a new CSVDialect field and parser method-body changes) are additive; no version bump.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d7190600eb

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".


public var delimiter: UInt8
public var quoteChar: UInt8
public var escapeChar: UInt8 = 0x22

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Keep doubled escaping synchronized with the quote character

When a dialect uses a single quote as its quote character, this fixed 0x22 default makes the parser treat doubled single quotes as a close quote rather than an escape. This regresses the CSV importer: CSVImportParsing.resolveDialect changes quoteChar for its existing Single quote option but leaves this new property at 0x22, so input such as 'It''s fine',x is decoded incorrectly (and embedded delimiters/newlines after an escaped quote can also be mis-tokenized). The inspector likewise allows selecting Single Quote together with “Doubled Quote,” but that combination writes/parses using a literal double-quote escape instead of doubling the selected quote character.

Useful? React with 👍 / 👎.

@datlechin
datlechin force-pushed the feat/1469-csv-properties branch from a48d85a to 31a66c0 Compare July 22, 2026 03:37
@datlechin
datlechin force-pushed the feat/1469-csv-escape-char branch from d719060 to 429a4dc Compare July 22, 2026 03:40
@datlechin

Copy link
Copy Markdown
Member Author

Addressed a code review. Findings and fixes:

  • Doubled-quote escape bug: the "Doubled Quote" escape option hardcoded byte 0x22 instead of tracking the selected quote character, so pairing Single Quote with Doubled Quote produced quoteChar=0x27, escapeChar=0x22 and flipped the parser into backslash mode, corrupting single-quote-doubled files. Fixed: CSVDialect.init now defaults escapeChar to quoteChar, and the options mapping resolves "Doubled Quote" to the selected quote char.
  • Added a field(at:column:) backslash-escape test and quote-tracking tests.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 429a4dcfd9

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +86 to +89
if escape != quote, byte == escape, i + 1 < end {
field.append(bytes[i + 1])
i += 2
continue

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve backslashes before ordinary characters

With Backslash selected for files that use it only to escape quotes, a quoted value containing a literal backslash before an ordinary character is corrupted: for example, "C:\new" is decoded as C:new. This branch consumes the escape byte before any following byte, whereas only \" and \\ are emitted by the writer. Restrict escaping to the quote and escape characters (and make the analogous paths in field and indexRows agree) so ordinary backslashes survive imports.

Useful? React with 👍 / 👎.

@datlechin
datlechin force-pushed the feat/1469-csv-properties branch from 31a66c0 to 1e9c6e6 Compare July 22, 2026 03:53
@datlechin
datlechin force-pushed the feat/1469-csv-escape-char branch from 429a4dc to 9282c8d Compare July 22, 2026 03:53
@datlechin
datlechin force-pushed the feat/1469-csv-properties branch from 1e9c6e6 to 6a09a40 Compare July 22, 2026 03:56
@datlechin
datlechin force-pushed the feat/1469-csv-escape-char branch from 9282c8d to 3998ab8 Compare July 22, 2026 03:56
@datlechin
datlechin force-pushed the feat/1469-csv-properties branch from 6a09a40 to 31cdb39 Compare July 22, 2026 06:52
@datlechin
datlechin force-pushed the feat/1469-csv-escape-char branch from 3998ab8 to d9a208c Compare July 22, 2026 06:52
@datlechin
datlechin force-pushed the feat/1469-csv-properties branch from 31cdb39 to 1b2c45a Compare July 22, 2026 07:00
@datlechin
datlechin force-pushed the feat/1469-csv-escape-char branch from d9a208c to 3b7af82 Compare July 22, 2026 07:00
@datlechin
datlechin force-pushed the feat/1469-csv-properties branch from 1b2c45a to a04770b Compare July 22, 2026 07:02
@datlechin
datlechin force-pushed the feat/1469-csv-escape-char branch from 3b7af82 to 89d708a Compare July 22, 2026 07:02
Base automatically changed from feat/1469-csv-properties to main July 22, 2026 07:03
@mintlify

mintlify Bot commented Jul 22, 2026

Copy link
Copy Markdown

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated (UTC)
TablePro 🟢 Ready View Preview Jul 22, 2026, 7:04 AM

💡 Tip: Enable Workflows to automatically generate PRs for you.

@datlechin
datlechin merged commit a022d90 into main Jul 22, 2026
2 of 3 checks passed
@datlechin
datlechin deleted the feat/1469-csv-escape-char branch July 22, 2026 07:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant