Skip to content

Commit

Permalink
Merge pull request #2484 from BetterThanTomorrow/eval-output-context
Browse files Browse the repository at this point in the history
Eval output context

* Fixes #2483
  • Loading branch information
PEZ committed Apr 1, 2024
2 parents 19e4689 + 57bfad8 commit f292904
Show file tree
Hide file tree
Showing 6 changed files with 97 additions and 46 deletions.
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@

Changes to Calva.


## [Unreleased]

- [Implement experimental support for multicursor rewrap commands](https://github.com/BetterThanTomorrow/calva/issues/2448). Enable `calva.paredit.multicursor` in your settings to try it out. Closes [#2473](https://github.com/BetterThanTomorrow/calva/issues/2473)
- [Add a separator line between evaluation outputs to the Output terminal](https://github.com/BetterThanTomorrow/calva/issues/2483)
- [Implement experimental support for multicursor selectCurrentForm command](https://github.com/BetterThanTomorrow/calva/issues/2476). Enable `calva.paredit.multicursor` in your settings to try it out. Closes [#2476](https://github.com/BetterThanTomorrow/calva/issues/2476)
- [Implement experimental support for multicursor rewrap commands](https://github.com/BetterThanTomorrow/calva/issues/2473). Enable `calva.paredit.multicursor` in your settings to try it out. Closes [#2473](https://github.com/BetterThanTomorrow/calva/issues/2473)

## [2.0.432] - 2024-03-26

Expand Down
21 changes: 12 additions & 9 deletions src/evaluate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ async function evaluateCodeUpdatingUI(
if (evaluationSendCodeToOutputWindow) {
outputWindow.appendLine(code);
if (output.getDestinationConfiguration().evalOutput !== 'repl-window') {
output.appendClojureEval(code);
output.appendClojureEval(code, { ns, replSessionType: session.replType });
}
}

Expand All @@ -134,7 +134,7 @@ async function evaluateCodeUpdatingUI(
result = value;

if (showResult) {
output.appendClojureEval(value, async () => {
output.appendClojureEval(value, { ns, replSessionType: session.replType }, async () => {
if (selection) {
const c = selection.start.character;
if (editor && options.replace) {
Expand Down Expand Up @@ -171,10 +171,10 @@ async function evaluateCodeUpdatingUI(
outputWindow.markLastStacktraceRange(afterResultLocation);
});
if (output.getDestinationConfiguration().evalOutput !== 'repl-window') {
output.appendClojureOther(errMsg);
output.appendEvalErr(errMsg, { ns, replSessionType: session.replType });
}
} else {
output.appendLineEvalErr(errMsg);
output.appendEvalErr(errMsg, { ns, replSessionType: session.replType });
}
}
}
Expand Down Expand Up @@ -222,7 +222,10 @@ async function evaluateCodeUpdatingUI(
});
});
if (output.getDestinationConfiguration().evalOutput !== 'repl-window') {
output.appendLineEvalErr(err.length ? err.join('\n') : e);
output.appendEvalErr(err.length ? err.join('\n') : e, {
ns,
replSessionType: session.replType,
});
}
}
}
Expand Down Expand Up @@ -535,15 +538,15 @@ async function loadFile(
filePath,
stdout: (m) => output.appendEvalOut(m),
stderr: (m) => {
output.appendLineEvalErr(m);
output.appendEvalErr(m, { ns, replSessionType: session.replType });
errorMessages.push(m);
},
pprintOptions: pprintOptions,
});
try {
const value = await res.value;
if (value) {
output.appendClojureEval(value);
output.appendClojureEval(value, { ns, replSessionType: session.replType });
} else {
output.appendLineEvalOut('No results from file evaluation.');
}
Expand All @@ -558,7 +561,7 @@ async function loadFile(
}
);
if (output.getDestinationConfiguration().evalOutput !== 'repl-window') {
output.appendLineEvalErr(`Evaluation of file ${fileName} failed: ${e}`);
output.appendLineOtherErr(`Evaluation of file ${fileName} failed: ${e}`);
}
if (
!vscode.window.visibleTextEditors.find((editor: vscode.TextEditor) =>
Expand Down Expand Up @@ -701,7 +704,7 @@ async function evaluateInOutputWindow(code: string, sessionType: string, ns: str
column: evalPos.character,
});
} catch (e) {
output.appendLineEvalErr('Evaluation failed.');
output.appendLineOtherErr('Evaluation failed.');
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/nrepl/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -292,7 +292,7 @@ export class NReplSession {
if (msgData.out) {
output.appendEvalOut(msgData.out);
} else if (msgData.err) {
output.appendEvalErr(msgData.err);
output.appendEvalErr(msgData.err, { ns: msgData.ns, replSessionType: this.replType });
}
}
}
Expand Down
74 changes: 60 additions & 14 deletions src/results-output/output.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,24 @@ type AppendOptions = {
after?: AfterAppendCallback;
};

type AppendClojureOptions = {
ns?: string;
replSessionType?: string;
};

const lightTheme = {
evalSeparatorSessionType: customChalk.bgGreen,
evalSeparatorNs: customChalk.bgBlue,
evalOut: customChalk.gray,
evalErr: customChalk.red,
otherOut: customChalk.green,
otherErr: customChalk.red,
};

const darkTheme = {
evalOut: customChalk.grey,
evalSeparatorSessionType: customChalk.bgWhite,
evalSeparatorNs: customChalk.bgWhiteBright,
evalOut: customChalk.gray,
evalErr: customChalk.redBright,
otherOut: customChalk.grey,
otherErr: customChalk.redBright,
Expand Down Expand Up @@ -165,15 +174,40 @@ export function maybePrintLegacyREPLWindowOutputMessage() {
}
}

function appendClojure(options: AppendOptions, message: string, after?: AfterAppendCallback) {
const lastInfoLineData: Record<OutputDestination, AppendClojureOptions> = {
'repl-window': {},
'output-channel': {},
terminal: {},
};

function saveLastInfoLineData(destination: OutputDestination, options: AppendClojureOptions) {
const { ns, replSessionType } = options;
if (ns) {
lastInfoLineData[destination] = { ns, replSessionType };
}
}

function nsInfoLine(destination: OutputDestination, options: AppendClojureOptions) {
return options.ns &&
`${options.replSessionType}:${options.ns}` !==
`${lastInfoLineData[destination].replSessionType}:${lastInfoLineData[destination].ns}`
? `\n;${themedChalk().evalSeparatorSessionType(
' ' + options.replSessionType + ' '
)}${themedChalk().evalSeparatorNs(' ' + options.ns + ' ')}\n`
: '\n';
}

function appendClojure(
options: AppendOptions & AppendClojureOptions,
message: string,
after?: AfterAppendCallback
) {
const destination = options.destination;
const didLastTerminateLine = didLastOutputTerminateLine[destination];
didLastOutputTerminateLine[destination] = true;
if (destination === 'repl-window') {
outputWindow.appendLine(`${didLastTerminateLine ? '' : '\n'}${message}`, after);
return;
}
if (destination === 'output-channel') {
} else if (destination === 'output-channel') {
const doc = new model.StringDocument(message);
const cursor = doc.getTokenCursor(0);
const shouldFence =
Expand All @@ -183,17 +217,18 @@ function appendClojure(options: AppendOptions, message: string, after?: AfterApp
if (after) {
after(undefined, undefined);
}
return;
}
if (destination === 'terminal') {
} else if (destination === 'terminal') {
const printerOptions = { ...printer.prettyPrintingOptions(), 'color?': true };
const prettyMessage = printer.prettyPrint(message, printerOptions)?.value || message;
getOutputPTY().write(`${didLastTerminateLine ? '' : '\r\n'}${prettyMessage}\r\n`);
// TODO: Figure if it's worth a setting to opt-in on an ns info line
getOutputPTY().write(`${didLastTerminateLine ? '' : '\n'}${nsInfoLine(destination, options)}`);
// getOutputPTY().write(`${didLastTerminateLine ? '' : '\n'}`);
getOutputPTY().write(`${prettyMessage}\n`);
if (after) {
after(undefined, undefined);
}
return;
}
saveLastInfoLineData(destination, options);
}

/**
Expand All @@ -203,9 +238,13 @@ function appendClojure(options: AppendOptions, message: string, after?: AfterApp
* @param code The code to append
* @param after Optional callback to run after the append
*/
export function appendClojureEval(code: string, after?: AfterAppendCallback) {
export function appendClojureEval(
code: string,
options: AppendClojureOptions,
after?: AfterAppendCallback
) {
const destination = getDestinationConfiguration().evalResults;
appendClojure({ destination, outputCategory: 'evalResults' }, code, after);
appendClojure({ destination, outputCategory: 'evalResults', ...options }, code, after);
}

/**
Expand All @@ -223,7 +262,7 @@ export function appendClojureOther(message: string, after?: AfterAppendCallback)
function append(options: AppendOptions, message: string, after?: AfterAppendCallback) {
const destination = options.destination;
const didLastTerminateLine = didLastOutputTerminateLine[destination];
didLastOutputTerminateLine[destination] = message.endsWith('\n');
didLastOutputTerminateLine[destination] = util.stripAnsi(message).endsWith('\n');
if (destination === 'repl-window') {
const decoratedMessage =
options.outputCategory === 'evalOut' && config.getConfig().legacyPrintBareReplWindowOutput
Expand Down Expand Up @@ -269,13 +308,20 @@ export function appendEvalOut(message: string, after?: AfterAppendCallback) {
* @param message The message to append
* @param after Optional callback to run after the append
*/
export function appendEvalErr(message: string, after?: AfterAppendCallback) {
export function appendEvalErr(
message: string,
options: AppendClojureOptions,
after?: AfterAppendCallback
) {
const destination = getDestinationConfiguration().evalOutput;
const coloredMessage =
destinationSupportsAnsi(destination) && !messageContainsAnsi(message)
? themedChalk().evalErr(message)
: message;
// TODO: Figure if it's worth a setting to opt-in on an ns info line
append({ destination, outputCategory: 'evalErr' }, nsInfoLine(destination, options));
append({ destination, outputCategory: 'evalErr' }, coloredMessage, after);
saveLastInfoLineData(destination, options);
}

/**
Expand Down
2 changes: 1 addition & 1 deletion test-data/.calva/config.edn
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{:customREPLHoverSnippets
{#_#_:customREPLHoverSnippets
[{:name "edn hover symbol"
:snippet (str "**EDN edn hover symbol**: " $hover-text)}
{:name "edn hover symbol quoted"
Expand Down
40 changes: 20 additions & 20 deletions test-data/.vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,26 +22,26 @@
}
],
"calva.customREPLHoverSnippets": [
{
"name": "Selection, closing brackets",
"snippet": "$selection-closing-brackets"
},
{
"name": "edn hover hover-text",
"snippet": "(str \"**JSON hover hover-text** \" \"$hover-text\")"
},
{
"name": "Show doc string",
"snippet": "(clojure.string/replace (with-out-str (clojure.repl/doc $hover-text)) \"\n\" \"\n\n\")"
},
{
"name": "Show current pair",
"snippet": "'\"Current pair: $hover-current-pair\""
},
{
"name": "Show current file text",
"snippet": "'(\"Current file text: $hover-file-text\")"
}
// {
// "name": "Selection, closing brackets",
// "snippet": "$selection-closing-brackets"
// },
// {
// "name": "edn hover hover-text",
// "snippet": "(str \"**JSON hover hover-text** \" \"$hover-text\")"
// },
// {
// "name": "Show doc string",
// "snippet": "(clojure.string/replace (with-out-str (clojure.repl/doc $hover-text)) \"\n\" \"\n\n\")"
// },
// {
// "name": "Show current pair",
// "snippet": "'\"Current pair: $hover-current-pair\""
// },
// {
// "name": "Show current file text",
// "snippet": "'(\"Current file text: $hover-file-text\")"
// }
],
"calva.fiddleFilePaths": [
{
Expand Down

0 comments on commit f292904

Please sign in to comment.