middleman-syntax icon indicating copy to clipboard operation
middleman-syntax copied to clipboard

Use format string for CSS class

Open Arcovion opened this issue 9 years ago • 13 comments

Currently the chosen CSS class is automatically concatenated with the lexer.tag here: https://github.com/middleman/middleman-syntax/blob/master/lib/middleman-syntax/highlighter.rb#L11

I'm thinking a more flexible approach would be to use a format string (same style as middleman-blog):

css_class: 'highlight {lang}'  # Current default, must now specify {lang} as well
css_class: '{lang}'  # No class
css_class: 'highlight'  # Omitting the language class, currently not possible
css_class: 'highlight language-{lang}'  # Prefix, currently not possible

Also I noticed passing false is coerced to a string due to the line I linked, I think it should behave as nil OR both nil and false should raise errors.

The HTML5 working draft suggests this prefix idea which is why I added it. Previously I thought of just concatenating the two without a space if the css_class ends with a dash - but using a format string seems cleaner and means you wouldn't need another option to turn the language class off.

What do you think? It's a breaking change, so maybe adding another option like use_format_string: true would be needed? Will write the PR if this feature is accepted.

Arcovion avatar Feb 15 '15 23:02 Arcovion

What real problem would you be solving by making this so configurable?

bhollis avatar Feb 25 '15 08:02 bhollis

No real problem per se, I know that the HTML5 spec suggests the prefix and other highlighters like highlight.js have options for it (:class_prefix) - it's just semantics. With this you can also remove the CSS class completely (lexer.tag is always added currently). It is not worth a breaking change, but gives 100% control over the output.

Arcovion avatar Feb 25 '15 08:02 Arcovion

Sure. But there's a cost to adding features, especially configurable features. Not just the code to support them, but documentation, tests, responding to issues, maintaining the feature as you evolve the library, etc. I like to make sure that a new feature meets a relatively high bar - not only that it solves a real problem somebody's having, but that it solves a problem enough people are having to outweigh the cost of one more option people have to think about.

That said, don't let me discourage you from doing whatever you want. I'm not really that involved with this project these days, and I don't want to get in the way of progress. I just figured I'd toss in some advice.

bhollis avatar Feb 26 '15 05:02 bhollis

Yea that's why I wrote this instead of jumping in with a PR right away. Rouge is planning on having more options for HTML output, this would supplement that as one thing Rouge itself can't do is provide options for redcarpet and what CSS class is used. I'll wait until then though, I don't know when they plan on adding that and they're probably holding off on adding options too as you said.

Arcovion avatar Feb 26 '15 08:02 Arcovion

@arcovion have you written or modified a version of this to accommodate your needs? I'm looking to do the exact same thing so I can use prism.js. There may be an easier way for me but I've yet to figure it out.

christopherjanzen avatar May 25 '15 04:05 christopherjanzen

@christopherjanzen I haven't — I would code this up but it's hard to justify a potentially breaking change until there is a new major version of Rouge.

You can override it quite easily though I think, monkeypatch this highlight method to suit your needs:

highlighter_options[:css_class] = "language-#{lexer.tag}"

Arcovion avatar May 25 '15 04:05 Arcovion

Yeah, I did get that to work. Maybe I'm thinking of a simpler solution that doesn't require rouge at all? Something that would allow me to just use fenced code blocks that automatically applies language-***. Still looking. May have to get my hands dirty.

christopherjanzen avatar May 25 '15 05:05 christopherjanzen

Ah, well you need need Rouge's find_fancy method to automatically determine the type of code. You could simply write out the HTML and manually add the language class to it in the highlight method.

Rough idea:

def self.highlight(code, language=nil, opts={})
  lang = (Rouge::Lexer.find_fancy(language, code) || Rouge::Lexers::PlainText).tag
  "<pre><code class=\"language-#{lang}\">#{html_escape code}</code></pre>"
end

Arcovion avatar May 25 '15 05:05 Arcovion

Hmm I'll have to play around with this but thanks very much for the great leads! I think I'll be able to come up with a solution for my specific needs.

christopherjanzen avatar May 25 '15 05:05 christopherjanzen

I ended up with this:

"<pre><code class=\"language-#{lang}\">#{code}</code></pre>"

any downside to not using html_escape? I couldn't get it to work because it couldn't find the method html_escape.

christopherjanzen avatar May 25 '15 06:05 christopherjanzen

You must escape it, or the browser will process the code or any entities literally instead of treating it as text. Their html_escape method is here.

Arcovion avatar May 25 '15 06:05 Arcovion

Okay, think I finally figured it out! Thanks for your help.

christopherjanzen avatar May 25 '15 14:05 christopherjanzen

Hi all, What was the solution that ended up working then? Facing a similar issue where I'd like to override the default output to match what PrismJS expects and having a bit of trouble modifying that past the initial activation.

activate :syntax

zslabs avatar Nov 22 '16 15:11 zslabs

Hello @Arcovion, is there any missing action here? maybe time to close it?

markets avatar Jan 30 '24 15:01 markets