From b329d9f5c86f1418bf8bfbfcbbf40bbaedb86156 Mon Sep 17 00:00:00 2001 From: Andrey Bogoyavlensky Date: Wed, 5 Feb 2020 00:13:17 +0300 Subject: [PATCH] Add optional ability to show evaluation result inline --- README.md | 3 +- package.json | 29 +++++++++++++++-- src/clojureEval.ts | 81 +++++++++++++++++++++++++++++++++++++++++++--- src/clojureMain.ts | 10 +++++- 4 files changed, 115 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 500dd27..e648a63 100644 --- a/README.md +++ b/README.md @@ -61,7 +61,7 @@ option in your VSCode settings globally or per-project and connect manually to w ```clojure {:user {:plugins [[cider/cider-nrepl "0.22.1"]] - :dependencies [[cljfmt "0.5.7"]]}} + :dependencies [[cljfmt "0.5.7"]]}} ``` Alternatively, you can put the code above to your project `project.clj` file. @@ -75,6 +75,7 @@ The extension contributes the configuration parameters listed in the table below |`clojureVSCode.autoStartNRepl` | Whether to start an nREPL when opening a file or project. | |`clojureVSCode.formatOnSave` | Format files with [cljfmt](https://github.com/weavejester/cljfmt) on save. | |`clojureVSCode.cljfmtParameters`| Formatting parameters passed to `cljfmt` each time it runs, e.g. `:indentation? true :remove-surrounding-whitespace? false` | +|`clojureVSCode.showResultInline` | Show evaluation result inline. | ## ClojureScript Project Setup diff --git a/package.json b/package.json index 1bbc072..4b6d174 100644 --- a/package.json +++ b/package.json @@ -121,11 +121,36 @@ }, "clojureVSCode.cljfmtParameters": { "type": "string", - "description": "Parameters which will be passed to cljfmt", + "description": "Parameters which will be passed to cljfmt.", "default": "" + }, + "clojureVSCode.showResultInline": { + "type": "boolean", + "default": false, + "description": "Show evaluation result inline." } } - } + }, + "colors": [ + { + "id": "clojureVSCode.inlineResultBackground", + "description": "Background color of the inline result.", + "defaults": { + "dark": "#00000000", + "light": "#00000000", + "highContrast": "#00000000" + } + }, + { + "id": "clojureVSCode.inlineResultForeground", + "description": "Foreground color of the inline result.", + "defaults": { + "dark": "#99999999", + "light": "#99999999", + "highContrast": "#99999999" + } + } + ] }, "scripts": { "vscode:prepublish": "webpack --mode production", diff --git a/src/clojureEval.ts b/src/clojureEval.ts index 0bfe763..fd487fc 100644 --- a/src/clojureEval.ts +++ b/src/clojureEval.ts @@ -1,6 +1,7 @@ import * as vscode from 'vscode'; import { cljConnection } from './cljConnection'; +import { LANGUAGE } from './clojureMode'; import { cljParser } from './cljParser'; import { nreplClient } from './nreplClient'; import { TestListener } from './testRunner'; @@ -10,6 +11,17 @@ const BLOCK_DECORATION_TYPE = vscode.window.createTextEditorDecorationType({ backgroundColor: { id: 'editor.findMatchHighlightBackground' } }); +const INLINE_RESULT_LENGTH = 150; +const INLINE_RESULT_DECORATION_TYPE = vscode.window.createTextEditorDecorationType({ + before: { + margin: '0 0 0 2em', + textDecoration: 'none', + fontWeight: 'normal', + fontStyle: 'normal', + }, + rangeBehavior: vscode.DecorationRangeBehavior.ClosedOpen +}); + export function clojureEval(outputChannel: vscode.OutputChannel): void { evaluate(outputChannel, false); } @@ -174,10 +186,15 @@ function evaluate(outputChannel: vscode.OutputChannel, showResults: boolean): vo } const selection = blockSelection || editor.selection; - let text = editor.document.getText(); + let text = editor.document.getText(), + selectionEndLine: number; + if (!selection.isEmpty) { + selectionEndLine = selection.end.line; const ns: string = cljParser.getNamespace(text); text = `(ns ${ns})\n${editor.document.getText(selection)}`; + } else { + selectionEndLine = editor.document.lineCount - 1; } cljConnection.sessionForFilename(editor.document.fileName).then(session => { @@ -195,7 +212,7 @@ function evaluate(outputChannel: vscode.OutputChannel, showResults: boolean): vo if (!!respObjs[0].ex) return handleError(outputChannel, selection, showResults, respObjs[0].session); - return handleSuccess(outputChannel, showResults, respObjs); + return handleSuccess(outputChannel, showResults, respObjs, selectionEndLine); }) }); } @@ -235,10 +252,51 @@ function handleError(outputChannel: vscode.OutputChannel, selection: vscode.Sele }); } -function handleSuccess(outputChannel: vscode.OutputChannel, showResults: boolean, respObjs: any[]): void { +function truncateLine(value: string): string { + if (value.length > INLINE_RESULT_LENGTH) { + return value.substring(0, INLINE_RESULT_LENGTH) + '...' + } + return value; +} + +function showInlineResult(respObj: any, line: number): void { + const isError = Boolean(respObj.err), + editor = vscode.window.activeTextEditor; + let result: string, + foregroundColor: vscode.ThemeColor; + + if (isError) { + // show more error description at once + result = respObj.err.replace(/\n/g, ' '); + foregroundColor = new vscode.ThemeColor('editorError.foreground'); + } else { + result = respObj.value; + foregroundColor = new vscode.ThemeColor('clojureVSCode.inlineResultForeground'); + } + + if (result && editor) { + const decoration: vscode.DecorationOptions = { + renderOptions: { + before: { + backgroundColor: new vscode.ThemeColor('clojureVSCode.inlineResultBackground'), + color: foregroundColor, + contentText: truncateLine(result), + }, + }, + range: editor.document.validateRange( + new vscode.Range(line, Number.MAX_SAFE_INTEGER, line, Number.MAX_SAFE_INTEGER) + ) + }; + editor.setDecorations(INLINE_RESULT_DECORATION_TYPE, [decoration]); + } +} + +function handleSuccess(outputChannel: vscode.OutputChannel, showResults: boolean, respObjs: any[], selectionEndLine: number): void { if (!showResults) { vscode.window.showInformationMessage('Successfully compiled'); } else { + const config = vscode.workspace.getConfiguration('clojureVSCode'); + respObjs.forEach(respObj => { if (respObj.out) outputChannel.append(respObj.out); @@ -246,8 +304,23 @@ function handleSuccess(outputChannel: vscode.OutputChannel, showResults: boolean outputChannel.append(respObj.err); if (respObj.value) outputChannel.appendLine(`=> ${respObj.value}`); - outputChannel.show(true); + + if (config.showResultInline) { + showInlineResult(respObj, selectionEndLine); + } else { + outputChannel.show(true); + }; }); } nreplClient.close(respObjs[0].session); +}; + +export function clearInlineResultDecorationOnMove(event: vscode.TextEditorSelectionChangeEvent) { + const config = vscode.workspace.getConfiguration('clojureVSCode'); + if (config.showResultInline + && event.textEditor.document.languageId === LANGUAGE + && event.textEditor === vscode.window.activeTextEditor) { + + event.textEditor.setDecorations(INLINE_RESULT_DECORATION_TYPE, []); + } } diff --git a/src/clojureMain.ts b/src/clojureMain.ts index df10bf0..db57f03 100644 --- a/src/clojureMain.ts +++ b/src/clojureMain.ts @@ -2,7 +2,10 @@ import * as vscode from 'vscode'; import { CLOJURE_MODE, LANGUAGE } from './clojureMode'; import { ClojureCompletionItemProvider } from './clojureSuggest'; -import { clojureEval, clojureEvalAndShowResult, testNamespace, runAllTests } from './clojureEval'; +import { + clojureEval, clojureEvalAndShowResult, testNamespace, runAllTests, + clearInlineResultDecorationOnMove +} from './clojureEval'; import { ClojureDefinitionProvider } from './clojureDefinition'; import { ClojureLanguageConfiguration } from './clojureConfiguration'; import { ClojureHoverProvider } from './clojureHover'; @@ -48,6 +51,11 @@ export function activate(context: vscode.ExtensionContext) { vscode.workspace.registerTextDocumentContentProvider('jar', new JarContentProvider()); vscode.languages.setLanguageConfiguration(LANGUAGE, ClojureLanguageConfiguration); + + // events + vscode.window.onDidChangeTextEditorSelection(event => { + clearInlineResultDecorationOnMove(event); + }, null, context.subscriptions); } export function deactivate() { }