Skip to content

Commit

Permalink
Code Line Numbers Highlighting (#216)
Browse files Browse the repository at this point in the history
* Add option documentation

* Add editor unit tests

* Add code highlighting feature

* Add release note

* Add CSS classes

* Documentation tweaks

* Polish release notes...

* More tweaks
  • Loading branch information
coatless authored Jun 18, 2024
1 parent 9f05fb8 commit 93d42d9
Show file tree
Hide file tree
Showing 6 changed files with 458 additions and 19 deletions.
58 changes: 57 additions & 1 deletion _extensions/webr/qwebr-monaco-editor-element.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
// Global array to store Monaco Editor instances
globalThis.qwebrEditorInstances = [];

function isValidCodeLineNumbers(stringCodeLineNumbers) {
// Regular expression to match valid input strings
const regex = /^(\d+(-\d+)?)(,\d+(-\d+)?)*$/;
return regex.test(stringCodeLineNumbers);
}

// Function that builds and registers a Monaco Editor instance
globalThis.qwebrCreateMonacoEditorInstance = function (cellData) {

Expand Down Expand Up @@ -54,7 +60,7 @@ globalThis.qwebrCreateMonacoEditorInstance = function (cellData) {
const model = editor.getModel();
// Set EOL for the model
model.setEOL(monaco.editor.EndOfLineSequence.LF);

// Dynamically modify the height of the editor window if new lines are added.
let ignoreEvent = false;
const updateHeight = () => {
Expand All @@ -80,6 +86,56 @@ globalThis.qwebrCreateMonacoEditorInstance = function (cellData) {
}
};

// Function to generate decorations to highlight lines
// in the editor based on input string.
function decoratorHighlightLines(codeLineNumbers) {
// Store the lines to be lighlight
let linesToHighlight = [];

// Parse the codeLineNumbers string to get the line numbers to highlight
// First, split the string by commas
codeLineNumbers.split(',').forEach(part => {
// Check if we have a range of lines
if (part.includes('-')) {
// Handle range of lines (e.g., "6-8")
const [start, end] = part.split('-').map(Number);
for (let i = start; i <= end; i++) {
linesToHighlight.push(i);
}
} else {
// Handle single line (e.g., "7")
linesToHighlight.push(Number(part));
}
});

// Create monaco decorations for the lines to highlight
const decorations = linesToHighlight.map(lineNumber => ({
range: new monaco.Range(lineNumber, 1, lineNumber, 1),
options: {
isWholeLine: true,
className: 'qwebr-editor-highlight-line'
}
}));

// Return decorations to be applied to the editor
return decorations;
}

// Ensure that the editor-code-line-numbers option is set and valid
// then apply styling
if (qwebrOptions['editor-code-line-numbers']) {
// Remove all whitespace from the string
const codeLineNumbers = qwebrOptions['editor-code-line-numbers'].replace(/\s/g,'');
// Check if the string is valid for line numbers, e.g., "1,3-5,7"
if (isValidCodeLineNumbers(codeLineNumbers)) {
// Apply the decorations to the editor
editor.createDecorationsCollection(decoratorHighlightLines(codeLineNumbers));
} else {
// Warn the user that the input is invalid
console.warn(`Invalid "editor-code-line-numbers" value in code cell ${qwebrOptions['label']}: ${codeLineNumbers}`);
}
}

// Helper function to check if selected text is empty
function isEmptyCodeText(selectedCodeText) {
return (selectedCodeText === null || selectedCodeText === undefined || selectedCodeText === "");
Expand Down
9 changes: 9 additions & 0 deletions _extensions/webr/qwebr-styling.css
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,15 @@ body.quarto-dark .qwebr-button:hover {
color: #696969;
}

/* Style the code highlight lines */
body.quarto-light .qwebr-editor-highlight-line {
background-color: lightblue;
}

body.quarto-dark .qwebr-editor-highlight-line {
background-color: darkblue;
}

/* Style the modal pop-up */

/* The Modal (background) */
Expand Down
Loading

0 comments on commit 93d42d9

Please sign in to comment.