group imports command

This commit is contained in:
NeonXP 2023-08-08 02:40:09 +03:00
parent 80815c107e
commit a8fa5bf1cf
No known key found for this signature in database
GPG key ID: B0DA6283C40CB2CB
7 changed files with 176 additions and 18 deletions

View file

@ -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"

View file

@ -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"
} }
] ]
}, },

View file

@ -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
View 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;

View file

@ -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);
}); });
}); });

View file

@ -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
View 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
};