| /*--------------------------------------------------------- |
| * Copyright (C) Microsoft Corporation. All rights reserved. |
| * Licensed under the MIT License. See LICENSE in the project root for license information. |
| *--------------------------------------------------------*/ |
| |
| 'use strict'; |
| |
| import cp = require('child_process'); |
| import vscode = require('vscode'); |
| import { toolExecutionEnvironment } from './goEnv'; |
| import { promptForMissingTool } from './goInstallTools'; |
| import { byteOffsetAt, getBinPath, getFileArchive, 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: toolExecutionEnvironment() }, (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); |
| } |
| }); |
| } |