Reputation: 1113
My Question: Is there a way to write an extension that changes what vscode displays without changing the underlying code? Vscode seems to have a ton of different types of extensions and I am having a hard time finding where to start.
The Context: I want to try writing a vscode extension I have had an idea for for a while. (If it already exists, let me know.)
The "tab" character in ASCII is actually a "Horizontal Tabulation" key. It was originally meant for making tables in conjunction with "Vertical Tabulation." Your printer/terminal would have a column and row stop point that the HT and VT characters could advance to. It would be kinda cool to resurrect the original purpose of the tab key. In other words, code written like so:
On the disk:
#␉Comment␉Here␉for␉Columns␊
thing =␉"howdy",␉"doody",␉"mein froind",␉"!"␊
␉" I love",␉"what you've",␉"done with",␉"the place";␊
What's displayed (vertical line would be partly transparent):
# | Comment | Here | for | Columns
thing = | "howdy", | "doody", | "mein froind", | "!"
| " I love", | "what you've", | "done with", | "the place";
So, tabs could be aligned magically by looking at subsequent lines and attempting to align anything that follows a horizontal tab character. Tab would no longer represent a column of width 8 or 4, but be flexible and align with the previous and following lines of code.
This would mean you don't need to manually align anything. You could also have it so overflows of your max line length would auto-wrap and auto-align tabs. I would probably avoid using the vertical tab character, as most code interpreters might not be able to ignore it properly. Most should ignore the regular horizontal tab, though.
So, what type of extension would this be? How do I display code different from what it is on the disk? Thanks ahead of time.
Upvotes: 4
Views: 718
Reputation: 1113
I found a hack-ish way to do it. Not ideal, as rendering is choppy.
Create a decorator-type extension. When defining the decoration type, set the letter spacing (and opacity in the case of text) to basically make the content of the match invisible and space-less
const tabDecorationType = vscode.window.createTextEditorDecorationType({
letterSpacing: '-1em',
opacity: '0'
});
When setting the decorations later on, have your DecorationOptions object set the text before and after to essentially give your decoration the new text
const regEx = /\t/g;
const text = activeEditor.document.getText();
const tabs: vscode.DecorationOptions[] = [];
let match;
while (match = regEx.exec(text)) {
const startPos = activeEditor.document.positionAt(match.index);
const endPos = activeEditor.document.positionAt(match.index + 1);
const decoration: vscode.DecorationOptions = {
range: new vscode.Range(startPos, endPos),
renderOptions: {
after: {contentText: "| "},
before: {contentText: " "}, // <-- replace with correct number of spaces
}
};
tabs.push(decoration);
}
activeEditor.setDecorations(tabDecorationType, tabs);
And you essentially have replaced text. (It would take some more scanning to get the correct number of spaces for my desired implementation, but that's not really a part of the question.) This implementation is not super ideal, as it takes a second for the decorations to render and update. This makes code augmentations a little ugly when they are key to the formatting of the document.
Update Note: Descriptors seem to be picky with whitespace. They will remove all but one space before and after the descriptor and remove any new line characters. This means you have to put some character like '_' in and make the descriptor text invisible with 'color' to get a bunch of whitespace and you can't really get a newline... even more hack-ish and less ideal.
Upvotes: 2