-
Notifications
You must be signed in to change notification settings - Fork 29.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support dynamic line heights using decorations #194609
Support dynamic line heights using decorations #194609
Conversation
Nice work so far! I didn't take a very close look, but keep in mind that if no line heights are set, there shouldn't be any performance hit by this feature. |
This limits the maximum line height to 255, which seems sufficient.
I created another fun little test case: const model = monaco.editor.createModel(`# Coming soon
## to VSCode
### (and Monaco editor)
#### Variable line heights
##### Allowing for fancy stuff
###### Such as bigger markdown headers
And this is regular text`, 'markdown');
// Hover on each property to see its docs!
const ed = monaco.editor.create(document.getElementById("container"), {
model,
automaticLayout: true,
});
var decorations = ed.createDecorationsCollection([
{
range: new monaco.Range(1, 1, 1, Infinity),
options: { lineHeight: 50, inlineClassName: "m50" },
},
{
range: new monaco.Range(3, 1, 3, Infinity),
options: { lineHeight: 45, inlineClassName: "m45" },
},
{
range: new monaco.Range(5, 1, 5, Infinity),
options: { lineHeight: 40, inlineClassName: "m40" },
},
{
range: new monaco.Range(7, 1, 7, Infinity),
options: { lineHeight: 35, inlineClassName: "m35" },
},
{
range: new monaco.Range(9, 1, 9, Infinity),
options: { lineHeight: 30, inlineClassName: "m30" },
},
{
range: new monaco.Range(11, 1, 11, Infinity),
options: { lineHeight: 25, inlineClassName: "m25" },
},
]); .m50 { font-size: 50px; }
.m45 { font-size: 45px; }
.m40 { font-size: 40px; }
.m35 { font-size: 35px; }
.m30 { font-size: 30px; }
.m25 { font-size: 25px; } |
As far as I know everything works now. Tests are still missing (old ones commented out). I would like to fix that once it’s confirmed the rest looks good. |
This applies to selected text, search highlight, and same word highlight, and other forms of highlighting.
I think the minimap should also reflect the line height. |
@@ -699,6 +705,7 @@ export class LinesLayout { | |||
break; | |||
} | |||
} | |||
linesOffsets[lineNumber - startLineNumber] = currentLineRelativeOffset; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I also don't understand this line here. Was this a bug before?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sometimes I need the top offset of the next line requested. So I need the line offsets of all lines in the view, plus one the next line.
@@ -46,6 +48,7 @@ export class ViewModelDecorations implements IDisposable { | |||
this._decorationsCache = Object.create(null); | |||
this._cachedModelDecorationsResolver = null; | |||
this._cachedModelDecorationsResolverViewRange = null; | |||
this._lineHeight = configuration.options.get(EditorOption.lineHeight); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We have to react on when the line height is changed through options.
Thank you for the PR, nice job! Generally, this looks quite good! Just the actual computation in Can you look into cursor height and try different line heights in various features of vscode? Like the diff editor? How broken is the VS Code experience when some lines have a different height than others? |
I created the Re minimap: I’m personally not a fan of the minimap. I’m not sure how it should behave, so I’ll take your word for it. I would need to look into that. Some feedback I for from my client is that I still need to look into line wrapping if a non-monospace font is used. I haven’t looked into that yet. This could mean I need to make changes, or that they need to leverage an existing Monaco setting Some other feedback is that they would like to make the line height smaller. So essentially they want support for #66468. The actual implementation for that issue could be an extension. My biggest problem with that is that I don’t know how to deal with decorations and line numbers. |
Re diff editor: It’s not terrible, not not great eiter. Both editors look good invididually, but they aren’t properly aligned when decorations are applied. I also haven’t implemented the interface for extensions yet, but that shouldn’t be too hard. I think they need 2 additional properties: If it’s ok, I would also like to add the |
var jsCode = Such as bigger markdown headers And this is regular text`'markdown'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
signed Apetree100122
return this._decorationsHeightMapCache; | ||
} | ||
|
||
public getDecorationsOffset(lineNumber: number = this._linesCollection.getViewLineCount()): number { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lineNumber: number = this._linesCollection.getViewLineCount()
I think this should be = this._linesCollection.getViewLineCount() + 1
.
I'm currently refactoring this a bit.
@@ -507,7 +509,7 @@ export class LinesLayout { | |||
public getVerticalOffsetAfterLineNumber(lineNumber: number, includeViewZones = false): number { | |||
this._checkPendingChanges(); | |||
lineNumber = lineNumber | 0; | |||
const previousLinesHeight = this._lineHeight * lineNumber; | |||
const previousLinesHeight = this._decorations.getDecorationsOffset(lineNumber); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm pretty sure this should be:
const previousLinesHeight = this._decorations.getDecorationsOffset(lineNumber + 1);
const lineCount = this._linesCollection.getViewLineCount(); | ||
const lineHeights = new Uint8ClampedArray(lineCount + 1).fill(this._lineHeight); | ||
const viewRange = new Range(1, this._linesCollection.getViewLineMinColumn(0), lineCount, this._linesCollection.getViewLineMaxColumn(lineCount)); | ||
const modelDecorations = this._linesCollection.getDecorationsInRange(viewRange, this.editorId, true, false, false); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is not good, I just noticed that viewRange
is the entire document range.
This means that setting a decoration flushes everything here and causes querying all decorations.
Is there any plan to merge this code? Really looking forward to such exciting feature. |
This contains the parts of #194609 that we can already merge. While it does not implement dynamic line heights, it is a first step in that direction. Co-authored-by: Remco Haszing <remcohaszing@gmail.com>
I extracted the parts that we can take in #207160. |
This contains the parts of #194609 that we can already merge. While it does not implement dynamic line heights, it is a first step in that direction. Co-authored-by: Remco Haszing <remcohaszing@gmail.com>
This adds support for dynamic line heights using decorations in Monaco editor. This is done by adding the
lineHeight
property toIModelDecorationOptions
. This property represents the line height of the decoration all lines it touches. The line height can only be increased, not decreased.For testing, I used the following JavaScript and CSS in the Monaco playground:
Since text might now not fill the entire line height, I chose to align the text at the bottom of the line. This matches default behaviour of typical document processors such as LibreOffice Writer and Google Docs.
The following screenshot shows that the following works:
The following screenshot shows matching brackets are aligned correctly.
The following shows that text selection works. It also shows that the height of the selection indicator is adjusted to the editor’s line height, not that of the decorator. This is different from for example how LibreOffice does it. The same applies to other types of highlights, such as matching words and search.
Text selection in LibreOffice
Things that still need to be done:
cc @hediet
Closes #147067