aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/errors.js60
-rw-r--r--src/extension.js97
-rw-r--r--src/implement-interface.js95
-rw-r--r--src/interfaces-provider.js17
4 files changed, 195 insertions, 74 deletions
diff --git a/src/errors.js b/src/errors.js
new file mode 100644
index 0000000..65b31a7
--- /dev/null
+++ b/src/errors.js
@@ -0,0 +1,60 @@
+const vscode = require('vscode');
+
+const fnRegex = /^(\t*)(.*)err\s?:?=.+?$/;
+
+class ErrorsWrapper {
+ provideCodeActions(document, range) {
+ const editor = vscode.window.activeTextEditor;
+ if (!editor) {
+ return undefined;
+ }
+
+ const line = document.lineAt(editor.selection.start.line);
+ if (!fnRegex.test(line.text)) {
+ vscode.commands.executeCommand('setContext', 'allowWrapIferr', false);
+ return undefined;
+ }
+ vscode.commands.executeCommand('setContext', 'allowWrapIferr', true);
+ const action = new vscode.CodeAction('Add error checking', vscode.CodeActionKind.RefactorRewrite);
+ action.command = { command: 'gotools.wrap-error', title: 'Add error checking block', tooltip: '' };
+ return [
+ action,
+ ];
+ }
+}
+
+const wrapError = () => {
+ const editor = vscode.window.activeTextEditor;
+ if (!editor) {
+ return;
+ }
+ const document = editor.document;
+
+ const line = document.lineAt(editor.selection.start.line);
+ const matches = line.text.match(fnRegex);
+ if (matches === null || matches.length === 0) {
+ return;
+ }
+ const extravars = matches[2].split(',').map(x => x.trim()).filter(x => x);
+ if (extravars.filter(x => x !== "_").length > 0) {
+ editor.insertSnippet(
+ new vscode.SnippetString(`\nif err != nil {\n\treturn \${1:nil, }\${2:err}\n}\n`),
+ new vscode.Position(line.range.end.line, line.range.end.character + line.firstNonWhitespaceCharacterIndex),
+ );
+ } else {
+ const tabs = matches[1];
+ const original = matches[0].trimStart()
+ editor.insertSnippet(
+ new vscode.SnippetString(`${tabs}if ${original}; err != nil {\n${tabs}\treturn \${2:nil, }\${3:err}\n${tabs}}\n`),
+ line.range,
+ {
+ undoStopBefore: true,
+ undoStopAfter: true
+ }
+ );
+ }
+};
+
+module.exports = {
+ ErrorsWrapper, wrapError
+} \ No newline at end of file
diff --git a/src/extension.js b/src/extension.js
index 45a30cd..850d5be 100644
--- a/src/extension.js
+++ b/src/extension.js
@@ -1,88 +1,37 @@
-// The module 'vscode' contains the VS Code extensibility API
-// Import the module and reference it with the alias vscode in your code below
const vscode = require('vscode');
-const fnRegex = /^(\t*)(.*)err\s?:?=.+?$/;
-
-// This method is called when your extension is activated
-// Your extension is activated the very first time the command is executed
-
+const { ErrorsWrapper, wrapError } = require('./errors');
+const selectReceiver = require('./implement-interface');
/**
* @param {vscode.ExtensionContext} context
*/
function activate(context) {
- let wrapErrorCommand = vscode.commands.registerCommand('gotools.wrap-error', wrapError);
- context.subscriptions.push(
- vscode.languages.registerCodeActionsProvider(
- 'go',
- new ErrorsWrapper(),
- {
- providedCodeActionKinds: [
- vscode.CodeActionKind.RefactorRewrite
- ]
- }
- )
- );
- context.subscriptions.push(wrapErrorCommand);
+ let wrapErrorCommand = vscode.commands.registerCommand('gotools.wrap-error', wrapError);
+ context.subscriptions.push(
+ vscode.languages.registerCodeActionsProvider(
+ 'go',
+ new ErrorsWrapper(),
+ {
+ providedCodeActionKinds: [
+ vscode.CodeActionKind.RefactorRewrite
+ ]
+ }
+ )
+ );
+ context.subscriptions.push(wrapErrorCommand);
+
+ vscode.commands.registerCommand("gotools.imports", function () {
+ // TODO
+ })
+
+ context.subscriptions.push(vscode.commands.registerCommand("gotools.implement", selectReceiver));
}
// This method is called when your extension is deactivated
function deactivate() { }
-class ErrorsWrapper {
-
- provideCodeActions(document, range) {
- const editor = vscode.window.activeTextEditor;
- if (!editor) {
- return undefined;
- }
- const line = document.lineAt(editor.selection.start.line);
- if (!fnRegex.test(line.text)) {
- vscode.commands.executeCommand('setContext', 'allowWrapIferr', false);
- return undefined;
- }
- vscode.commands.executeCommand('setContext', 'allowWrapIferr', true);
- const action = new vscode.CodeAction('Add error checking', vscode.CodeActionKind.RefactorRewrite);
- action.command = { command: 'gotools.wrap-error', title: 'Add error checking block', tooltip: '' };
- return [
- action,
- ];
- }
-}
module.exports = {
- activate,
- deactivate
+ activate,
+ deactivate
}
-
-const wrapError = () => {
- const editor = vscode.window.activeTextEditor;
- if (!editor) {
- return;
- }
- const document = editor.document;
-
- const line = document.lineAt(editor.selection.start.line);
- const matches = line.text.match(fnRegex);
- if (matches === null || matches.length === 0) {
- return;
- }
- const extravars = matches[2].split(',').map(x => x.trim()).filter(x => x);
- if (extravars.filter(x => x !== "_").length > 0) {
- editor.insertSnippet(
- new vscode.SnippetString(`\nif err != nil {\n\treturn \${1:nil, }\${2:err}\n}\n`),
- new vscode.Position(line.range.end.line, line.range.end.character + line.firstNonWhitespaceCharacterIndex),
- );
- } else {
- const tabs = matches[1];
- const original = matches[0].trimStart()
- editor.insertSnippet(
- new vscode.SnippetString(`${tabs}if ${original}; err != nil {\n${tabs}\treturn \${2:nil, }\${3:err}\n${tabs}}\n`),
- line.range,
- {
- undoStopBefore: true,
- undoStopAfter: true
- }
- );
- }
-};
diff --git a/src/implement-interface.js b/src/implement-interface.js
new file mode 100644
index 0000000..8c6f3a3
--- /dev/null
+++ b/src/implement-interface.js
@@ -0,0 +1,95 @@
+const vscode = require('vscode');
+const { dirname } = require('path');
+const cp = require('child_process');
+const provideInterfaces = require('./interfaces-provider');
+const debounce = require('lodash.debounce');
+
+
+
+function selectReceiver() {
+ const receiverInput = vscode.window.createInputBox();
+ const pattern = /^([a-zA-Z_][a-zA-Z0-9_]*)\s+(\*?(?:[a-zA-Z_][a-zA-Z0-9]*\.)?[a-zA-Z_][a-zA-Z0-9_]*)$/;
+ receiverInput.placeholder = "Enter receiver (ex: 'm *MyType')";
+
+ receiverInput.onDidChangeValue(value => {
+ if (value != "" && !value.match(pattern)) {
+ receiverInput.validationMessage = `Valid format: "f *File", "m MyType", "c CustomType"`;
+ } else {
+ receiverInput.validationMessage = '';
+ }
+ });
+
+ receiverInput.onDidAccept(e => {
+ const receiver = receiverInput.value;
+ const matches = receiver.match(pattern);
+ if (!matches) {
+ vscode.window.showWarningMessage(`Receiver is not in the correct format. Valid: "f *File", "m MyType", "c CustomType"`);
+ return undefined;
+ }
+ selectInterface({ name: matches[1], type_: matches[2] });
+ receiverInput.hide();
+ });
+
+ receiverInput.onDidHide(() => {
+ receiverInput.dispose();
+ });
+ receiverInput.show();
+}
+
+/**
+ *
+ * @param {*} receiver
+ */
+function selectInterface(receiver) {
+ const quickPick = vscode.window.createQuickPick();
+ quickPick.placeholder = "Which interface would you like to implement?";
+ const debounced = debounce((value) => {
+ provideInterfaces(value, (interfaces) => {
+ const items = interfaces.map((label) => ({ label }));
+ quickPick.items = items;
+ });
+ }, 400, { trailing: true });
+
+ quickPick.onDidChangeValue(value => {
+ debounced(value);
+ });
+
+ quickPick.onDidChangeSelection(selection => {
+ if (selection[0]) {
+ implement(selection[0].label, receiver);
+ }
+ quickPick.hide();
+ });
+
+ quickPick.onDidHide(() => {
+ quickPick.dispose();
+ });
+ quickPick.show();
+}
+
+function implement(interface_, receiver) {
+ const editor = vscode.window.activeTextEditor;
+ vscode.window.withProgress({
+ location: vscode.ProgressLocation.Notification,
+ title: "Generating stub methods..."
+ }, (progress, token) => {
+ return new Promise((resolve) => {
+ const r = `${receiver.name} ${receiver.type_}`
+ cp.exec(`impl "${r}" ${interface_}`,
+ { cwd: dirname(editor.document.fileName) },
+ (error, stdout, stderr) => {
+ if (error) {
+ vscode.window.showInformationMessage(stderr);
+ return resolve(true);
+ }
+
+ const position = editor.selection.active;
+
+ editor.insertSnippet(new vscode.SnippetString("\n" + stdout), position.with(position.line+1, 0));
+ resolve(true);
+ });
+ });
+ });
+}
+
+module.exports = selectReceiver; \ No newline at end of file
diff --git a/src/interfaces-provider.js b/src/interfaces-provider.js
new file mode 100644
index 0000000..d42995e
--- /dev/null
+++ b/src/interfaces-provider.js
@@ -0,0 +1,17 @@
+const vscode = require('vscode');
+
+function provideInterfaces(keyword, callback) {
+ vscode.commands.executeCommand("vscode.executeWorkspaceSymbolProvider", keyword)
+ .then(
+ /**
+ * @param {array} objects
+ */
+ (objects) => {
+ const interfaces = objects.
+ filter(x => x.kind == vscode.SymbolKind.Interface).
+ map(x => x.name)
+ callback(interfaces);
+ });
+}
+
+module.exports = provideInterfaces \ No newline at end of file