diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/errors.js | 60 | ||||
-rw-r--r-- | src/extension.js | 97 | ||||
-rw-r--r-- | src/implement-interface.js | 95 | ||||
-rw-r--r-- | src/interfaces-provider.js | 17 |
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 |