My team @ FAANG is using a prose mirror based text editor (TipTap) to implement a new product. We love all the features this editor provides OOB. Even for features / capabilities not provided via TipTap API, ProseMirror provides excellent support to manually implement them. Thanks for keeping this library awesome!
Problem
One feature that both ProseMirror and TipTap (by consequence) lacks is the ability to show line numbers on the document.
North Star
We would love to implement this on a similar way to what Quip web currently does. This is, adjust the gap in between line numbers dynamically depending on the content per line. (e.g. if we have a headline 1, then there will be a bigger gap w.r.t paragraphs, if we insert an image, we will have a gap as big as the image is, the same for code blocks etc.)
I know this question has been asked multiple times with Prose Mirror core maintainers answering that this feature is out of scope for PM. However, here is my long shot:
At high level: What would it take to implement this feature considering our north star?
Is this nearly impossible to implement with a Prose Mirror based editor? If so, any alternatives that could help us achieving our goal? (e.g. rich text editor that provides most common capabilities this is: headings, tables, formatting, etc. That also supports line numbers.)
If above north star is somewhat doable, any code pointers, recommendations, high-level approach to solve this? I can even ask my company if there is a way so that we can collaborate for this work-stream with this awesome open source community. I bet there is a bunch of people interested on onboarding this feature as part of their PM instances.
Note: Our thinking is that only if ProseMirror would allow us to get the content line by line, explore it’s content, then we might have solved 75% of the problem via this algorithm. I know PM has a tree structure rather than a line structure though, so that’s why we’re asking for high level approaches here.
I have no idea what line numbers in a structured text document would even really mean. It may be easier to start from a code editor (say CodeMirror) if a line-based document format is what you need.
Happy to provide more context, the TLDR; is that it
would mean render a line number per paragraph, headline, image, table or code block as you would imagine. In this context it would be more like an “element number” acting as a line number rather than a true line number since it might be misleading when having a code block for example. In order to support this capability, we might need to know the element’s boundaries (e.g. height, so that we now where to render the next element number).
We do have a proof of concept working for this that works almost nicely for text only. However we do want to expand logic to handle images / tables and code blocks.
Do you have any high level suggestion / thoughts on this matter? Basically we’d love to understand whether this in fact is something not feasible so that we flag and plan accordingly.
I think that’s doable if I understood it correctly. Will take some work though. You need to map out first what nodes should contain line numbers, probably at the start every block node at depth 0 level first. Then, add exceptions for at least lists if you want list_items to have line numbers as well. Not sure why exactly you need the line number gap to be dynamic but you could use NodeViews or just just plain attributes. You should also have a robust method of syncing the line numbers & their gaps incase something weird happens.
Not sure why exactly you need the line number gap to be dynamic but you could use NodeViews or just just plain attributes
Just to be very clear. This is something very similar to what we’re looking for. As you can see the gaps for “line elements” adjust dynamically depending on the content for the “line”. Does that make sense now?
You need to map out first what nodes should contain line numbers, probably at the start every block node at depth 0 level first.
I love the idea. I’m assuming that exploring nodes at depth = 0 would somewhat give us the all the nodes “per line” so to say. Is that correct? If so, do you mind elaborating a bit more on which specific Prose Mirror APIs / primitives / functions might be helpful to retrieve such nodes such that depth = 0?.
Oh I see. Yeah that seems doable. For the block nodes at depth = 0, just use tr.doc.descendants() and return false every time you find a block node you want to put line number to. I guess depth = 0 is a bit misleading as if you wrap block nodes and want to apply the line number to the child instead, eg using section blocks, you’ll just resolve to whatever depth is necessary. But I’m sure you’ll figure it out, good luck.