Skip to content

feat(editor): add Copy SQL Without Comments action - #1172

Merged
debba merged 1 commit into
TabularisDB:mainfrom
chiliec:feat/copy-sql-without-comments
Oct 19, 2026
Merged

debba merged 1 commit into
TabularisDB:mainfrom
chiliec:feat/copy-sql-without-comments

Conversation

@chiliec

@chiliec chiliec commented Oct 17, 2026

Copy link
Copy Markdown
Contributor

What

Adds a Copy SQL Without Comments editor context-menu action (issue #1161). It copies the current selection — or the whole document when there is no selection — with ordinary line and block comments removed.

Why

Sharing a statement often means manually deleting explanatory comments while being careful not to touch strings or executable SQL annotations. This does that in one action.

How

  • New pure helper src/utils/stripSqlComments.ts reuses the existing SQL tokenizer (scanToken) so the quote/comment dialect rules stay defined in one place. It:
    • preserves quoted identifiers, string literals, dollar-quoted bodies, optimizer hints and executable comments (/*! … */ and MariaDB /*M! … */);
    • replaces a comment that sits between two non-whitespace characters with a single space so adjacent tokens do not merge;
    • returns the input unchanged for an undefined/unknown dialect (same fail-safe direction as scanNonCodeSpans), and uses the tab's declared dialect — not a hardcoded driver id.
  • src/pages/Editor.tsx registers the action next to the existing editor actions and copies via the existing copyTextToClipboard. It reads the editor model and never mutates the document.
  • One new English string (editor.copyWithoutComments); other locales fall back to English, consistent with the current partial locale files.

Tests

tests/utils/stripSqlComments.test.ts (19 cases): line/block/#/nested comments, SELECT 1--1 subtraction vs -- comment per dialect, strings and identifiers that contain comment markers, dollar-quoted bodies, /*! and /*M! executable comments kept, multi-statement input, unknown/undefined dialect pass-through, and the no-merge spacing rule.

Validation (run locally)

  • pnpm exec vitest run tests/utils/stripSqlComments.test.ts → 19 passed
  • pnpm exec tsc -b → clean
  • pnpm exec eslint src/pages/Editor.tsx src/utils/stripSqlComments.ts → 0 errors
  • node scripts/check-theme-tokens.mjs → OK
  • Related suites pnpm exec vitest run tests/utils/sqlAnalysis.test.ts tests/utils/sql → 523 passed

Note: the repo's full vitest run needs the jsdom environment, which requires Node ≥ 22.12 (require(ESM)); I ran on Node 22.20. The new tests are environment-agnostic.

Comment thread src/pages/Editor.tsx
: ed.getValue();
if (!source) return;
const stripped = stripSqlComments(source, activeDialectRef.current);
void copyTextToClipboard(stripped);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

WARNING: Clipboard failures are silently dropped as an unhandled rejection

copyTextToClipboard rethrows when no onError callback is passed, and void discards the returned promise, so a failed navigator.clipboard.writeText becomes an unhandled promise rejection and the user gets no feedback. Pass an onError handler (e.g. surface the existing alert/toast) so the failure is handled.


Reply with @kilocode-bot fix it to have Kilo Code address this issue.

import {
dialectOptions,
type Dialect,
type DialectOptions,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

SUGGESTION: Dialect allow-list duplicates the splitter's dialect table

DIALECTS re-declares the supported dialect ids, while scanNonCodeSpans validates against DIALECT_TABLE with Object.hasOwn. If a dialect is added to the splitter, this set must be updated separately or stripSqlComments silently returns the input unchanged for it. Consider exporting a shared guard from sqlSplitter (or reusing scanNonCodeSpans's check) so the rules stay in one place, as the file header intends.


Reply with @kilocode-bot fix it to have Kilo Code address this issue.

@kilo-code-bot

kilo-code-bot Bot commented Oct 17, 2026 •

Copy link
Copy Markdown
Contributor

Code Review Summary

Status: 1 Issue Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 0
WARNING 1
SUGGESTION 0
Issue Details (click to expand)

WARNING

File Line Issue
src/pages/Editor.tsx 4102 void copyTextToClipboard(stripped) has no onError, so a clipboard failure rethrows as an unhandled promise rejection with no user feedback
Files Reviewed (14 files)
  • src/i18n/locales/*.json (11 files)
  • src/pages/Editor.tsx - 1 issue
  • src/utils/stripSqlComments.ts
  • tests/utils/stripSqlComments.test.ts

Fix these issues in Kilo Cloud

Previous Review Summary (commit 3cc7f57)

Current summary above is authoritative. Previous snapshots are kept for context only.

Previous review (commit 3cc7f57)

Status: 2 Issues Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 0
WARNING 1
SUGGESTION 1
Issue Details (click to expand)

WARNING

File Line Issue
src/pages/Editor.tsx 4079 void copyTextToClipboard(stripped) has no onError, so a clipboard failure rethrows as an unhandled promise rejection with no user feedback

SUGGESTION

File Line Issue
src/utils/stripSqlComments.ts 9 DIALECTS duplicates the splitter's dialect table; it can drift from DIALECT_TABLE and silently pass SQL through unchanged for a new dialect
Files Reviewed (4 files)
  • src/i18n/locales/en.json
  • src/pages/Editor.tsx - 1 issue
  • src/utils/stripSqlComments.ts - 1 issue
  • tests/utils/stripSqlComments.test.ts

Fix these issues in Kilo Cloud


Reviewed by claude-sonnet-5.5 · Input: 254 · Output: 1.9K · Cached: 299.7K

Review guidance: REVIEW.md from base branch main

@debba debba left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Thanks for working on this! Reusing scanToken from the splitter instead of writing yet another lexer is the right call, and it shows: I threw a bunch of awkward inputs at it (MySQL 1--1, # comments, markers inside strings and quoted identifiers, backslash escapes, E-strings, dollar quotes, Oracle q-quotes, [a -- b] on SQL Server, nested comments) and they all came out right. The a/**/b → a b spacing rule is a nice detail too.

There are a few things I need changed before this can go in, though:

  1. Optimizer hints are stripped. The description (and #1161) say hints are preserved, but isExecutableBlockComment only keeps /*M! (and /*! survives because the tokenizer treats it as data). Nothing keeps /*+. For example SELECT /*+ INDEX(t idx) */ * FROM t becomes SELECT * FROM t on MySQL, Oracle and Postgres (pg_hint_plan), and Oracle's --+ FULL(t) form is removed too. That silently changes the plan of the copied query. Please keep hint comments and add tests for them.
  2. It breaks once rebased on main. The branch is about 15 commits behind. Since #1200, activeDialect in Editor.tsx is a SqlSyntax object from resolveSqlSyntax(activeCapabilities), not a string, so after merging main tsc -b fails on the stripSqlComments(source, activeDialectRef.current) call (Argument of type 'SqlSyntax | undefined' is not assignable to parameter of type 'string | undefined'). The helper should accept the same dialect input the splitter does.
  3. Hardcoded dialect list. DIALECTS in stripSqlComments.ts duplicates the splitter's list and already misses bigquery, so for a BigQuery plugin the action copies the text unchanged without saying so. isDialect() / optionsFor from sqlSplitter would avoid the drift (and see .rules/plugins.md about branching on capabilities).
  4. Translations. editor.copyWithoutComments is only in en.json. .rules/general.md asks for new strings in every locale under src/i18n/locales/, even if some files are still incomplete.
  5. Non-SQL surfaces. #1161 asks to hide the action where it doesn't apply, but it's always registered; without a dialect it just copies the text as is. A Monaco precondition or skipping the registration would match the issue.

Smaller things, fine as follow-ups:

  • The test "preserves an unterminated block comment region as a string-like span" actually asserts that the comment is stripped, so the name says the opposite.
  • Comment-only lines leave empty lines behind (-- header\nSELECT 1;\n-- footer gives \nSELECT 1;\n).
  • With CRLF line endings, a line ending in a -- comment loses its \r, so you end up with mixed line endings.

The 19 tests pass on the branch and lint is clean, so the core is in good shape. It's mainly the hints, the rebase and the dialect handling.

Add an editor action that copies the current selection (or the whole
document when nothing is selected) with ordinary line and block comments
removed. A pure stripSqlComments helper reuses the splitter's tokenizer
and takes the same dialect input as the splitter (a dialect name or the
connection's resolved syntax, including a plugin's sql_syntax).

Kept: strings, quoted identifiers, dollar-quoted bodies, optimizer hints
(/*+ ... */ and Oracle's --+) and executable comments (/*! and MariaDB
/*M!). A removed comment between two non-whitespace characters becomes a
single space, lines that only held comments are dropped, and CRLF line
endings are preserved.

The action is hidden (Monaco precondition) when the connection declares
no SQL dialect, and its label is translated in every locale.

Closes TabularisDB#1161
@chiliec
chiliec force-pushed the feat/copy-sql-without-comments branch from 3cc7f57 to ac730c9 Compare October 19, 2026 11:03
@github-actions

Copy link
Copy Markdown
Contributor

Preview build

The preview build of commit ac730c9 failed (skipped). See the workflow run for logs.

@chiliec

chiliec commented Oct 19, 2026

Copy link
Copy Markdown
Contributor Author

Thanks for the thorough review. All five are done:

  1. Hints are kept: /*+ … */ in every dialect and Oracle's --+, with tests.
  2. Rebased on main. stripSqlComments takes DialectInput like the splitter, and tsc -b passes.
  3. Dropped DIALECTS. It now uses isDialect/dialectOptions, or the resolved syntax's own options, so BigQuery's sql_syntax works (test with the GoogleSQL fixture).
  4. Added editor.copyWithoutComments to every locale.
  5. The action now has a Monaco precondition, so it's hidden when the connection declares no SQL dialect.

I also did the three smaller ones: renamed the unterminated-comment test, lines that only held comments are dropped, and CRLF endings are kept.

@debba debba left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Thanks, this is a great update! I went through all five points again and they're all fixed: hints are kept (/*+ ... */ everywhere and Oracle's --+, while /* + ... */ with a space is still stripped, which is exactly right), the helper takes DialectInput and typechecks on top of main, the dialect list is gone so BigQuery's GoogleSQL syntax works, the key is in every locale, and the Monaco precondition really hides the item (not just greys it out) and updates when the active connection changes. The three smaller ones are fixed too; I especially liked that CRLF endings now survive and that comment-only lines disappear without gluing the surrounding lines together.

I re-ran the tests on the branch (652 across stripSqlComments and the splitter/syntax suites), plus typecheck and lint, and also tried a bunch of awkward inputs again (strings, dollar quotes, q-quotes, [a -- b], 1--1 on MySQL, /*! and /*M!). Everything came out right, so I'm approving. A few follow-ups, none of them blocking:

  • void copyTextToClipboard(stripped) has no error handling and no feedback: if the copy fails it becomes an unhandled rejection and the user sees nothing. copyAllRows in the same file shows the toast/alert pattern we use elsewhere.
  • A connection declaring only sql_dialect: "generic" (or an unknown name, which the backend maps to generic) counts as declared, so the action shows and strips with guessed quoting rules. On a backslash-escape engine declared as generic, SELECT 'x\' -- y' AS a, b FROM t loses real SQL. PLUGIN_GUIDE.md treats "only generic" as undeclared, so I'd do the same here unless the plugin also provides sql_syntax.
  • /*+ and --+ are kept in every dialect, including SQLite and SQL Server where they're just comments. Safe direction, so fine, it could just be limited to the dialects that have hints.
  • The description is a bit out of date: it still says only the English string was added and lists 19 cases, and it doesn't say how plugin drivers behave (.rules/plugins.md asks for that).

I'll do my own checks in the app before merging.

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.

2 participants