-
Notifications
You must be signed in to change notification settings - Fork 46
Adding line numbers in editor #940
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
base: main
Are you sure you want to change the base?
Adding line numbers in editor #940
Conversation
|
I have removed the scroll bar from line numbers. Working on long lines issue. |
I went through the discussion, implementing long lines thing is a bit complex. Currently I am trying to do something similar to this article. |
The canvas-based approaches look pretty promising but potentially slow on larger text files. Please consider some form of memoization if you're going to do this. |
|
prism-react-editor uses prismjs , works pretty well but is dependency heavy. |
|
Aside note: With my proof of concept, there were versions and updates. Make sure you're testing the latest version, not a previous one please. Some of the CSS changed to fix wrapping and line calculation, where it mostly worked in earlier versions, it's closer to (or exactly as, at least with what I tested) what is expected. |
|
For now, I do have a solution which implements horizontal scrolling instead of line-wrapping. Recording.2025-02-18.234242.mp4 |
We might even want to make it toggleable. In most cases, soft wrapping is the right approach. I would like to look at this again when I have time to do so. Right now, I do not have the time to do so. I don't know when that would be, but it's not right this moment. Apologies! Thanks for looking into this and trying to find a solution! Having a PR to work in is fantastic! My demo seemed to be working outside of Cockpit, and there's the whole issue where something works in vitro but not in vivo. (That is, borrowing from science: something may work in an isolated area, like a test tube, but doesn't work quite the same when inside a body. Same for Cockpit, as there are a lot more things going on within Cockpit already and also with PatternFly than some simplified test area.) |
|
I have taken a look at the PR and the line wrapping doesn't work as @garrett's demo code wasn't ported to this PR. Did you have issues integrating it? I have taken a look and it doesn't seem super hard to create something with a canvas approach, we do need to work on optimization it. At least made some notes for myself. The required code up front to create a canvas to use for const textarea = document.querySelector('#editor-text-area')
const styles = window.getComputedStyle(textarea, null)
const parseValue = (v) => v.endsWith('px') ? parseInt(v.slice(0, -2), 10) : 0;
const textareaStyles = window.getComputedStyle(textarea);
const paddingLeft = parseValue(textareaStyles.paddingLeft);
const paddingRight = parseValue(textareaStyles.paddingRight);
const textareaWidth = textarea.getBoundingClientRect().width - paddingLeft - paddingRight;
const font_size = textareaStyles.getPropertyValue('font-size');
const font_family = textareaStyles.getPropertyValue('font-family');
const font = `${font_size} ${font_family}`;
const canvas = document.createElement('canvas');
const context = canvas.getContext('2d');
context.font = font;Also for reference take a look at this github example. |
|
Some things for testing as a canvas can have a performance impact:
|
I am testing code changes locally but haven't pushed them here. |
c6f7f51 to
e8ae79f
Compare
I have tried implementing the canvas approach. It still breaks though. 20250223-1924-55.4817904.mp4 |
|
Here is a demo of pasting text. Recording.2025-02-24.010501.mp4Recording.2025-02-24.010649.mp4 |
|
I have some how messed up |
jelly
left a comment
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.
Progress looks good! There is an issue with the calculation of the textarea size which causes the "weird bugs" you see when resizing the textarea.
| const displayLineNumbers = () => { | ||
| const lineNumbers = calculateLineNumbers(); | ||
| lineNumbersEle.innerHTML = lineNumbers | ||
| .map((num) => `<div>${num === 0 ? " " : num}</div>`) |
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.
Like @garrett's example we should use a CSS property for the number of lines and use that with calc() instead of adding more html elements.
| }); | ||
|
|
||
| const resizeObserver = new ResizeObserver(() => { | ||
| lineNumbersEle.style.height = `${textarea.getBoundingClientRect().height}px`; |
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 should be done in layout, I don't understand why this is needed?
| (lineNumbersEle.style as any)[property] = textareaStyles[property]; | ||
| } | ||
| }); | ||
| }; |
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 should be done once, and saved in state and changed on resize. paddingTop/paddingBottom should not be interesting for us.
|
|
||
| const paddingLeft = parseValue(textareaStyles.paddingLeft); | ||
| const paddingRight = parseValue(textareaStyles.paddingRight); | ||
| const textareaWidth = textarea.getBoundingClientRect().width - paddingLeft - paddingRight; |
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 called every input now and is rather expensive, needs to be put into state and only get called onResize and initially.
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 did some further digging and I found out why you have bugs, this width is wrong as it doesn't account for the scrollbar and this is why there are line number issues.
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.
Instead of textarea.getBoundingClientRect().width I tried using textarea.clientWidth , clientWidth excludes scrollbar width. The problem still persists.
|
|
||
| words.forEach((word) => { | ||
| const wordWidth = context.measureText(word + " ").width; | ||
| const lineWidth = context.measureText(currentLine).width; |
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.
it feels like we can optimize this away and just add a new variable let lineWidth = 0 and keep appending to that.
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.
Should we use characterWidth instead of wordWidth? I think it will provide more accurate line wrapping.



#916



I have done a basic implementation for displaying line numbers in the editor. Currently I have tested it with resizing my browser window