diff --git a/package.json b/package.json index 43538062..575de809 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,8 @@ "activationEvents": [ "onLanguage:prql", "onCommand:prql.openSqlPreview", - "onCommand:prql.generateSqlFile" + "onCommand:prql.generateSqlFile", + "onCommand:prql.copySqlToClipboard" ], "contributes": { "languages": [ @@ -57,6 +58,12 @@ "title": "Generate SQL File", "category": "PRQL", "icon": "$(database)" + }, + { + "command": "prql.copySqlToClipboard", + "title": "Copy SQL to Clipboard", + "category": "PRQL", + "icon": "$(copy)" } ], "menus": { @@ -70,6 +77,11 @@ "command": "prql.generateSqlFile", "when": "resourceFilename =~ /\\.prql$/", "group": "navigation" + }, + { + "command": "prql.copySqlToClipboard", + "when": "prql.sqlPreviewActive", + "group": "navigation" } ], "editor/title/context": [ diff --git a/src/commands.ts b/src/commands.ts index a52f60f2..b2e82778 100644 --- a/src/commands.ts +++ b/src/commands.ts @@ -1,5 +1,6 @@ import { commands, + env, window, workspace, Disposable, @@ -20,6 +21,15 @@ import { TextEncoder } from "util"; */ export function registerCommands(context: ExtensionContext) { registerCommand(context, constants.GenerateSqlFile, generateSqlFile); + + registerCommand(context, constants.CopySqlToClipboard, () => { + const sql: string | undefined = context.workspaceState.get("prql.sql"); + if (sql) { + // write the last generated sql code to vscode clipboard + env.clipboard.writeText(sql); + window.showInformationMessage("PRQL: SQL copied to Clipboard."); + } + }); } /** diff --git a/src/constants.ts b/src/constants.ts index 7bea2873..f2f791dd 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -17,3 +17,7 @@ export const SqlPreviewTitle = "SQL Preview"; // PRQL extension command constants export const OpenSqlPreview = `${ExtensionId}.openSqlPreview`; export const GenerateSqlFile = `${ExtensionId}.generateSqlFile`; +export const CopySqlToClipboard = `${ExtensionId}.copySqlToClipboard`; + +// PRQL context keys +export const SqlPreviewActive = `${ExtensionId}.sqlPreviewActive`; diff --git a/src/sql_output/index.ts b/src/sql_output/index.ts index 7ed7676c..8de1c5ad 100644 --- a/src/sql_output/index.ts +++ b/src/sql_output/index.ts @@ -91,12 +91,18 @@ async function compilePrql( return { status: "ok", html: highlighted, + sql: result, }; } +function clearSqlContext(context: ExtensionContext) { + commands.executeCommand("setContext", constants.SqlPreviewActive, false); + context.workspaceState.update("prql.sql", undefined); +} + let lastOkHtml: string | undefined; -function sendText(panel: WebviewPanel) { +function sendText(context: ExtensionContext, panel: WebviewPanel) { const editor = window.activeTextEditor; if (panel.visible && editor && isPrqlDocument(editor)) { @@ -106,8 +112,16 @@ function sendText(panel: WebviewPanel) { lastOkHtml = result.html; } panel.webview.postMessage(result); + + // set sql preview flag and update sql output + commands.executeCommand("setContext", constants.SqlPreviewActive, true); + context.workspaceState.update("prql.sql", result.sql); }); } + + if (!panel.visible || !panel.active) { + clearSqlContext(context); + } } function sendThemeChanged(panel: WebviewPanel) { @@ -141,7 +155,7 @@ function createWebviewPanel( disposables.push( event( debounce(() => { - sendText(panel); + sendText(context, panel); }, 10) ) ); @@ -154,7 +168,8 @@ function createWebviewPanel( if (editor && editor !== lastEditor) { lastEditor = editor; lastOkHtml = undefined; - sendText(panel); + clearSqlContext(context); + sendText(context, panel); } }) ); @@ -169,6 +184,7 @@ function createWebviewPanel( panel.onDidDispose( () => { + clearSqlContext(context); disposables.forEach((d) => d.dispose()); onDidDispose(); }, @@ -176,7 +192,7 @@ function createWebviewPanel( context.subscriptions ); - sendText(panel); + sendText(context, panel); return panel; } diff --git a/src/sql_output/utils.ts b/src/sql_output/utils.ts index c7a754e5..d2018b3b 100644 --- a/src/sql_output/utils.ts +++ b/src/sql_output/utils.ts @@ -3,6 +3,7 @@ import { ExtensionContext, Uri } from "vscode"; export interface CompilationResult { status: "ok" | "error"; html?: string; + sql?: string; error?: { message: string; };