group imports command
This commit is contained in:
parent
80815c107e
commit
a8fa5bf1cf
7 changed files with 176 additions and 18 deletions
11
README.md
11
README.md
|
@ -24,7 +24,7 @@ Extension in active development! Your contribution is always welcome :)
|
||||||
|
|
||||||
# Interface implementation
|
# Interface implementation
|
||||||
|
|
||||||
Command "Go: Implement Interface Methods" based on https://github.com/ricardoerikson/vscode-go-impl-methods/ extension.
|
Command "Go: Implement Interface Methods" based on https://github.com/ricardoerikson/vscode-go-impl-methods/ extension by Ricardo Erikson.
|
||||||
|
|
||||||
Install the impl package as follows:
|
Install the impl package as follows:
|
||||||
|
|
||||||
|
@ -37,3 +37,12 @@ go get -u github.com/josharian/impl
|
||||||
1. At command pallete select command "Go: Implement Interface Methods"
|
1. At command pallete select command "Go: Implement Interface Methods"
|
||||||
2. Write receiver for methods. Example: "f *File", "m MyType", "c CustomType"
|
2. Write receiver for methods. Example: "f *File", "m MyType", "c CustomType"
|
||||||
3. Select interface to implement
|
3. Select interface to implement
|
||||||
|
|
||||||
|
|
||||||
|
# Group imports
|
||||||
|
|
||||||
|
Group imports command based on https://github.com/gustavo-bordin/golang-imports-group/ extension by Gustavo Bordin.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
1. At command pallete select command "Go: Group imports"
|
|
@ -2,7 +2,7 @@
|
||||||
"name": "gotools",
|
"name": "gotools",
|
||||||
"displayName": "Golang Tools",
|
"displayName": "Golang Tools",
|
||||||
"description": "Tools for productive work",
|
"description": "Tools for productive work",
|
||||||
"version": "0.1.4",
|
"version": "0.1.5",
|
||||||
"engines": {
|
"engines": {
|
||||||
"vscode": "^1.80.0"
|
"vscode": "^1.80.0"
|
||||||
},
|
},
|
||||||
|
@ -56,6 +56,11 @@
|
||||||
"command": "gotools.implement",
|
"command": "gotools.implement",
|
||||||
"title": "Implement Interface Methods",
|
"title": "Implement Interface Methods",
|
||||||
"category": "Go"
|
"category": "Go"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"command": "gotools.group-imports",
|
||||||
|
"title": "Group imports",
|
||||||
|
"category": "Go"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
const vscode = require('vscode');
|
const vscode = require('vscode');
|
||||||
const { ErrorsWrapper, wrapError } = require('./errors');
|
const { ErrorsWrapper, wrapError } = require('./errors');
|
||||||
const selectReceiver = require('./implement-interface');
|
const selectReceiver = require('./implement-interface');
|
||||||
|
const groupImports = require('./group-imports');
|
||||||
/**
|
/**
|
||||||
* @param {vscode.ExtensionContext} context
|
* @param {vscode.ExtensionContext} context
|
||||||
*/
|
*/
|
||||||
|
@ -19,9 +20,7 @@ function activate(context) {
|
||||||
);
|
);
|
||||||
context.subscriptions.push(wrapErrorCommand);
|
context.subscriptions.push(wrapErrorCommand);
|
||||||
|
|
||||||
vscode.commands.registerCommand("gotools.imports", function () {
|
context.subscriptions.push(vscode.commands.registerCommand("gotools.group-imports", groupImports))
|
||||||
// TODO
|
|
||||||
})
|
|
||||||
|
|
||||||
context.subscriptions.push(vscode.commands.registerCommand("gotools.implement", selectReceiver));
|
context.subscriptions.push(vscode.commands.registerCommand("gotools.implement", selectReceiver));
|
||||||
}
|
}
|
||||||
|
|
97
src/group-imports.js
Normal file
97
src/group-imports.js
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
const vscode = require('vscode');
|
||||||
|
const { getModuleName, getImportsRange, getFileContent } = require('./utils');
|
||||||
|
|
||||||
|
const BUILTIN_TYPE = "builtin"
|
||||||
|
const THIRD_PARTY_TYPE = "thirdParty"
|
||||||
|
const VENDOR_TYPE = "vendor"
|
||||||
|
const LOCAL_TYPE = "local"
|
||||||
|
|
||||||
|
|
||||||
|
function getImports(fileContent) {
|
||||||
|
try {
|
||||||
|
let importsRegex = new RegExp("(?<=import \\(\n).*?(?=\\))", "s")
|
||||||
|
let imports = importsRegex.exec(fileContent)[0]
|
||||||
|
return imports
|
||||||
|
} catch(_) {
|
||||||
|
vscode.window.showErrorMessage("Could not find imports")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function convertImportsToList(imports) {
|
||||||
|
return imports.split("\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
function getImportType(import_) {
|
||||||
|
let goModName = getModuleName() + "/"
|
||||||
|
let vendorPath = goModName.substring(0, goModName.lastIndexOf('/'));
|
||||||
|
|
||||||
|
let isBuiltin = !import_.includes(".") && !import_.includes(goModName)
|
||||||
|
let isThirdParty = import_.includes(".") && !import_.includes(goModName)
|
||||||
|
let isLocal = import_.includes(goModName)
|
||||||
|
let isVendor = import_.includes(vendorPath) && !isLocal
|
||||||
|
|
||||||
|
if(isBuiltin) {
|
||||||
|
return BUILTIN_TYPE
|
||||||
|
} else if (isVendor) {
|
||||||
|
return VENDOR_TYPE
|
||||||
|
} else if(isThirdParty) {
|
||||||
|
return THIRD_PARTY_TYPE
|
||||||
|
} else if(isLocal) {
|
||||||
|
return LOCAL_TYPE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function importGroupsToString(importsGroup) {
|
||||||
|
return Object.keys(importsGroup)
|
||||||
|
.filter((key) => importsGroup[key].length)
|
||||||
|
.map((key) => importsGroup[key].join('\n'))
|
||||||
|
.join('\n\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
function saveImportsGroup(importsGroup, importRanges, activeEditor) {
|
||||||
|
const edit = new vscode.WorkspaceEdit();
|
||||||
|
const range = new vscode.Range(
|
||||||
|
importRanges.start,
|
||||||
|
0,
|
||||||
|
importRanges.end - 1,
|
||||||
|
Number.MAX_VALUE
|
||||||
|
);
|
||||||
|
|
||||||
|
let importsParsed = importGroupsToString(importsGroup)
|
||||||
|
let documentUri = activeEditor.document.uri
|
||||||
|
|
||||||
|
edit.replace(documentUri, range, importsParsed);
|
||||||
|
vscode.workspace.applyEdit(edit).then(activeEditor.document.save);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function getImportGroups(importsList) {
|
||||||
|
const importsGroup = {
|
||||||
|
[BUILTIN_TYPE]: [],
|
||||||
|
[THIRD_PARTY_TYPE]: [],
|
||||||
|
[VENDOR_TYPE]: [],
|
||||||
|
[LOCAL_TYPE]: [],
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
importsList.filter(n => n).forEach(import_ => {
|
||||||
|
let importType = getImportType(import_)
|
||||||
|
importsGroup[importType].push(import_)
|
||||||
|
})
|
||||||
|
|
||||||
|
return importsGroup
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatImports() {
|
||||||
|
const activeEditor = vscode.window.activeTextEditor
|
||||||
|
let fileContent = getFileContent(activeEditor)
|
||||||
|
let imports = getImports(fileContent)
|
||||||
|
let importsList = convertImportsToList(imports)
|
||||||
|
let importsGroup = getImportGroups(importsList)
|
||||||
|
let importsRange = getImportsRange(fileContent)
|
||||||
|
saveImportsGroup(importsGroup,importsRange,activeEditor)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = formatImports;
|
|
@ -1,11 +1,9 @@
|
||||||
const vscode = require('vscode');
|
const vscode = require('vscode');
|
||||||
const { dirname } = require('path');
|
const { dirname } = require('path');
|
||||||
const cp = require('child_process');
|
const cp = require('child_process');
|
||||||
const provideInterfaces = require('./interfaces-provider');
|
const { provideInterfaces } = require('./interfaces-provider');
|
||||||
const debounce = require('lodash.debounce');
|
const debounce = require('lodash.debounce');
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function selectReceiver() {
|
function selectReceiver() {
|
||||||
const receiverInput = vscode.window.createInputBox();
|
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_]*)$/;
|
const pattern = /^([a-zA-Z_][a-zA-Z0-9_]*)\s+(\*?(?:[a-zA-Z_][a-zA-Z0-9]*\.)?[a-zA-Z_][a-zA-Z0-9_]*)$/;
|
||||||
|
@ -15,11 +13,11 @@ function selectReceiver() {
|
||||||
if (value != "" && !value.match(pattern)) {
|
if (value != "" && !value.match(pattern)) {
|
||||||
receiverInput.validationMessage = `Valid format: "f *File", "m MyType", "c CustomType"`;
|
receiverInput.validationMessage = `Valid format: "f *File", "m MyType", "c CustomType"`;
|
||||||
} else {
|
} else {
|
||||||
receiverInput.validationMessage = '';
|
receiverInput.validationMessage = '';
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
receiverInput.onDidAccept(e => {
|
receiverInput.onDidAccept(() => {
|
||||||
const receiver = receiverInput.value;
|
const receiver = receiverInput.value;
|
||||||
const matches = receiver.match(pattern);
|
const matches = receiver.match(pattern);
|
||||||
if (!matches) {
|
if (!matches) {
|
||||||
|
@ -45,8 +43,7 @@ function selectInterface(receiver) {
|
||||||
quickPick.placeholder = "Which interface would you like to implement?";
|
quickPick.placeholder = "Which interface would you like to implement?";
|
||||||
const debounced = debounce((value) => {
|
const debounced = debounce((value) => {
|
||||||
provideInterfaces(value, (interfaces) => {
|
provideInterfaces(value, (interfaces) => {
|
||||||
const items = interfaces.map((label) => ({ label }));
|
quickPick.items = interfaces;
|
||||||
quickPick.items = items;
|
|
||||||
});
|
});
|
||||||
}, 400, { trailing: true });
|
}, 400, { trailing: true });
|
||||||
|
|
||||||
|
@ -56,7 +53,7 @@ function selectInterface(receiver) {
|
||||||
|
|
||||||
quickPick.onDidChangeSelection(selection => {
|
quickPick.onDidChangeSelection(selection => {
|
||||||
if (selection[0]) {
|
if (selection[0]) {
|
||||||
implement(selection[0].label, receiver);
|
implement(selection[0].detail + '.' + selection[0].label, receiver);
|
||||||
}
|
}
|
||||||
quickPick.hide();
|
quickPick.hide();
|
||||||
});
|
});
|
||||||
|
@ -72,7 +69,7 @@ function implement(interface_, receiver) {
|
||||||
vscode.window.withProgress({
|
vscode.window.withProgress({
|
||||||
location: vscode.ProgressLocation.Notification,
|
location: vscode.ProgressLocation.Notification,
|
||||||
title: "Generating stub methods..."
|
title: "Generating stub methods..."
|
||||||
}, (progress, token) => {
|
}, () => {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
const r = `${receiver.name} ${receiver.type_}`
|
const r = `${receiver.name} ${receiver.type_}`
|
||||||
cp.exec(`impl "${r}" ${interface_}`,
|
cp.exec(`impl "${r}" ${interface_}`,
|
||||||
|
@ -84,8 +81,7 @@ function implement(interface_, receiver) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const position = editor.selection.active;
|
const position = editor.selection.active;
|
||||||
|
editor.insertSnippet(new vscode.SnippetString("\n" + stdout), position.with(position.line + 1, 0));
|
||||||
editor.insertSnippet(new vscode.SnippetString("\n" + stdout), position.with(position.line+1, 0));
|
|
||||||
resolve(true);
|
resolve(true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -9,9 +9,9 @@ function provideInterfaces(keyword, callback) {
|
||||||
(objects) => {
|
(objects) => {
|
||||||
const interfaces = objects.
|
const interfaces = objects.
|
||||||
filter(x => x.kind == vscode.SymbolKind.Interface).
|
filter(x => x.kind == vscode.SymbolKind.Interface).
|
||||||
map(x => x.name)
|
map(x => ({ label: x.name, detail: x.containerName }))
|
||||||
callback(interfaces);
|
callback(interfaces);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = provideInterfaces
|
module.exports = { provideInterfaces };
|
52
src/utils.js
Normal file
52
src/utils.js
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
const vscode = require('vscode');
|
||||||
|
const path = require('path')
|
||||||
|
const fs = require('fs')
|
||||||
|
|
||||||
|
|
||||||
|
function getModuleName() {
|
||||||
|
try {
|
||||||
|
let workspacePath = vscode.workspace.workspaceFolders[0].uri.path
|
||||||
|
let modPath = path.join(workspacePath, "go.mod")
|
||||||
|
let data = fs.readFileSync(modPath).toString()
|
||||||
|
let moduleNameReg = new RegExp("(?<=module ).*")
|
||||||
|
let moduleName =moduleNameReg.exec(data)
|
||||||
|
|
||||||
|
return moduleName[0]
|
||||||
|
} catch (err) {
|
||||||
|
vscode.window.showInformationMessage("Could not get module name")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getFileContent(activeEditor) {
|
||||||
|
return activeEditor.document.getText()
|
||||||
|
}
|
||||||
|
|
||||||
|
function getImportsRange(documentText) {
|
||||||
|
let start = 1;
|
||||||
|
let documentLines = documentText.split('\n')
|
||||||
|
for (var line of documentLines) {
|
||||||
|
if (line.includes('import (')) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
start++;
|
||||||
|
}
|
||||||
|
|
||||||
|
let end = start;
|
||||||
|
for (var line of documentLines.slice(start)) {
|
||||||
|
if (line.includes(')')) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
end++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
end,
|
||||||
|
start,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
getModuleName, getFileContent, getImportsRange
|
||||||
|
};
|
Loading…
Reference in a new issue