forked from golang/vscode-go
-
Notifications
You must be signed in to change notification settings - Fork 0
/
goFillStruct.ts
103 lines (90 loc) · 3.13 KB
/
goFillStruct.ts
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
/*---------------------------------------------------------
* Copyright (C) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------*/
'use strict';
import cp = require('child_process');
import vscode = require('vscode');
import { promptForMissingTool } from './goInstallTools';
import { byteOffsetAt, getBinPath, getFileArchive, getToolsEnvVars, makeMemoizedByteOffsetConverter } from './util';
// Interface for the output from fillstruct
interface GoFillStructOutput {
start: number;
end: number;
code: string;
}
export function runFillStruct(editor: vscode.TextEditor): Promise<void> {
const args = getCommonArgs(editor);
if (!args) {
return Promise.reject('No args');
}
return execFillStruct(editor, args);
}
function getCommonArgs(editor: vscode.TextEditor): string[] | undefined {
if (!editor) {
vscode.window.showInformationMessage('No editor is active.');
return;
}
if (!editor.document.fileName.endsWith('.go')) {
vscode.window.showInformationMessage('Current file is not a Go file.');
return;
}
const args = ['-modified', '-file', editor.document.fileName];
if (editor.selection.isEmpty) {
const offset = byteOffsetAt(editor.document, editor.selection.start);
args.push('-offset');
args.push(offset.toString());
} else {
args.push('-line');
args.push(`${editor.selection.start.line + 1}`);
}
return args;
}
function getTabsCount(editor: vscode.TextEditor): number {
const startline = editor.selection.start.line;
const tabs = editor.document.lineAt(startline).text.match('^\t*');
return tabs ? tabs.length : 0;
}
function execFillStruct(editor: vscode.TextEditor, args: string[]): Promise<void> {
const fillstruct = getBinPath('fillstruct');
const input = getFileArchive(editor.document);
const tabsCount = getTabsCount(editor);
return new Promise<void>((resolve, reject) => {
const p = cp.execFile(fillstruct, args, { env: getToolsEnvVars() }, (err, stdout, stderr) => {
try {
if (err && (<any>err).code === 'ENOENT') {
promptForMissingTool('fillstruct');
return reject();
}
if (err) {
vscode.window.showInformationMessage(`Cannot fill struct: ${stderr}`);
return reject();
}
const output = <GoFillStructOutput[]>JSON.parse(stdout);
if (output.length === 0) {
vscode.window.showInformationMessage(`Got empty fillstruct output`);
return reject();
}
const indent = '\t'.repeat(tabsCount);
const offsetConverter = makeMemoizedByteOffsetConverter(Buffer.from(editor.document.getText()));
editor
.edit((editBuilder) => {
output.forEach((structToFill) => {
const out = structToFill.code.replace(/\n/g, '\n' + indent);
const rangeToReplace = new vscode.Range(
editor.document.positionAt(offsetConverter(structToFill.start)),
editor.document.positionAt(offsetConverter(structToFill.end))
);
editBuilder.replace(rangeToReplace, out);
});
})
.then(() => resolve());
} catch (e) {
reject(e);
}
});
if (p.pid) {
p.stdin.end(input);
}
});
}