Skip to content

Commit

Permalink
Merge pull request #2624 from ikappaki/issue/error-hover-new-lines
Browse files Browse the repository at this point in the history
Preserve whitespaces format of evaluation error in tooltip

* Fixes #2623
  • Loading branch information
PEZ committed Sep 15, 2024
2 parents f279ee7 + a643afd commit 9df9146
Show file tree
Hide file tree
Showing 3 changed files with 123 additions and 11 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ Changes to Calva.

## [Unreleased]

- [Preserve whitespaces format of evaluation error in tooltip](https://github.com/BetterThanTomorrow/calva/issues/2623)

## [2.0.471] - 2024-09-12

- [Trim leading newlines from the result/error string before inline display](https://github.com/BetterThanTomorrow/calva/issues/2617)
Expand Down
74 changes: 72 additions & 2 deletions src/extension-test/integration/suite/annotations-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,6 @@ suite('Annotations suite', () => {
});

test('decorate result trims leading whitespaces', async function () {
testUtil.log(suite, 'activeEditor');

// any file would do
const testFilePath = path.join(testUtil.testDataDir, 'test.clj');
const editor = await testUtil.openFile(testFilePath);
Expand Down Expand Up @@ -63,4 +61,76 @@ suite('Annotations suite', () => {
await vscode.commands.executeCommand('workbench.action.closeActiveEditor');
testUtil.log(suite, 'test.clj closed');
});

test('tooltip contents of evaluated result', async function () {
// any file would do
const testFilePath = path.join(testUtil.testDataDir, 'test.clj');
const editor = await testUtil.openFile(testFilePath);

// Any range will do, the range below happens to be around "hover-map".
const selection = new vscode.Selection(2, 5, 2, 14);
editor.selection = selection;
const proxyEditor = testUtil.createVscTextEditorProxy(editor);

// will eventually call on the editor's `setDecorations` fn with the text to render.
const setDecorationsSpy = sinon.spy(proxyEditor, 'setDecorations');

const resultString = ' :Line1 with a leading space\n:Line2 some text\n\nLine4 the end.';

// SUCCESS case, format should contain the result in a clojure code block
{
annotations.decorateSelection(
resultString,
selection,
proxyEditor,
null,
annotations.AnnotationStatus.SUCCESS
);

//await testUtil.sleep(60000);

assert.deepStrictEqual(
setDecorationsSpy.firstCall.args[0],
annotations._getEvalSelectionDecorationTypes(annotations.AnnotationStatus.SUCCESS)
);
assert.deepStrictEqual(setDecorationsSpy.firstCall.args[1], []);
assert.deepStrictEqual(
setDecorationsSpy.secondCall.args[0],
annotations._getEvalSelectionDecorationTypes(annotations.AnnotationStatus.SUCCESS)
);
const decorateOpts = setDecorationsSpy.secondCall.args[1] as vscode.DecorationOptions[];
const hoverMessage = decorateOpts[0].hoverMessage as vscode.MarkdownString;
const expectedResultSuccess = `${annotations._getDecorateSelectionHeader(
resultString
)}\n\`\`\`clojure\n${resultString}\n\`\`\``;
assert.strictEqual(hoverMessage.value, expectedResultSuccess);
}

sinon.reset();

// ERROR case, should contain the result in a plain code block (```)
{
annotations.decorateSelection(
resultString,
selection,
proxyEditor,
null,
annotations.AnnotationStatus.ERROR
);

assert.deepStrictEqual(
setDecorationsSpy.firstCall.args[0],
annotations._getEvalSelectionDecorationTypes(annotations.AnnotationStatus.ERROR)
);
assert.deepStrictEqual(setDecorationsSpy.firstCall.args[1], []);
const decorateOpts = setDecorationsSpy.secondCall.args[1] as vscode.DecorationOptions[];
const hoverMessage = decorateOpts[0].hoverMessage as vscode.MarkdownString;
const expectedResultSuccess = `${annotations._getDecorateSelectionHeader(
resultString
)}\n\`\`\`\n${resultString}\n\`\`\``;
assert.strictEqual(hoverMessage.value, expectedResultSuccess);
}

await vscode.commands.executeCommand('workbench.action.closeActiveEditor');
});
});
58 changes: 49 additions & 9 deletions src/providers/annotations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ function setResultDecorations(editor: vscode.TextEditor, ranges) {
editor.setDecorations(evalResultsDecorationType, ranges);
}

function setSelectionDecorations(editor, ranges, status) {
function setSelectionDecorations(editor: vscode.TextEditor, ranges, status) {
const key = editor.document.uri + ':selectionDecorationRanges:' + status;
util.cljsLib.setStateValue(key, ranges);
editor.setDecorations(evalSelectionDecorationTypes[status], ranges);
Expand Down Expand Up @@ -93,6 +93,8 @@ function clearAllEvaluationDecorations() {
void vscode.commands.executeCommand('setContext', 'calva:hasInlineResults', false);
}

// Amongst other things, this function removes any leading whitespace
// from the RESULTSTRING displayed in the decoration.
function decorateResults(
resultString,
hasError,
Expand All @@ -114,6 +116,32 @@ function decorateResults(
void vscode.commands.executeCommand('setContext', 'calva:hasInlineResults', true);
}

// Returns a string of commands seperated by `|` to display in the
// results tooltip for the given RESULTSTRING.
//
// The commands are
//
// 1. Copy results to the clipboard.
// 2. Reveal the output destination.
function getDecorateSelectionCmdsString(resultString: string) {
const copyCommandUri = `command:calva.copyAnnotationHoverText?${encodeURIComponent(
JSON.stringify([{ text: resultString }])
)}`,
copyCommandMd = `[Copy](${copyCommandUri} "Copy results to the clipboard")`;
const openWindowCommandUri = `command:calva.showResultOutputDestination`,
openWindowCommandMd = `[Show Output](${openWindowCommandUri} "Reveal the output destination")`;

return `${copyCommandMd} | ${openWindowCommandMd}`;
}

// Amongst other things, this function generates the hover content for
// RESULTSTRING based on the STATUS value:
//
// - `ERROR`: Includes the commands header from `getDecorateSelectionCmdsString`, followed by RESULTSTRING
// wrapped in a Markdown plain code block preserving whitespaces.
//
// - `SUCCESS`: Includes the commands header from `getDecorateSelectionCmdsString`, followed by RESULTSTRING
// wrapped in a Markdown Clojure code block.
function decorateSelection(
resultString: string,
codeSelection: vscode.Selection,
Expand All @@ -130,17 +158,15 @@ function decorateSelection(
});
decoration['range'] = codeSelection;
if (status != AnnotationStatus.PENDING && status != AnnotationStatus.REPL_WINDOW) {
const copyCommandUri = `command:calva.copyAnnotationHoverText?${encodeURIComponent(
JSON.stringify([{ text: resultString }])
)}`,
copyCommandMd = `[Copy](${copyCommandUri} "Copy results to the clipboard")`;
const openWindowCommandUri = `command:calva.showResultOutputDestination`,
openWindowCommandMd = `[Show Output](${openWindowCommandUri} "Reveal the output destination")`;
const codeBlockLang = status == AnnotationStatus.ERROR ? '' : 'clojure';
const hoverMessage = new vscode.MarkdownString(
`${copyCommandMd} | ${openWindowCommandMd}\n` + '```clojure\n' + resultString + '\n```'
getDecorateSelectionCmdsString(resultString) +
`\n\`\`\`${codeBlockLang}\n` +
resultString +
'\n```'
);
hoverMessage.isTrusted = true;
decoration['hoverMessage'] = status == AnnotationStatus.ERROR ? resultString : hoverMessage;
decoration['hoverMessage'] = hoverMessage;
}
// for (let s = 0; s < evalSelectionDecorationTypes.length; s++) {
// setSelectionDecorations(editor, [], s);.
Expand All @@ -166,7 +192,21 @@ function onDidChangeTextDocument(event: vscode.TextDocumentChangeEvent) {
function copyHoverTextCommand(args: { [x: string]: string }) {
void vscode.env.clipboard.writeText(args['text']);
}

// ------------- EXPORT FOR UNIT TEST USE ONLY ----------------------------------

const _getDecorateSelectionHeader = getDecorateSelectionCmdsString;

/// retuns the selection decoration type of the given annotation STATUS.
function _getEvalSelectionDecorationTypes(status: AnnotationStatus) {
return evalSelectionDecorationTypes[status];
}

// ------------------------------------------------------------------------------

export default {
_getDecorateSelectionHeader,
_getEvalSelectionDecorationTypes,
AnnotationStatus,
clearEvaluationDecorations,
clearAllEvaluationDecorations,
Expand Down

0 comments on commit 9df9146

Please sign in to comment.