diff --git a/package.json b/package.json index 13ec194..a2800cf 100644 --- a/package.json +++ b/package.json @@ -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": [ { @@ -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", diff --git a/src/configurationSettings.ts b/src/configurationSettings.ts new file mode 100644 index 0000000..3704ac6 --- /dev/null +++ b/src/configurationSettings.ts @@ -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(); + + public get onDidChangeConfiguration(): Event { + 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("showResponseInDifferentTab", false); + } + +} \ No newline at end of file diff --git a/src/extension.ts b/src/extension.ts index 4e526d7..6f2a44c 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -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); @@ -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 = { @@ -147,6 +146,8 @@ class RunLineInTerminal { } } +const elegantSpinner = require('elegant-spinner'); + class RunLineInEditor { private resultDocument: TextDocument | undefined; @@ -154,28 +155,44 @@ class RunLineInEditor { 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); } 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); 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); } @@ -188,6 +205,10 @@ class RunLineInEditor { } private findResultDocument() { + if (this.settings.showResponseInDifferentTab) { + return workspace.openTextDocument({ language: 'json' }) + .then(document => this.resultDocument = document); + } if (this.resultDocument) { return Promise.resolve(this.resultDocument); } @@ -242,6 +263,7 @@ class RunLineInEditor { dispose() { this.disposables.forEach(disposable => disposable.dispose()); + this.runStatusBarItem.dispose(); } } @@ -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) { + 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)]);