Make it possible to style entire blocks of lines #1157

Closed
opened 2013-01-14 18:21:45 +01:00 by marijnh · 4 comments
marijnh commented 2013-01-14 18:21:45 +01:00 (Migrated from gitlab.com)

Right now, it's not possible (afaik) to style an entire line (or multiple lines) for block-level highlighting sections. For example, in GFM mode, there's no way to add a background that extends to the edges of the editor behind the code block (to set it part from the rest of the code).

Although for many languages embedded into GFM mode, especially smaller code blocks, there isn't much confusion, when Markdown (or HTML) or a very long block of code is embedded, it can be hard to tell the difference between the code block, and the actual code.

Here's what I'd like to be able to do (notice the gray background behind the code block):

Example document with background behind entire line.

Possible solutions

Idea 1 (preferred)

Extend the last character's style to the edge of the editor, either by adding an empty element after the last character, or adjusting the size of the last character's wrapper accordingly. This makes it possible to have multiple levels of block-level styles. Consider the following example:

- foo

        bar

The list item could have a background that spanned the entire width of line 1 & 2. Then, for line 3, the list background would continue to the word bar, where the background for code would start and continue to the end of the line. Personally, this would be ideal.

The only issue that comes to mind for this solution is a possible performance hit due to recalculating the width of the background every time a character is typed. One workaround for this would be an overflow:hidden; hack of some sort. Another workaround would be to only extend the styles to the end of the line if one of the classes listed started (or ended) with block-. Then, only the modes that actually used it, would have to deal with it.

Idea 2

Make it possible to add a class to the pre that wraps the spans during the highlighting phase. Or add another block-level wrapper inside the pre to add the class to. This could be added as blockToken.

The downside of this solution is it only supports one level of block-level code. For example, a code block inside of a list would only have the list's class listed. Adding the class for each would break for code within a blockquote (> would be highlighted as code as well, when it shouldn't be). But, this solution could always be tweaked for each mode to make it work (better than no block-level styles at all).

Why I believe the functionality should be built into the core highlighting code

Every mode I've dealt with has had a block-level specific function and inline-level specific function. Many times, there's been more than one for each. However, few add a background to the block-level styles because it's not easy to read (or they don't think it looks good). Additionally, this should be rather easy to integrate into modes that have already been written, without having to add much more code (for the most part, it should just be rearranging things a bit).

Right now, it's not possible (afaik) to style an entire line (or multiple lines) for block-level highlighting sections. For example, in [GFM mode](http://codemirror.net/mode/gfm/index.html), there's no way to add a background that extends to the edges of the editor behind the code block (to set it part from the rest of the code). Although for many languages embedded into GFM mode, especially smaller code blocks, there isn't much confusion, when Markdown (or HTML) or a very long block of code is embedded, it can be hard to tell the difference between the code block, and the actual code. Here's what I'd like to be able to do (notice the gray background behind the code block): ![Example document with background behind entire line.](https://f.cloud.github.com/assets/1123348/65201/754768e8-5e6e-11e2-8ff0-1718edc02344.png) ## Possible solutions ### Idea 1 (preferred) Extend the last character's style to the edge of the editor, either by adding an empty element after the last character, or adjusting the size of the last character's wrapper accordingly. This makes it possible to have multiple levels of block-level styles. Consider the following example: ``` - foo bar ``` The list item could have a background that spanned the entire width of line 1 & 2. Then, for line 3, the list background would continue _to_ the word `bar`, where the background for code would start and continue to the end of the line. Personally, this would be ideal. The only issue that comes to mind for this solution is a possible performance hit due to recalculating the width of the background every time a character is typed. One workaround for this would be an `overflow:hidden;` hack of some sort. Another workaround would be to only extend the styles to the end of the line if one of the classes listed started (or ended) with `block-`. Then, only the modes that actually used it, would have to deal with it. ### Idea 2 Make it possible to add a class to the `pre` that wraps the `span`s during the highlighting phase. Or add another block-level wrapper inside the `pre` to add the class to. This could be added as `blockToken`. The downside of this solution is it only supports one level of block-level code. For example, a code block inside of a list would only have the list's class listed. Adding the class for each would break for code within a blockquote (`>` would be highlighted as code as well, when it shouldn't be). But, this solution could always be tweaked for each mode to make it work (better than no block-level styles at all). ## Why I believe the functionality should be built into the core highlighting code Every mode I've dealt with has had a block-level specific function and inline-level specific function. Many times, there's been more than one for each. However, few add a background to the block-level styles because it's not easy to read (or they don't think it looks good). Additionally, this should be rather easy to integrate into modes that have already been written, without having to add much more code (for the most part, it should just be rearranging things a bit).
marijnh commented 2013-01-15 10:48:48 +01:00 (Migrated from gitlab.com)

I might accept something that automatically promotes a certain type of token styles (say block-...) to be applied to the line wrapper DIV instead of the token's SPAN.

The thing with automatically continuing the style of the end token of a line is probably out. There's simply no elegant way to model it in HTML/CSS without, as you mention, a lot of expensive manual positioning and gratuitous element creation. This would be a tax that would have to be paid for all lines, not just the ones that use the feature, since CodeMirror wouldn't be able to easily tell whether a style has a background. Also, backgrounds for tokens are problematic in general because they'll obscure the selection and cursor.

I might accept something that automatically promotes a certain type of token styles (say `block-...`) to be applied to the line wrapper DIV instead of the token's SPAN. The thing with automatically continuing the style of the end token of a line is probably out. There's simply no elegant way to model it in HTML/CSS without, as you mention, a lot of expensive manual positioning and gratuitous element creation. This would be a tax that would have to be paid for _all_ lines, not just the ones that use the feature, since CodeMirror wouldn't be able to easily tell whether a style has a background. Also, backgrounds for tokens are problematic in general because they'll obscure the selection and cursor.
marijnh commented 2013-01-15 18:27:57 +01:00 (Migrated from gitlab.com)

Just some notes in regards to my personal testing:

  • Adding a background to a <span> will cover text that extends too high/low (eg, the bottom of the letter g), unless a large enough line-height is specified (1.3 should cover most characters/fonts).
  • A <span> can be added to the end of each line with display:inline-block;width:100%; and the final character's class to achieve the wanted affect, without a negative impact to performance (not noticeable, anyway). However, to disable scrolling (scrollbar doesn't appear, but scrolling can happen), overflow:hidden; must be set on each <pre>.
    • The issue with this is the height of inline-block elements doesn't match the height of inline elements. One approach would be to add n number of spaces, to extend the background to the end of the line, but when lineWrapping is not turned on, this would result in an outrageous number of spaces being added (length of longest line * # of lines, assuming monospace font).

      Another solution would be to manually set the height of each <span> (for nested block-level highlighting, with different font sizes). This is calculated when measuring already, so maybe piggyback off of that? That is, set the height of every <span> to the height of the tallest <span> on that line.

  • As mentioned by Marijn, the cursor and selection is hidden by a background behind text, so this would have to be worked around as well.

Will look into this more later to see if I can come up with anything. (And if I get hit by a truck, someone can start out from where I left off.)

Just some notes in regards to my personal testing: - Adding a background to a `<span>` will cover text that extends too high/low (eg, the bottom of the letter `g`), unless a large enough `line-height` is specified (`1.3` should cover most characters/fonts). - A `<span>` can be added to the end of each line with `display:inline-block;width:100%;` and the final character's class to achieve the wanted affect, without a negative impact to performance (not noticeable, anyway). However, to disable scrolling (scrollbar doesn't appear, but scrolling can happen), `overflow:hidden;` must be set on each `<pre>`. - The issue with this is the height of `inline-block` elements doesn't match the height of `inline` elements. One approach would be to add `n` number of spaces, to extend the background to the end of the line, but when `lineWrapping` is not turned on, this would result in an outrageous number of spaces being added (length of longest line \* # of lines, assuming monospace font). Another solution would be to manually set the `height` of each `<span>` (for nested block-level highlighting, with different font sizes). This is calculated when measuring already, so maybe piggyback off of that? That is, set the height of every `<span>` to the height of the tallest `<span>` on that line. - As mentioned by Marijn, the cursor and selection is hidden by a background behind text, so this would have to be worked around as well. Will look into this more later to see if I can come up with anything. (And if I get hit by a truck, someone can start out from where I left off.)
marijnh commented 2013-10-17 11:47:59 +02:00 (Migrated from gitlab.com)

Patch e0b0e32ed9 implements something similar to this. Testing welcome.

Patch e0b0e32ed97bdd9b4dcb559f0d383bbb197961e4 implements something similar to this. Testing welcome.
marijnh (Migrated from gitlab.com) closed this issue 2013-10-17 11:48:00 +02:00
marijnh commented 2020-05-23 22:38:41 +02:00 (Migrated from gitlab.com)

So how can I enable to add a class name in markdown code block so that I can highlight this.

So how can I enable to add a class name in markdown code block so that I can highlight this.
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
codemirror/codemirror5#1157
No description provided.