Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,16 @@
"Java 17",
"Java 21"
]
},
"vscode-db2i.delimitedList.quoteNumbers": {
"type": "boolean",
"description": "Quote numeric values when copying a selection as a SQL list",
"default": true
},
"vscode-db2i.delimitedList.wrapInParentheses": {
"type": "boolean",
"description": "Wrap the SQL list in parentheses when using 'Copy as SQL List' (instant copy)",
"default": false
}
}
},
Expand Down Expand Up @@ -542,6 +552,16 @@
"title": "Generate Insert from File",
"category": "Db2 for i"
},
{
"command": "vscode-db2i.copyAsDelimitedList",
"title": "Copy as SQL List",
"category": "Db2 for i"
},
{
"command": "vscode-db2i.copyAsDelimitedListPrompt",
"title": "Copy as SQL List (Prompt Format)",
"category": "Db2 for i"
},
{
"command": "vscode-db2i.refreshSchemaBrowser",
"title": "Refresh Schema Browser",
Expand Down Expand Up @@ -1032,6 +1052,14 @@
"command": "vscode-db2i.importDataContextMenu",
"when": "false"
},
{
"command": "vscode-db2i.copyAsDelimitedList",
"when": "editorLangId == sql && editorHasSelection"
},
{
"command": "vscode-db2i.copyAsDelimitedListPrompt",
"when": "editorLangId == sql && editorHasSelection"
},
{
"command": "vscode-db2i.filterDatabaseObjectTypes",
"when": "never"
Expand Down Expand Up @@ -1204,6 +1232,16 @@
{
"command": "vscode-db2i.importDataContextMenu",
"group": "sql@3"
},
{
"command": "vscode-db2i.copyAsDelimitedList",
"group": "sql@4",
"when": "editorLangId == sql && editorHasSelection"
},
{
"command": "vscode-db2i.copyAsDelimitedListPrompt",
"group": "sql@5",
"when": "editorLangId == sql && editorHasSelection"
}
],
"view/title": [
Expand Down
38 changes: 38 additions & 0 deletions src/contributes.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,16 @@
"Java 17",
"Java 21"
]
},
"vscode-db2i.delimitedList.quoteNumbers": {
"type": "boolean",
"description": "Quote numeric values when copying a selection as a SQL list",
"default": true
},
"vscode-db2i.delimitedList.wrapInParentheses": {
"type": "boolean",
"description": "Wrap the SQL list in parentheses when using 'Copy as SQL List' (instant copy)",
"default": false
}
}
},
Expand Down Expand Up @@ -137,6 +147,16 @@
"command": "vscode-db2i.importDataContextMenu",
"title": "Generate Insert from File",
"category": "Db2 for i"
},
{
"command": "vscode-db2i.copyAsDelimitedList",
"title": "Copy as SQL List",
"category": "Db2 for i"
},
{
"command": "vscode-db2i.copyAsDelimitedListPrompt",
"title": "Copy as SQL List (Prompt Format)",
"category": "Db2 for i"
}
],
"menus": {
Expand All @@ -148,6 +168,14 @@
{
"command": "vscode-db2i.importDataContextMenu",
"when": "false"
},
{
"command": "vscode-db2i.copyAsDelimitedList",
"when": "editorLangId == sql && editorHasSelection"
},
{
"command": "vscode-db2i.copyAsDelimitedListPrompt",
"when": "editorLangId == sql && editorHasSelection"
}
],
"editor/context": [
Expand All @@ -169,6 +197,16 @@
{
"command": "vscode-db2i.importDataContextMenu",
"group": "sql@3"
},
{
"command": "vscode-db2i.copyAsDelimitedList",
"group": "sql@4",
"when": "editorLangId == sql && editorHasSelection"
},
{
"command": "vscode-db2i.copyAsDelimitedListPrompt",
"group": "sql@5",
"when": "editorLangId == sql && editorHasSelection"
}
]
}
Expand Down
2 changes: 2 additions & 0 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import * as vscode from "vscode";
import SchemaBrowser from "./views/schemaBrowser";

import * as JSONServices from "./language/json";
import * as ClipboardServices from "./language/clipboard";
import * as resultsProvider from "./views/results";

import { JDBCOptions } from "@ibm/mapepire-js/dist/src/types";
Expand Down Expand Up @@ -73,6 +74,7 @@ export function activate(context: vscode.ExtensionContext): Db2i {
);

JSONServices.initialise(context);
ClipboardServices.initialise(context);
resultsProvider.initialise(context);

initConfig(context);
Expand Down
118 changes: 118 additions & 0 deletions src/language/clipboard.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
import * as vscode from "vscode";
import Configuration from "../configuration";

const NUMERIC_RE = /^\d+(\.\d+)?$/;
const LARGE_SELECTION_THRESHOLD = 256; // Just for safety

function getLines(selectedText: string): string[] {
return selectedText
.split(/\r?\n/)
.map((line: string) => line.trim())
.filter((line: string) => line.length > 0);
}

function quoteLine(line: string): string {
return `'${line.replace(/'/g, `''`)}'`;
}

function buildList(lines: string[], quoteNumbers: boolean, wrap: boolean): string {
const values = lines.map((line: string) =>
!quoteNumbers && NUMERIC_RE.test(line) ? line : quoteLine(line)
);
const csv = values.join(`, `);
return wrap ? `(${csv})` : csv;
}

async function writeToClipboard(text: string): Promise<boolean> {
try {
await vscode.env.clipboard.writeText(text);
return true;
} catch (e) {
vscode.window.showErrorMessage(`Failed to write to clipboard: ${e instanceof Error ? e.message : String(e)}`);
return false;
}
}

async function confirmLargeSelection(count: number): Promise<boolean> {
if (count <= LARGE_SELECTION_THRESHOLD) return true;
const answer = await vscode.window.showWarningMessage(
`Your selection contains ${count} values. Continue copying to clipboard?`,
{ modal: true },
`Continue`
);
return answer === `Continue`;
}

export function initialise(context: vscode.ExtensionContext) {
context.subscriptions.push(

// ── Instant copy using current settings ──────────────────────────────────
vscode.commands.registerCommand(`vscode-db2i.copyAsDelimitedList`, async () => {
const editor = vscode.window.activeTextEditor;
if (!editor) return;

const selectedText = editor.document.getText(editor.selection);
const lines = getLines(selectedText);

if (lines.length === 0) {
vscode.window.showErrorMessage(`No text selected.`);
return;
}

if (!await confirmLargeSelection(lines.length)) return;

const quoteNumbers = Configuration.get<boolean>(`delimitedList.quoteNumbers`) ?? true;
const wrapInParens = Configuration.get<boolean>(`delimitedList.wrapInParentheses`) ?? false;

const result = buildList(lines, quoteNumbers, wrapInParens);
if (await writeToClipboard(result)) {
vscode.window.showInformationMessage(`SQL list copied to clipboard.`);
}
}),

// ── Prompted copy with format options ────────────────────────────────────
vscode.commands.registerCommand(`vscode-db2i.copyAsDelimitedListPrompt`, async () => {
const editor = vscode.window.activeTextEditor;
if (!editor) return;

const selectedText = editor.document.getText(editor.selection);
const lines = getLines(selectedText);

if (lines.length === 0) {
vscode.window.showErrorMessage(`No text selected.`);
return;
}

if (!await confirmLargeSelection(lines.length)) return;

const hasNumbers = lines.some((line: string) => NUMERIC_RE.test(line));

const listQuoted = buildList(lines, true, false);
const listQuotedParens = buildList(lines, true, true);

type QuickPickItem = { label: string; description: string; value: string };
const options: QuickPickItem[] = [
{ label: `Copy as list`, description: listQuoted, value: listQuoted },
];

if (hasNumbers) {
const listUnquoted = buildList(lines, false, false);
const listUnquotedParens = buildList(lines, false, true);
options.push(
{ label: `Copy as list (numbers unquoted)`, description: listUnquoted, value: listUnquoted },
{ label: `Copy wrapped in parentheses`, description: listQuotedParens, value: listQuotedParens },
{ label: `Copy wrapped in parentheses (numbers unquoted)`, description: listUnquotedParens, value: listUnquotedParens }
);
} else {
options.push(
{ label: `Copy wrapped in parentheses`, description: listQuotedParens, value: listQuotedParens }
);
}

const choice = await vscode.window.showQuickPick(options, { title: `Copy as SQL List` });
if (choice && await writeToClipboard(choice.value)) {
vscode.window.showInformationMessage(`SQL list copied to clipboard.`);
}
})
);
}