-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathextension.js
157 lines (131 loc) · 4.54 KB
/
extension.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
const vscode = require('vscode');
/**
* @param {vscode.ExtensionContext} context
*/
function activate(context) {
let disposable = vscode.commands.registerCommand('fillinit.preFillFromArgs', function () {
const editor = vscode.window.activeTextEditor;
if (editor) {
const document = editor.document;
const currentLine = editor.selection.active.line;
const viewRange = searchForDunderInit(editor, currentLine);
if (!viewRange) {
vscode.window.showErrorMessage('No __init__ method found');
return;
}
const editRange = new vscode.Range(viewRange.start.line+1, 0, viewRange.start.line+1, Infinity);
const classLineText = document.getText(viewRange);
const edit = getArgs(classLineText);
editor.edit(editBuilder => {
editBuilder.replace(editRange, edit);
});
}
});
context.subscriptions.push(disposable);
}
function deactivate() {}
function searchForDunderInit(editor, activeLine) {
/*
Searches for the dunder init method
*/
const settings = vscode.workspace.getConfiguration('fillinit');
const document = editor.document;
let increase = 0;
let dir = 1;
let maxSearchSize = settings['maxSearchSize'];
while (true) {
dir *= -1;
increase++;
const checkRange = new vscode.Range(activeLine, 0, activeLine, Infinity);
const checkText = document.getText(checkRange);
if (checkText.includes('__init__')) {
return new vscode.Range(activeLine, 0, activeLine, Infinity);;
} else {
activeLine += dir * increase;
}
if (increase > maxSearchSize) {
return null;
}
}
}
function paramStringBuilder(paramName, indentAmount, selfName = "self") {
/*
Parse the argument (in that case python argument) and build self parameter initialization string
So far it checks for type hints, default values.
Naming convention and linting is left for python server (e.g. Pylance) responsible as we do not want to
fix and take care of all the possible problems of the world :)
*/
const settings = vscode.workspace.getConfiguration('fillinit');
let typeHint = ""
// trimming * and ** in args, kwargs as they are not needed
paramName = paramName.trim().replace(/^\**/, "")
// checking if there is a default param value as we don't need it
if (paramName.includes("=")) {
paramName = (paramName.split("=")[0])
}
// check if there is a type hinting included
if (paramName.includes(":")) {
[paramName, typeHint] = paramName.split(":")
paramName = paramName.trim()
typeHint = typeHint.trim()
if (settings.includeTypeHints) {
return `${' '.repeat(indentAmount)}${selfName}.${paramName}: ${typeHint} = ${paramName}\n`
}
}
return `${' '.repeat(indentAmount)}${selfName}.${paramName} = ${paramName}\n`
}
function parseInitParamString(_str) {
const params = [];
let position_from = 0;
let bracket_counter = 0;
for (var cur_pos = 0; cur_pos < _str.length; cur_pos++) {
//check if there is any opening brackets for type hints, if so then increase bracket counter so i can skip the "wrong comma"
if ("[(".includes(_str[cur_pos])) {
bracket_counter += 1;
continue;
}
// check if there is any closing bracket for type hints, if so then decrease bracket counter so i am closer to the right comma
if (")]".includes(_str[cur_pos])) {
bracket_counter -= 1;
continue;
}
//finally check if this comma is a final argument comma separator, not some inner from type hint
if (_str[cur_pos] == "," && bracket_counter==0) {
params.push(_str.substring(position_from, cur_pos));
position_from = cur_pos + 1;
}
continue;
}
// adding the last argument as there is no comma at the end
params.push(_str.substring(position_from, _str.length));
return params.map(item => item.trim())
}
function getArgs(lineText) {
/*
Creates and indents the arguments inside of the dunder init method
``` def __init__(self, arg1, arg2, arg3):```
Returns:
self.arg1 = arg1
self.arg2 = arg2
self.arg3 = arg3
*/
const re = /\((.+)\)/;
let indentAmount = lineText.search(/\S/) + vscode.window.activeTextEditor.options.tabSize;
// assumes that no-one will ever use single-spaced indents
// and if you happen to use single-spaced indents, you should not be allowed to use a computer
if (lineText.search(/\S/) == 1) {
indentAmount += vscode.window.activeTextEditor.options.tabSize-1;
}
lineText = lineText.match(re)[1];
lineText = parseInitParamString(lineText);
let text = '';
// starting from index 1 to ommit self (the very first parameter)
for (let i = 1; i < lineText.length; i++) {
text += paramStringBuilder(lineText[i], indentAmount, lineText[0]);
}
return text;
}
module.exports = {
activate,
deactivate
}