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.
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.
Related
While making VSCode Extension I have a requirement to show decorations on a file. Then while you hover over that decoration you can see the default hover with some information you want to show. I am using the following code to create the hover using MarkDownString for VSCode. Even after using "float:right;" in the span the view comment section won't move to the extreme right of the hover. It would just stay in the left. Can someone help me with the way to make it right aligned? Screenshot added below for reference.
const myContent = new MarkdownString(`<span style='float:right;'><a href='#'>View Comment</a></span>`);
myContent.isTrusted = true;
myContent.supportHtml = true;
const decoration = { range, hoverMessage:myContent };
Screenshot
I want the highlighted red box area to be in extreme right of the hover. [The image used is just for reference].
After trying the same thing, I found this question still unanswered.
The MarkdownString documentation states that:
When supportHtml is true, the markdown render will also allow a safe subset of html tags and attributes to be rendered. See https://github.com/microsoft/vscode/blob/6d2920473c6f13759c978dd89104c4270a83422d/src/vs/base/browser/markdownRenderer.ts#L296 for a list of all supported tags and attributes.
Looking at the code linked, we can see that while "span" is allowed the "style" and "class" attributes, they are very strictly filtered and only allow some of the vscode built-ins to be used.
So, while styling elements with inline CSS or even a custom class might be possible, there is another approach to this - using Markdown tables, which get translated into HTML tables and allow custom alignment.
For example, what I ended up using was something like:
new MarkdownString(`
| |
| ---: |
| the very long line we want the below link to right-align to |
| [Link text](https://linktarget "Link hover message") |
`)
The idea came from the github issue linked in the the source file mentioned above.
A couple of notes:
codicons are still supported inside Markdown tables;
the HTML table generated does not expand to 100% of the hover message box, so if you want to right-align the link text with a longer line, they have to be in the same Markdown table;
Markdown table detection is very picky about spaces and newlines, you might have to play a bit with the formatting of your string for vscode to correctly transform it into a HTML table;
the Markdown table header cannot be omitted, at least that was the conclusion of my testing; it can however be empty;
the resulting HTML table might add some small invisible borders, I haven't investigated, but my alignment with other rows in the hover seemed 1px off;
trying to bypass the Markdown table creation and writing my own HTML table broke codicons support, although I haven't investigated that too much either;
I want to add small straight line onto some desired characters/numbers inside a string inside textview. I couldn't find a solution. Maybe using NSMutableAttributedString. Meanwhile, I mean doing this programmatically. There is strikethrough style, but not overstrike style. Or maybe adding the letters "a" and "_" with different .baseline values. But how to add both characters onto each other then?
Is it possible?
EDIT: Due to make a try for the helpful answers below, I think to make the line at a spesific height is needed. "A\u{0305}" makes the up line very close to the character, as if it sticks. Is there a way to make it at specific height? For example, if we assume that all the keyboard-inputted characters are written inside every single boxes, the ceiling side of these boxes could be lined?
So this (note: see edit below) appears to be an "a tilde ogonek" (it's Lithuanian).
You can write it for instance as follows using these two Unicode characters:
let atildeogonek = "\u{0105}\u{0303}"
let title = "How to add a small straight line (I mean like this: \(atildeogonek)) onto a character inside a string?"
The first character is the a with an ogonek, the second one is the tilde.
EDIT: The initial question specifically asked about the character ą̃ ("a tilde ogonek") in the title, and I used this code to demonstrate how to use Unicode characters in a Swift string. After posting this answer, the question was edited to be more general about "a line above a character".
Programmatically, you could use a function like this:
func overline(character: Character) -> Character? {
return "\(character)\u{0305}".first
}
That will take a character as input and return a new character (glyph) that has had the Unicode combining overline character added to it. It will return nil if adding the combining overline character fails.
The code print(overline(character:"A")!), for example, returns "A̅"
Or, if you want to add an overline to every character in a string, you could use a function like this:
func overline(characters: String) -> [Character?] {
return Array(characters).map { return "\($0)\u{0305}".first
}
}
(I'm not sure if there are any characters for which the above will fail, so I'm not sure if force-unwrapping the result is safe. Thus I left the result of both functions to be optional Character/Array of Character.)
You can easily find the unicodes of ā or ą̃ by using the xcode's own Character Viewer. Just follow the following steps :
hit : Control + Command + SpaceBar
If you get a compact one like this, click the upper right corner icon to expand it.
When expanded, Click the settings gear in the corner . Select customize list.
select Enclosed Characters
Go down to the bottom and open Code tables then add Unicode.
Now, just search for your required Character and you can check its unicode value. here i am searching ā
to print unicode's value :
print("\u{0101}")
I have a text field which I need to style for example with bold or italics parts.
I tried overridding the TextEditingController's buildTextSpan and formatting the text using annotation ranges with custom styles but the edge cases were too much and I really couldn't get it to work.
So, thought about using a formatter where before every change in format I'll add a custom character, like this:
This text is |bBOLD and this is |iITALICS. Would get me this:
This text is BOLD and this is ITALICS. So I override the buildTextSpan to build the TextSpan from a parse function where I split the text by the special characters and check the initial letter of each text for formatting info.
This works well except for the fact that when I press the right arrow to go the next character after the "This text is ", the cursor will stay fixed as it thinks there are two characters but being only for formatting, they aren't there on the render.
Is there any way I could tell the textfield to ignore certain characters when selecting, moving selection or typing?
I think this would work!
static const kCharToBEIgnored = 0x2C;
// Here 0x2C means ',' comma
// For complete list visit https://api.flutter.dev/flutter/charcode/charcode-library.html
String get text {
return String.fromCharCodes(
_value.text.codeUnits.where((ch) => ch != kCharToBEIgnored),
);
}
I have a Table of Figures generated using PDFPTable like so.
--------------------------------------
|Caption|Figure Title | PP|
--------------------------------------
| fig 1 |title text | 2 |
--------------------------------|----|
| fig 2 | This is a longer title| |
| | text that wraps | 55 |
--------------------------------------
| fig N | another title | 89 |
--------------------------------------
I need to generate leader dots from the last line of text; it may have wrapped in the cell.
Here's a sample again showing the Figure 2 item of wrapped titled text and additionally having leader dots from the end of the text to the right side of the cell.
| fig 2 | This is a longer title| |
| | text that wraps.......| 55 |
This is what I want to achieve.
When I write the cell text I don't know where it will wrap and therefore I don't know what the last line of text will be for the purpose of measuring it, and if I do know about the last line of text I'm hard pressed to find the immediate x position following it.
So far, I've tried harnessing Cell Events and Table Events to write the leader dots after the fact. The two problems that have stopped me so far are:
I can't find the x position directly after the last line of wrapped text.
If I try the strategy of underlying dots beneath the entire last line of text (so I don't have to know where it stops in the x position. I do now the y position) the only canvas that allows the dots to appear is PdfPTable.TEXTCANVAS however it writes the leader dots on top of the existing text instead of beneath. I can give the text chunk a background color, so if some leader dots exist behind it they will not be visible (a poor man's crop).
I'm open to any strategy inside the context of the PDFPTable.
First things first: +1 for your question and the answer you provided yourself.
But...
Although your answer may work, there is a better way to achieve your goal. I've written a small sample called DottedLineLeader as an alternative that will be much easier to maintain. This example uses the DottedLineSeparator wrapped in a Chunk object.
Take a look at how such a chunk separator is used:
Chunk leader = new Chunk(new DottedLineSeparator());
Paragraph p;
p = new Paragraph("This is a longer title text that wraps");
p.add(leader);
When we add this Paragraph to a PdfPCell, we get the following effect:
The dots in the dotted line are not '.' characters. Instead it's an actual line (vector data) with a specific dash pattern. Using this approach instead of your own, will significantly reduce the number of lines in your code, use less CPU and result in cleaner PDFs.
Here's one solution that suffices the question requirements.
Each PdfPCell object has a .Column property that "Returns the list of composite elements of the column". Its property ColumnText.LastX returns "The X position after the last line that has been written". This is the position where we want the leader dots to start.
This work can be done in the PdfPTablEvent.TableLayout handler where all the cell positions are known.
class TofEvents : IPdfPTableEvent {
public void TableLayout(PdfPTable table, float[][] widths, float[] heights, int headerRows, int rowStart, PdfContentByte[] canvases)
{
// do the work here
}
}
Because we know where the last line of the text ends on the page, and where the right side the cell is, we can fill that space with dots.
General calculation for creating the proper number of dots for a particular cell is:
// You'll have to get references to things you need from the handler method args -
float ptXCellLeft = GetLeftSideOfCellFromIncomingWidthsArgument();
PdfPCell cell = GetCurrentCellFromIncomingCellsArgument();
// the math -
Font f = getTheFontToUse(); // for measuring the text size in this font
float leaderDotSymbolWidth = f.BaseFont.GetWidthPoint(".", f.Size);
float leaderDotsWidth = cell.Width - (cell.Column.LastX - ptXCellLeft);
string strLeaderDotsFillText = ".".Repeat(Convert.ToInt32(leaderDotsWidth / leaderDotSymbolWidth));
The resulting strLeaderDotsFillText should fit nicely into the last line's space.
I have text files which contain code inside an Editor. The user can run an analysis on a certain part of his code, which will result in a set of lines which should be hidden. Next I want to present the user with only the remaining lines, but with correct linenumbers, as from the original document. Possible solutions I thought of:
Open a new Editor which does not contain the hidden lines, but *somehow* still has correct line numbers
Hide the lines in the original editor, and offer a button for the user to 'unhide'. Probably a similar solution required as in 1.
I don't really know how to go about this. Folds would be a weird solution, because they can be unfolded individually, and seem to be more semantically tied to things like methods or classes. Also, simply creating a new document without the hidden lines results in wrong linenumbers.
Use a ProjectionViewer and reflection to invoke the private method ProjectionViewer.collapse(int offset int length). This method is only used internally to hide a certain portion of the text, by manipulating the ProjectionDocument (see http://eclipse.org/articles/Article-Folding-in-Eclipse-Text-Editors/folding.html).
After this, folding text in the editor using the annotations(the little +/- icons) WILL break everything, so this solution and regular folding are mutually exclusive.