Skip to content

Commit

Permalink
Print results and output to a tmp .calva-out file
Browse files Browse the repository at this point in the history
Fixes #681

TODO:
- There are still problems with printing several times during an eval.
- If the output doc is visible it should be scrolled immediately
- Stop printing to Calva says.
- Possibly, open the output doc where it was last placed
  • Loading branch information
PEZ committed Jul 21, 2020
1 parent 9715678 commit b2c82f9
Show file tree
Hide file tree
Showing 6 changed files with 116 additions and 3 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
Changes to Calva.

## [Unreleased]
- [Send evaluation results and output to a file](https://github.com/BetterThanTomorrow/calva/issues/681)

## [2.0.107] - 2020-06-16
- Fix [Flicker matching brackets as code is typed](https://github.com/BetterThanTomorrow/calva/issues/673)
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,8 @@
".clojure",
".edn",
".joke",
".boot"
".boot",
".calva-out"
]
}
],
Expand Down
2 changes: 2 additions & 0 deletions src/connector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { CljsTypeConfig, ReplConnectSequence, getDefaultCljsType, CljsTypes, ask
import { disabledPrettyPrinter } from './printer';
import { keywordize } from './util/string';
import { REQUESTS, initializeDebugger } from './debugger/calva-debug';
import * as resultsOutput from './result-output'

async function createAndConnectReplWindow(session: NReplSession, mode: "clj" | "cljs", ): Promise<void> {
if (state.config().openREPLWindowOnConnect) {
Expand Down Expand Up @@ -60,6 +61,7 @@ async function connectToHost(hostname, port, connectSequence: ReplConnectSequenc
state.cursor.set('clj', cljSession);
state.cursor.set('cljc', cljSession);
status.update();
resultsOutput.openResultsDoc(true);

// Initialize debugger
await initializeDebugger(cljSession);
Expand Down
13 changes: 13 additions & 0 deletions src/evaluate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ import { activeReplWindow } from './repl-window';
import { NReplSession, NReplEvaluation } from './nrepl';
import statusbar from './statusbar';
import { PrettyPrintingOptions } from './printer';
import * as resultsOutput from './result-output'



function interruptAllEvaluations() {

Expand Down Expand Up @@ -92,6 +95,7 @@ async function evaluateSelection(document, options) {
stdout: (m) => {
out.push(m);
chan.appendLine(normalizeNewLines(m));
resultsOutput.appendToResultsDoc(normalizeNewLines(m));
},
stderr: m => err.push(m),
pprintOptions: pprintOptions
Expand All @@ -115,11 +119,14 @@ async function evaluateSelection(document, options) {
if (!asComment) {
chan.appendLine('=>');
chan.appendLine(value);
resultsOutput.appendToResultsDoc(value);
}

if (err.length > 0) {
chan.appendLine("Error:")
chan.appendLine(normalizeNewLinesAndJoin(err));
resultsOutput.appendToResultsDoc(";Error:")
resultsOutput.appendToResultsDoc(`;${normalizeNewLinesAndJoin(err)}`);
}
} catch (e) {
if (!err.length) { // venantius/ultra outputs errors on stdout, it seems.
Expand All @@ -128,6 +135,8 @@ async function evaluateSelection(document, options) {
if (err.length > 0) {
chan.appendLine("Error:")
chan.appendLine(normalizeNewLinesAndJoin(err));
resultsOutput.appendToResultsDoc(";Error:")
resultsOutput.appendToResultsDoc(`;${normalizeNewLinesAndJoin(err)}`);
}

const message = util.stripAnsi(err.join("\n"));
Expand Down Expand Up @@ -192,6 +201,7 @@ async function loadFile(document, callback: () => { }, pprintOptions: PrettyPrin
if (doc && doc.languageId == "clojure" && fileType != "edn" && current.get('connected')) {
state.analytics().logEvent("Evaluation", "LoadFile").send();
chan.appendLine("Evaluating file: " + fileName);
resultsOutput.appendToResultsDoc(";Evaluating file: " + fileName);

let res = client.loadFile(doc.getText(), {
fileName: fileName,
Expand All @@ -203,11 +213,14 @@ async function loadFile(document, callback: () => { }, pprintOptions: PrettyPrin
await res.value.then((value) => {
if (value) {
chan.appendLine("=> " + value);
resultsOutput.appendToResultsDoc(value);
} else {
chan.appendLine("No results from file evaluation.");
resultsOutput.appendToResultsDoc(";No results from file evaluation.");
}
}).catch((e) => {
chan.appendLine(`Evaluation of file ${fileName} failed: ${e}`);
resultsOutput.appendToResultsDoc(`;Evaluation of file ${fileName} failed: ${e}`);
});
}
if (callback) {
Expand Down
96 changes: 96 additions & 0 deletions src/result-output.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import * as os from 'os';
import * as path from 'path';
import * as vscode from 'vscode';
import * as state from './state';

const RESULTS_DOC_NAME = 'eval-results.calva-out';

function getResultsUri(untitled: boolean): vscode.Uri {
return vscode.Uri.parse((untitled ? 'untitled:' : '') + path.join(os.tmpdir(), RESULTS_DOC_NAME));
}

export async function openResultsDoc(clear: boolean = false): Promise<vscode.TextDocument> {
let exists: boolean = false;
let resultsDoc: vscode.TextDocument;
try {
const stat = await vscode.workspace.fs.stat(getResultsUri(false));
exists = true;
} catch {
exists = false;
}
await vscode.workspace.openTextDocument(getResultsUri(!exists)).then(async doc => {
resultsDoc = doc;
if (clear) {
var edit = new vscode.WorkspaceEdit();
edit.delete(getResultsUri(false), new vscode.Range(
new vscode.Position(0, 0),
doc.positionAt(doc.getText().length)
));
const success = await vscode.workspace.applyEdit(edit);
if (!success) {
state.deref().outputChannel().appendLine('Error clearing output document.')
}
}
vscode.window.showTextDocument(doc, 1, true);
});
return resultsDoc;
}

export function revealResultsDoc() {
openResultsDoc().then(doc => {
vscode.window.showTextDocument(doc);
});
}

let scrollToBottomSub: vscode.Disposable;

export function appendToResultsDoc(text: string, reveal: boolean = false) {
const edit = new vscode.WorkspaceEdit();
vscode.workspace.openTextDocument(getResultsUri(false)).then(doc => {
edit.insert(getResultsUri(false), doc.positionAt(Infinity), `${text}\n`);
if (scrollToBottomSub) {
scrollToBottomSub.dispose();
}
scrollToBottomSub = vscode.window.onDidChangeActiveTextEditor((editor) => {
if (path.basename(editor.document.fileName) === RESULTS_DOC_NAME) {
const lastPos = editor.document.positionAt(Infinity);
editor.selection = new vscode.Selection(lastPos, lastPos);
editor.revealRange(new vscode.Range(lastPos, lastPos));
console.log("Scrolled to bottom")
scrollToBottomSub.dispose();
}
});
state.extensionContext.subscriptions.push(scrollToBottomSub);
vscode.workspace.applyEdit(edit).then(
success => {
if (!success) {
console.log("Sad puppy")
}
},
reason => {
console.error(`Error appending output to: ${getResultsUri(false).path}`);
console.error(reason)
}
);
})
}

// function createFileWithContent(filename, content) {
// var newFile = vscode.Uri.parse('untitled:' + path.join(os.homedir(), filename));
// vscode.workspace.openTextDocument(newFile).then(function (document) {
// var edit = new vscode.WorkspaceEdit();
// edit.delete(newFile, new vscode.Range(
// document.positionAt(0),
// document.positionAt(document.getText().length - 1)
// ));
// return vscode.workspace.applyEdit(edit).then(function (success) {
// var edit = new vscode.WorkspaceEdit();
// edit.insert(newFile, new vscode.Position(0, 0), content);
// return vscode.workspace.applyEdit(edit).then(function (success) {
// if (success) {
// vscode.window.showTextDocument(document);
// }
// });
// });
// });
// }
4 changes: 2 additions & 2 deletions src/utilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ function getSession(fileType = undefined): NReplSession {
if (fileType.match(/^clj[sc]?/)) {
return current.get(fileType);
} else {
return current.get('clj');
return current.get('cljc');
}
}

Expand Down Expand Up @@ -402,7 +402,7 @@ function updateREPLSessionType() {
sessionType = 'cljs'
else if (fileType == 'clj' && getSession('clj') !== null)
sessionType = 'clj'
else if (fileType == 'cljc' && getSession('cljc') !== null)
else if (getSession('cljc') !== null)
sessionType = getSession('cljc') == getSession('clj') ? 'clj' : 'cljs';
else
sessionType = 'clj'
Expand Down

0 comments on commit b2c82f9

Please sign in to comment.