Skip to content

Commit

Permalink
Add 'buf format' (#70)
Browse files Browse the repository at this point in the history
Co-authored-by: Rubens Farias <[email protected]>
  • Loading branch information
amckinney and rubensf authored Apr 5, 2022
1 parent c8f61fe commit d0e46ff
Show file tree
Hide file tree
Showing 4 changed files with 103 additions and 5 deletions.
6 changes: 3 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

22 changes: 20 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "vscode-buf",
"displayName": "Buf",
"description": "Visual Studio Code support for Buf",
"version": "0.4.0",
"version": "0.5.0",
"icon": "logo.png",
"publisher": "bufbuild",
"repository": {
Expand All @@ -23,6 +23,7 @@
"vscode": "^1.63.0"
},
"categories": [
"Formatters",
"Linters"
],
"keywords": [
Expand All @@ -31,7 +32,9 @@
"protobuf",
"protocol buffers",
"buf",
"lint"
"bufbuild",
"lint",
"format"
],
"activationEvents": [
"workspaceContains:**/*.proto",
Expand Down Expand Up @@ -61,6 +64,11 @@
}
}
},
"configurationDefaults": {
"[proto]": {
"editor.formatOnSave": true
}
},
"languages": [
{
"id": "yaml",
Expand All @@ -70,6 +78,16 @@
"buf.work",
"buf.gen"
]
},
{
"id": "proto",
"extensions": [
".proto"
],
"aliases": [
"Protocol Buffers",
"Protobuf"
]
}
]
},
Expand Down
2 changes: 2 additions & 0 deletions src/extension.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import * as vscode from "vscode";
import { downloadPage, lint, minimumVersion, version } from "./buf";
import { isError } from "./errors";
import { Formatter } from "./formatter";
import { parseLines, Warning } from "./parser";
import { format, less } from "./version";

Expand Down Expand Up @@ -124,6 +125,7 @@ export function activate(context: vscode.ExtensionContext) {
diagnosticCollection.set(document.uri, diagnostics);
};

context.subscriptions.push(vscode.languages.registerDocumentFormattingEditProvider('proto', new Formatter(binaryPath)));
context.subscriptions.push(vscode.workspace.onDidSaveTextDocument(doLint));
context.subscriptions.push(vscode.workspace.onDidOpenTextDocument(doLint));
context.subscriptions.push(
Expand Down
78 changes: 78 additions & 0 deletions src/formatter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import * as cp from "child_process";
import * as os from "os";
import * as path from "path";
import * as vscode from "vscode";
import { TextEncoder } from "util";

export class Formatter implements vscode.DocumentFormattingEditProvider {
readonly binaryPath: string = '';

constructor(binaryPath: string) {
if (!binaryPath || binaryPath.length === 0) {
throw new Error('binaryPath is required to construct a formatter');
}
this.binaryPath = binaryPath;
}

public provideDocumentFormattingEdits(
document: vscode.TextDocument,
// @ts-ignore: The formatter doesn't have any options, but we need to implement the interface.
options: vscode.FormattingOptions,
token: vscode.CancellationToken
): vscode.ProviderResult<vscode.TextEdit[]> {
if (vscode.window.visibleTextEditors.every((e) => e.document.fileName !== document.fileName)) {
return [];
}
return this.runFormatter(document, token).then(
(edits) => edits,
(err) => {
console.log(err);
return Promise.reject('Check the console in dev tools to find errors when formatting.');
}
);
}

private randomId(): string {
return (Math.floor(Math.random() * 100000000)).toString();
}

private runFormatter(
document: vscode.TextDocument,
token: vscode.CancellationToken
): Thenable<vscode.TextEdit[]> {
return new Promise<vscode.TextEdit[]>((resolve, reject) => {
const cwd = path.join(os.tmpdir(), "vscode-buf-" + this.randomId());
vscode.workspace.fs.createDirectory(vscode.Uri.file(cwd)).then(() => {
// Buf format expects a `.proto` file, so add unique id as a prefix.
const backupFile = path.join(cwd, this.randomId() + "-" + path.basename(document.fileName));
vscode.workspace.fs.writeFile(vscode.Uri.file(backupFile), new TextEncoder().encode(document.getText())).then(() => {
let stdout = '';
let stderr = '';

const p = cp.spawn(this.binaryPath, ['format', backupFile], { cwd });
token.onCancellationRequested(() => !p.killed && p.kill());

p.stdout.setEncoding('utf8');
p.stdout.on('data', (data: any) => (stdout += data));
p.stderr.on('data', (data: any) => (stderr += data));
p.on('error', (err: any) => {
if (err && (<any>err).code === 'ENOENT') {
return reject();
}
});
p.on('close', (code: number) => {
if (code !== 0) {
return reject(stderr);
}
const fileStart = new vscode.Position(0, 0);
const fileEnd = document.lineAt(document.lineCount - 1).range.end;
const textEdits: vscode.TextEdit[] = [
new vscode.TextEdit(new vscode.Range(fileStart, fileEnd), stdout)
];
return resolve(textEdits);
});
});
});
});
}
}

0 comments on commit d0e46ff

Please sign in to comment.