Gerrit Bot has uploaded this change for review.
goImpl: improvements
Improvements:
1. Now variable and type can be deduced from cursor selection
2. Now you can implement multiple interfaces at once
Note: I'm assuming that PR will be rejected due to Commit/PR guidelines, but c'mon this is useful change.
If you are planning to add this change anyway but with correct Commit/PR, just add credits, or smth.
Change-Id: Ie9649ae6afc957c12c41045fb8b720ea2e3f49a9
GitHub-Last-Rev: 93b18612d4f018b0561303a66b9603c86732fe86
GitHub-Pull-Request: golang/vscode-go#2936
---
M src/goImpl.ts
1 file changed, 55 insertions(+), 29 deletions(-)
diff --git a/src/goImpl.ts b/src/goImpl.ts
index 61ac926..ea8b649 100644
--- a/src/goImpl.ts
+++ b/src/goImpl.ts
@@ -15,8 +15,12 @@
import vscode = require('vscode');
import { CommandFactory } from './commands';
-// Supports only passing interface, see TODO in implCursor to finish
-const inputRegex = /^(\w+\ \*?\w+\ )?([\w\.\-\/]+)$/;
+// Accepts input of the form:
+// [f *File] io.Closer [, ...]
+// [f *File] io.Closer
+// io.Closer (type name will be deduced from variable name from cursor position)
+// io.Closer, io.Reader (same as above)
+const inputRegex = /^(?<identifier>(?<variable>[\p{Letter}_][\p{Letter}_\p{Number}\d]*) *(?<type>[*]? *[\p{Letter}_][\p{Letter}_\p{Number}\d]*) +)?(?<interfaces>(?:[\p{Letter}_][\p{Letter}_\p{Number}\d\.\-\/]*)+(?: *, *(?:[\p{Letter}_][\p{Letter}_\p{Number}\d\.\-\/]*)+)*)$/u;
export const implCursor: CommandFactory = () => () => {
const editor = vscode.window.activeTextEditor;
@@ -27,7 +31,7 @@
const cursor = editor.selection;
return vscode.window
.showInputBox({
- placeHolder: 'f *File io.Closer',
+ placeHolder: '[f *File] io.Closer [, ...]',
prompt: 'Enter receiver and interface to implement.'
})
.then((implInput) => {
@@ -35,42 +39,64 @@
return;
}
const matches = implInput.match(inputRegex);
- if (!matches) {
+ if (!matches || !matches.groups || !matches.groups.interfaces) {
vscode.window.showInformationMessage(`Not parsable input: ${implInput}`);
return;
}
- // TODO: automatically detect type name at cursor
- // if matches[1] is undefined then detect receiver type
- // take first character and use as receiver name
+ let identifier = matches.groups?.identifier;
+ if (!identifier) {
+ const beforeCursor = new vscode.Range(new vscode.Position(cursor.start.line, 0), cursor.start);
+ const beforeCursorText = editor.document.getText(beforeCursor);
+ const typeIndex = beforeCursorText.lastIndexOf('type');
+ if (typeIndex === -1) {
+ vscode.window.showInformationMessage('No identifier found at cursor.');
+ return;
+ }
- runGoImpl([matches[1], matches[2]], cursor.start, editor);
+ const variable = editor.document.getText(cursor)[0].toLowerCase();
+ identifier = editor.document.getText(cursor);
+ identifier = `${variable} *${identifier}`;
+
+ let newPosition = cursor.start.with(cursor.start.line + 1, 0);
+ newPosition = newPosition.translate(1, 0);
+ editor.selection = new vscode.Selection(newPosition, newPosition);
+ }
+ const interfaces = matches.groups?.interfaces.trim().split(',');
+ interfaces.forEach((iface, i) => {
+ interfaces[i] = iface.trim();
+ });
+ runGoImpl([identifier, interfaces], editor);
});
};
-function runGoImpl(args: string[], insertPos: vscode.Position, editor: vscode.TextEditor) {
+function runGoImpl(prompt: [string, string[]], editor: vscode.TextEditor) {
const goimpl = getBinPath('impl');
- const p = cp.execFile(
- goimpl,
- args,
- { env: toolExecutionEnvironment(), cwd: dirname(editor.document.fileName) },
- (err, stdout, stderr) => {
- if (err && (<any>err).code === 'ENOENT') {
- promptForMissingTool('impl');
- return;
- }
+ prompt[1].forEach((iface) => {
+ const p = cp.execFile(
+ goimpl,
+ [prompt[0], iface],
+ { env: toolExecutionEnvironment(), cwd: dirname(editor.document.fileName) },
+ (err, stdout, stderr) => {
+ if (err && (<any>err).code === 'ENOENT') {
+ promptForMissingTool('impl');
+ return;
+ }
- if (err) {
- vscode.window.showInformationMessage(`Cannot stub interface: ${stderr}`);
- return;
- }
+ if (err) {
+ vscode.window.showInformationMessage(`Cannot stub interface: ${stderr}`);
+ return;
+ }
- editor.edit((editBuilder) => {
- editBuilder.insert(insertPos, stdout);
- });
+ (function (out: string) {
+ editor.edit((editBuilder) => {
+ editBuilder.insert(editor.selection.start, out);
+ });
+ })(stdout);
+ }
+ );
+ if (p.pid) {
+ p.stdin?.end();
}
- );
- if (p.pid) {
- p.stdin?.end();
- }
+ });
}
To view, visit change 519035. To unsubscribe, or for help writing mail filters, visit settings.
Congratulations on opening your first change. Thank you for your contribution!
Next steps:
A maintainer will review your change and provide feedback. See
https://go.dev/doc/contribute#review for more info and tips to get your
patch through code review.
Most changes in the Go project go through a few rounds of revision. This can be
surprising to people new to the project. The careful, iterative review process
is our way of helping mentor contributors and ensuring that their contributions
have a lasting impact.