I'm trying to apply a decoration on words in vscode text that matches some specific words.
const document = activeEditor.document;
const decoration = window.createTextEditorDecorationType({
textDecoration: 'underline wavy #0000ff'
});
let ranges = [];
for (let word of words) {
let matches = [...document.getText().matchAll(new RegExp(word, 'g'))];
if (matches.length === 0) continue;
for (let match of matches) {
let startPos = document.positionAt(match.index as number);
let endPos = document.positionAt(match.index as number + match[0].length);
ranges.push({
range: new Range(startPos, endPos),
});
}
}
activeEditor.setDecorations(decoration, ranges);
/* listeners when the text changes retriggers the code etc*/
Regex is correct and also the range of the curr words pos.
When I apply the styles vscode makes a mess, actually it does apply them on matched word but also on all the following ones. If I delete the words the decoration persist (IDK why) in the point where the word were (like if I write anything else in the point the new text gets the previous decoration).
Following vscode docs the decorations should update automatically when the ranges change btw is not.
There is an issue in the code, related on how you create the decoration
. You must create only once, no matter how many times you use it. So, you could create it right after the extension initialization and use it latter.
Also, the phrase "Following vscode docs the decorations should update automatically when the ranges change btw is not.", is not quite accurate. Some updates are indeed automatic, but most of them, no. The safest approach is you take care of text changes and fire the decoration again.
An updated, runnable code, is bellow.
export function activate(context: vscode.ExtensionContext) {
// declare a timer to delay the decoration update
let timeout: NodeJS.Timer;
// creates the decoration only once
const decoration = vscode.window.createTextEditorDecorationType({
textDecoration: 'underline wavy #0000ff'
});
triggerUpdateDecorations();
// whenever the text changes, update the decorators
vscode.workspace.onDidChangeTextDocument(event => {
if (vscode.window.activeTextEditor && event.document === vscode.window.activeTextEditor.document) {
updateDecorations();
}
}, null, context.subscriptions);
// basically your original source, without the createDecoration piece
function updateDecorations() {
if (!vscode.window.activeTextEditor) return;
const document = vscode.window.activeTextEditor.document;
const ranges: vscode.Range[] = [];
// let words = ["bola", "coisa"];
for (let word of words) {
let matches = [...document.getText().matchAll(new RegExp(word, 'g'))];
if (matches.length === 0) continue;
for (let match of matches) {
let startPos = document.positionAt(match.index as number);
let endPos = document.positionAt(match.index as number + match[0].length);
ranges.push(
new vscode.Range(startPos, endPos),
);
}
}
vscode.window.activeTextEditor.setDecorations(decoration, ranges);
}
// fire decoration update using a small delay
function triggerUpdateDecorations() {
if (timeout) {
clearTimeout(timeout);
}
timeout = setTimeout(updateDecorations, 100);
}
}
Hope this helps