Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,18 @@
"when": "editorTextFocus && editorLangId == 'azcli'"
}
],
"configuration": {
"type": "object",
"title": "Azure CLI Tools Configuration",
"properties": {
"ms-azurecli.showResponseInDifferentTab": {
"type": "boolean",
"default": false,
"scope": "resource",
"description": "Show response in different tab"
}
}
},
"menus": {
"editor/context": [
{
Expand Down Expand Up @@ -130,7 +142,8 @@
"@types/semver": "5.5.0",
"tslint": "5.16.0",
"typescript": "3.3.3333",
"vscode": "1.1.33"
"vscode": "1.1.33",
"elegant-spinner": "1.0.1"
},
"dependencies": {
"jmespath": "0.15.0",
Expand Down
50 changes: 50 additions & 0 deletions src/configurationSettings.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { Event, EventEmitter, window, workspace } from 'vscode';

export interface IAzureCliToolsSettings {
showResponseInDifferentTab: boolean;
}

export class AzureCliToolsSettings implements IAzureCliToolsSettings {
public showResponseInDifferentTab: boolean = false;

private static _instance: AzureCliToolsSettings;

public static get Instance(): AzureCliToolsSettings {
if (!AzureCliToolsSettings._instance) {
AzureCliToolsSettings._instance = new AzureCliToolsSettings();
}

return AzureCliToolsSettings._instance;
}

public readonly configurationUpdateEventEmitter = new EventEmitter<void>();

public get onDidChangeConfiguration(): Event<void> {
return this.configurationUpdateEventEmitter.event;
}

private constructor() {
workspace.onDidChangeConfiguration(() => {
this.initializeSettings();
this.configurationUpdateEventEmitter.fire();
});
window.onDidChangeActiveTextEditor(e => {
if (e) {
this.initializeSettings();
this.configurationUpdateEventEmitter.fire();
}
});

this.initializeSettings();
}

private initializeSettings() {
const editor = window.activeTextEditor;
const document = editor && editor.document;

const azureCliToolsSettings = workspace.getConfiguration("ms-azurecli", document ? document.uri : null);

this.showResponseInDifferentTab = azureCliToolsSettings.get<boolean>("showResponseInDifferentTab", false);
}

}
39 changes: 32 additions & 7 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as jmespath from 'jmespath';

import { HoverProvider, Hover, SnippetString, StatusBarAlignment, StatusBarItem, ExtensionContext, TextDocument, TextDocumentChangeEvent, Disposable, TextEditor, Selection, languages, commands, Range, ViewColumn, Position, CancellationToken, ProviderResult, CompletionItem, CompletionList, CompletionItemKind, CompletionItemProvider, window, workspace, env, Uri } from 'vscode';

import { AzService, CompletionKind, Arguments, Status } from './azService';
import { parse, findNode } from './parser';
import { exec } from './utils';
import { AzureCliToolsSettings } from './configurationSettings';

export function activate(context: ExtensionContext) {
const azService = new AzService(azNotFound);
Expand All @@ -19,7 +19,6 @@ export function activate(context: ExtensionContext) {
context.subscriptions.push(new RunLineInTerminal());
context.subscriptions.push(new RunLineInEditor(status));
context.subscriptions.push(commands.registerCommand('ms-azurecli.installAzureCLI', installAzureCLI));

}

const completionKinds: Record<CompletionKind, CompletionItemKind> = {
Expand Down Expand Up @@ -147,35 +146,53 @@ class RunLineInTerminal {
}
}

const elegantSpinner = require('elegant-spinner');

class RunLineInEditor {

private resultDocument: TextDocument | undefined;
private parsedResult: object | undefined;
private queryEnabled = false;
private query: string | undefined;
private disposables: Disposable[] = [];
private readonly settings: AzureCliToolsSettings = AzureCliToolsSettings.Instance;
private runStatusBarItem: StatusBarItem;
private interval!: NodeJS.Timer;
private spinner = elegantSpinner();

constructor(private status: StatusBarInfo) {
this.disposables.push(commands.registerTextEditorCommand('ms-azurecli.toggleLiveQuery', editor => this.toggleQuery(editor)));
this.disposables.push(commands.registerTextEditorCommand('ms-azurecli.runLineInEditor', editor => this.run(editor)));
this.disposables.push(workspace.onDidCloseTextDocument(document => this.close(document)));
this.disposables.push(workspace.onDidChangeTextDocument(event => this.change(event)));

this.runStatusBarItem = window.createStatusBarItem(StatusBarAlignment.Left);
Comment thread
mburleigh marked this conversation as resolved.
}

private run(source: TextEditor) {
var t0 = Date.now();
this.interval = setInterval(() => {
this.runStatusBarItem.text = `Waiting for response ${this.spinner()}`;
}, 50);
this.runStatusBarItem.show();

this.parsedResult = undefined;
this.query = undefined; // TODO
const cursor = source.selection.active;
const line = source.document.lineAt(cursor).text;
const isPlainText = (line.indexOf('--query') !== -1) || (line.indexOf('-h') !== -1) || (line.indexOf('--help') !== -1);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you do this in a separate PR? And maybe check the output if it starts and ends with {} or [] to assume it is JSON. That would handle more cases.

return this.findResultDocument()
.then(document => window.showTextDocument(document, ViewColumn.Two, true))
.then(target => replaceContent(target, JSON.stringify({ 'Running command': line }) + '\n')
.then(() => exec(line))
.then(({ stdout }) => stdout, ({ stdout, stderr }) => JSON.stringify({ stderr, stdout }, null, ' '))
.then(content => replaceContent(target, content)
.then(() => this.parsedResult = JSON.parse(content))
.then(undefined, err => {})
)
.then(content => {
replaceContent(target, content, isPlainText ? 'plaintext' : '')
.then(() => this.parsedResult = JSON.parse(content))
.then(undefined, err => {});
clearInterval(this.interval);
this.runStatusBarItem.text = 'AZ CLI command executed in ' + (Date.now() - t0) + ' milliseconds.';
})
)
.then(undefined, console.error);
}
Expand All @@ -188,6 +205,10 @@ class RunLineInEditor {
}

private findResultDocument() {
if (this.settings.showResponseInDifferentTab) {
Comment thread
mburleigh marked this conversation as resolved.
return workspace.openTextDocument({ language: 'json' })
.then(document => this.resultDocument = document);
}
if (this.resultDocument) {
return Promise.resolve(this.resultDocument);
}
Expand Down Expand Up @@ -242,6 +263,7 @@ class RunLineInEditor {

dispose() {
this.disposables.forEach(disposable => disposable.dispose());
this.runStatusBarItem.dispose();
}
}

Expand Down Expand Up @@ -304,8 +326,11 @@ function allMatches(regex: RegExp, string: string, group: number) {
}
}

function replaceContent(editor: TextEditor, content: string) {
function replaceContent(editor: TextEditor, content: string, documentLanguage: string = '') {
const document = editor.document;
if (documentLanguage) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be better to always update because in the case where the document is reused, it might receive JSON again after plain text.

languages.setTextDocumentLanguage(document, documentLanguage);
}
const all = new Range(new Position(0, 0), document.lineAt(document.lineCount - 1).range.end);
return editor.edit(builder => builder.replace(all, content))
.then(() => editor.selections = [new Selection(0, 0, 0, 0)]);
Expand Down