Skip to content
Merged
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
20 changes: 18 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,20 +46,36 @@
"title": "Open SQL Preview",
"category": "PRQL",
"icon": "$(open-preview)"
},
{
"command": "prql.generateSqlFile",
"title": "Generate SQL File",
"category": "PRQL",
"icon": "$(database)"
}
],
"menus": {
"editor/title": [
{
"command": "prql.openSqlPreview",
"when": "resourceFilename =~ /.*(.prql)/",
"when": "resourceFilename =~ /\\.prql$/",
"group": "navigation"
},
{
"command": "prql.generateSqlFile",
"when": "resourceFilename =~ /\\.prql$/",
"group": "navigation"
}
],
"editor/title/context": [
{
"command": "prql.openSqlPreview",
"when": "resourceFilename =~ /.*\\.(prql)/",
"when": "resourceFilename =~ /\\.prql$/",
"group": "navigation"
},
{
"command": "prql.generateSqlFile",
"when": "resourceFilename =~ /\\.prql$/",
"group": "navigation"
}
]
Expand Down
83 changes: 83 additions & 0 deletions src/commands.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import {
commands,
window,
workspace,
Disposable,
ExtensionContext,
Uri
} from 'vscode';

import * as path from 'path';
import * as constants from './constants';

import { compile } from './compiler';
import { TextEncoder } from 'util';

/**
* Registers PRQL extension commands.
*
* @param context Extension context.
*/
export function registerCommands(context: ExtensionContext) {
registerCommand(context, constants.GenerateSqlFile, generateSqlFile);
}

/**
* Registers vscode extension command.
*
* @param context Extension context.
* @param commandId Command identifier.
* @param callback Command handler.
* @param thisArg The `this` context used when invoking command handler.
*/
function registerCommand(context: ExtensionContext, commandId: string,
callback: (...args: any[]) => any, thisArg?: any): void {

const command: Disposable = commands.registerCommand(commandId, async (...args) => {
try {
await callback(...args);
} catch (e: unknown) {
window.showErrorMessage(String(e));
console.error(e);
}
}, thisArg);

context.subscriptions.push(command);
}

/**
* Compiles PRQL text from the active text editor,
* and creates or updates the corresponding SQL file
* with PRQL compiler output.
*
* Opens generated SQL file in text editor for code formatting,
* or running generated SQL statements with available
* vscode database extensions and sql tools.
*/
async function generateSqlFile() {
const editor = window.activeTextEditor;

if (editor && editor.document.languageId === 'prql') {
// compile PRQL
const prql = editor.document.getText();
const result = compile(prql);

if (Array.isArray(result)) {
window.showErrorMessage(`PRQL Compile \
${result[0].display ?? result[0].reason}`);
}
else {
// create sql file
const prqlDocumentUri: Uri = editor.document.uri;
const prqlFilePath = path.parse(prqlDocumentUri.fsPath);
const sqlFilePath = path.join(prqlFilePath.dir, `${prqlFilePath.name}.sql`);
const sqlFileUri: Uri = Uri.file(sqlFilePath);
const textEncoder: TextEncoder = new TextEncoder()
const sqlContent: Uint8Array = textEncoder.encode(result);
await workspace.fs.writeFile(sqlFileUri, sqlContent);

// show generated sql file
await window.showTextDocument(sqlFileUri);
}
}
}
4 changes: 1 addition & 3 deletions src/compiler.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import * as prqlJs from "prql-js";
import * as prqlJs from 'prql-js';

export function compile(prqlString: string): string | ErrorMessage[] {
try {
Expand Down Expand Up @@ -36,7 +36,5 @@ export interface ErrorMessage {
/// - column number within that line (0-based),
export interface SourceLocation {
start: [number, number];

end: [number, number];
}

19 changes: 19 additions & 0 deletions src/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/* eslint-disable @typescript-eslint/naming-convention */

/**
* PRQL extension constants.
*/

// Extension constants
export const PublisherId = 'PRQL-lang';
export const ExtensionName = 'prql-vscode';
export const ExtensionId = 'prql';
export const ExtensionDisplayName = 'PRQL';

// PRQL webview constants
export const SqlPreviewPanel = `${ExtensionId}.sqlPreviewPanel`;
export const SqlPreviewTitle = 'SQL Preview';

// PRQL extension command constants
export const OpenSqlPreview = `${ExtensionId}.openSqlPreview`;
export const GenerateSqlFile = `${ExtensionId}.generateSqlFile`;
46 changes: 29 additions & 17 deletions src/diagnostics.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,30 @@
import * as vscode from "vscode";
import { isPrqlDocument } from "./utils";
import { SourceLocation, compile } from "./compiler";

function getRange(location: SourceLocation | null): vscode.Range {
import {
Diagnostic,
DiagnosticCollection,
DiagnosticSeverity,
ExtensionContext,
Position,
Range,
TextDocument,
languages,
window,
workspace
} from 'vscode';

import { isPrqlDocument } from './utils';
import { SourceLocation, compile } from './compiler';

function getRange(location: SourceLocation | null): Range {
if (location) {
return new vscode.Range(location.start[0], location.start[1], location.end[0],
return new Range(location.start[0], location.start[1], location.end[0],
location.end[1]);
}

return new vscode.Range(new vscode.Position(0, 0), new vscode.Position(0, 0));
return new Range(new Position(0, 0), new Position(0, 0));
}

function updateLineDiagnostics(diagnosticCollection: vscode.DiagnosticCollection) {
const editor = vscode.window.activeTextEditor;
function updateLineDiagnostics(diagnosticCollection: DiagnosticCollection) {
const editor = window.activeTextEditor;

if (editor && isPrqlDocument(editor)) {
const text = editor.document.getText();
Expand All @@ -22,24 +34,24 @@ function updateLineDiagnostics(diagnosticCollection: vscode.DiagnosticCollection
diagnosticCollection.set(editor.document.uri, []);
} else {
const range = getRange(result[0].location);
const diagnostic = new vscode.Diagnostic(range, result[0].reason ?? "Syntax Error",
vscode.DiagnosticSeverity.Error);
const diagnostic = new Diagnostic(range, result[0].reason ?? 'Syntax Error',
DiagnosticSeverity.Error);
diagnosticCollection.set(editor.document.uri, [diagnostic]);
}
}
}

export function activateDiagnostics(context: vscode.ExtensionContext) {
const diagnosticCollection = vscode.languages.createDiagnosticCollection("prql");
export function activateDiagnostics(context: ExtensionContext) {
const diagnosticCollection = languages.createDiagnosticCollection('prql');
context.subscriptions.push(diagnosticCollection);

vscode.workspace.onDidCloseTextDocument((document: vscode.TextDocument) =>
workspace.onDidCloseTextDocument((document: TextDocument) =>
diagnosticCollection.set(document.uri, []));

[
vscode.workspace.onDidOpenTextDocument,
vscode.workspace.onDidChangeTextDocument,
vscode.window.onDidChangeActiveTextEditor
workspace.onDidOpenTextDocument,
workspace.onDidChangeTextDocument,
window.onDidChangeActiveTextEditor
].forEach(event => {
context.subscriptions.push(event(() => updateLineDiagnostics(diagnosticCollection)));
});
Expand Down
20 changes: 15 additions & 5 deletions src/extension.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,18 @@
import * as vscode from "vscode";
import { activateSqlOutputPanel } from "./sql_output";
import { activateDiagnostics } from "./diagnostics";
import { ExtensionContext } from 'vscode';
import { activateSqlPreviewPanel } from './sql_output';
import { activateDiagnostics } from './diagnostics';
import { registerCommands } from './commands';

export function activate(context: vscode.ExtensionContext) {
/**
* Activates PRQL extension,
* enables PRQL text document diagnostics,
* registers Open SQL Preview and other
* PRQL extension commands.
*
* @param context Extension context.
*/
export function activate(context: ExtensionContext) {
activateDiagnostics(context);
activateSqlOutputPanel(context);
activateSqlPreviewPanel(context);
registerCommands(context);
}
Loading