Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add option to open command results in a new tab #47

Closed
wants to merge 6 commits into from
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);
mburleigh marked this conversation as resolved.
Show resolved Hide 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
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) {
mburleigh marked this conversation as resolved.
Show resolved Hide 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
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