lsegal / yard

YARD is a Ruby Documentation tool. The Y stands for "Yay!"
http://yardoc.org
MIT License
1.95k stars 398 forks source link

Syntax highlighting of code in other languages than Ruby? #1405

Open thomthom opened 3 years ago

thomthom commented 3 years ago

I'm working on adding additional documentation in a .md document that ships with the API docs. In the docs I have C/C++ code examples for Ruby C Extensions. However, these code blocks doesn't get any syntax coloring. Is it possible with YARD? Via some addon gem or something?

thomthom commented 3 years ago

ah! I found this in the WhatsNew.md file:

https://github.com/lsegal/yard/blob/main/docs/WhatsNew.md#multiple-syntax-highlighting-language-support-050

On that note, it describes using !!!LANGNAME to indicate language. Does that mean normal markdown method of spesifying langue doesn't work?

```c++
// ...
```

```ruby
# ...
```
thomthom commented 3 years ago

Also, where does one add a html_syntax_highlight_LANGNAME type method?

thomthom commented 3 years ago

So, I already had a custom yard plugin with a custom template. And I tried adding it to templates/default/layout/html/setup.rb

def html_syntax_highlight_cpp(source)
  formatter = Rouge::Formatters::HTML.new
  lexer = Rouge::Lexers::Cpp.new
  formatter.format(lexer.lex(source))
end

And this worked! Is this the canonical way to do this? (At least for a template. I'm guessing it would be different if I wanted to make a yard plugin gem that worked across templates?)

lsegal commented 3 years ago

And this worked! Is this the canonical way to do this? (At least for a template. I'm guessing it would be different if I wanted to make a yard plugin gem that worked across templates?)

YARD::Templates::Helpers::HtmlHelper is the module that houses all the syntax highlighting methods, and would be the generic way to support such a plugin.

FWIW there are a few YARD syntax highlight plugins out there today. I would also recommend potentially injecting client-side highlighting JS libraries if you're only providing minimal amounts of visible code snippets. Highlight.js and equivalents would work seamlessly with most templates and could be brought in with a 1 line script injection.

thomthom commented 3 years ago

YARD::Templates::Helpers::HtmlHelper is the module that houses all the syntax highlighting methods, and would be the generic way to support such a plugin.

So a plugin would open that namespace and add methods to it?

FWIW there are a few YARD syntax highlight plugins out there today. I would also recommend potentially injecting client-side highlighting JS libraries if you're only providing minimal amounts of visible code snippets. Highlight.js and equivalents would work seamlessly with most templates and could be brought in with a 1 line script injection.

Oh, interesting. I didn't find those in my search. (my RubyGems foo is poor). I'll have a look and see if they cover my needs.

lsegal commented 3 years ago

So a plugin would open that namespace and add methods to it?

Yep. Adding custom markup formats works the same way.

thomthom commented 3 years ago

Thank you for the insights.

And format is only extracted via !!!LANGNAME notation, not via Markdown code block notation:

```c++
// ...
```

?

lsegal commented 3 years ago

And format is only extracted via !!!LANGNAME notation, not via Markdown code block notation:

Nope, both work, !!!LANGNAME is just a syntax to support indented blocks in RDoc formatting, which doesn't support language annotations (since it has no concept of fencing). YARD will post-process HTML output to detect the language type generated by Markdown and other processors:

https://github.com/lsegal/yard/blob/d61dac0fffb97c1fb40e8170e229d359f1ba31c6/lib/yard/templates/helpers/html_helper.rb#L640-L655

(edit: fixed code snippet link)

thomthom commented 3 years ago

Thanks! I don't know why I didn't see it working before, but now I do. I also tried out some of the other plugins, but none worked properly for my purpose. Most promising and closest to success was yard-coderay, but it didn't handle C++ syntax well. But your feedback and looking at yard-coderay I think I have what I need to make my own using Rouge. Only thing I have to resolve is that Rouge generate separate CSS code, not inline. So I need to figure out who to write that to file and link into the doc.

thomthom commented 3 years ago

hm... I'm only seeing the !!!LANG syntax working.

I inspected the calls to the code extracter and detect_lang_in_codeblock_attributes is getting passed two empty strings. The HTML that YARD parses is having code blocks that are plain <pre><code>...</code></pre>. The ```cpp syntax isn't adding any class annotations to the code blocks it generates.

lsegal commented 3 years ago

The HTML that YARD parses is having code blocks that are plain <pre><code>...</code></pre>

It would be a requirement for the Markdown processor library you're using to generate language-aware fenced code blocks. YARD doesn't do the generation for markdown, it's up to the library to understand fencing syntax-- since it's not a standard Markdown feature, not all libraries support it. Redcarpet (YARD's "first-choice" Markdown parser lib) should support this.

thomthom commented 3 years ago

Hm... Our code docs are using Rdoc, because of legacy reasons. But we have markdown pages included in the docs for additional info. Is it possible to set which markdown provider to use for the .md files only without switching all the documentation to use markdown syntax?

lsegal commented 3 years ago

Markdown files (.md) already use the markdown parser regardless of what is selected as the markup type; that said, yard doc options don't directly support changing the markup library provider (-M) for secondary markup types (i.e. the ones beyond what is selected with -m). You can do it with an extension / code though, specifically by manually reordering the list in YARD::Templates::Helpers::MarkupHelper:

https://github.com/lsegal/yard/blob/d61dac0fffb97c1fb40e8170e229d359f1ba31c6/lib/yard/templates/helpers/markup_helper.rb#L24-L34

That said, I'm not sure why you'd need to do this, since you should be able to gem install redcarpet. In fact, any of the top 3 providers should support fenced code blocks.

topherfangio commented 1 month ago

Two questions:

  1. I'd like to use https://highlightjs.org/ to get that automatic highlighting. How would you recommend I go about injecting it?
  2. Using the @example tag, there doesn't seem to be a way to set the language?
#
# @example Basic Chat
#    !!!haml
#    = daisy_chat do |chat|
#      - chat.with_message do
#        I can't believe it's not the weekend yet!

This renders ok, but doesn't add the haml class to the output (it just has example and code classes).