3

I want to style some HTML source block exports differently than others.

Say I want the "Hi" block to have a green background and "Bye" to be red:

#+COMMENT: -*- org-html-htmlize-output-type: css -*-

#+begin_src python
print("Hi")
#+end_src

#+begin_src python
print("Bye")
#+end_src

The relevent HTML export is,

<div id="content">
<div class="org-src-container">
<pre class="src src-python"><span class="org-keyword">print</span>(<span class="org-string">"Hi"</span>)
</pre>
</div>

<div class="org-src-container">
<pre class="src src-python"><span class="org-keyword">print</span>(<span class="org-string">"Bye"</span>)
</pre>
</div>
</div>

Each block corresponds to a org-src-container or src src-python and there is no way to differentiate them individually via CSS (unless I'm mistaken).

My thought is to assign a class or id tag to an individual block's div or pre. It seems like #+ATTR_HTML might work but the following produces the same output:

#+COMMENT: -*- org-html-htmlize-output-type: css -*-

#+ATTR_HTML: :class myclass :id myid
#+begin_src python
print("Hi")
#+end_src

#+begin_src python
print("Bye")
#+end_src

How can I add a class or id selector to specific block exports?

EDIT

From looking at the Org docs more, it appears that #+ATTR_HTML is only for tables and links when used with a source block. Frustratingly, it works exactly how I would like it to for example blocks: Org mode - change code block background color I suppose I could use that, except syntax highlighting doesn't seem to apply to example block exports.

I tried advising the org-html-src-block to include the desired tags (based off of Generate different markup for not-tangled code blocks in org-mode). Unfortunately, I couldn't find a way to pass information to the function (e.g. such as through a new key-value pair within the #+begin_src line). The info parameter only contains meta-data.

Finally, I tried applying a filter (i.e. regexp replace). This worked for single lines, but I couldn't get it to apply generally, such for multiple lines or to have a generic form. Using the regexp-builder, I could capture the code portion, the CSS tag, and the value with

"\\(?1:[^\n]+\\)#\s+\\(?2:[A-Za-z-]+\\):\s+\\(?3:.+\\)"

This would correspond to the print("Hi"), background-color, and rgb(255, 0, 0) in

#+begin_src python
print("Hi")  # background-color: rgb(255, 0, 0)
#+end_src

This was inspired by: https://emacs.stackexchange.com/questions/20417/org-mode-highlight-lines-i$|org-export-derived-backend-p

1 Answer 1

3

You can do this with the advice method. It's not the info parameter you need, but src-block. Use the org-export-read-attribute to extract the #ATTR_HTML contents.

The following advice checks for the :class and :id keywords in a #attr_html line and constructs a div around the source block accordingly.

(defun my-org-html-src-block-advice (oldfun src-block contents info)
  "Add class or id CSS tags to html source block output.

Allows class or id tags to be added to a source block using
#attr_html:

    #+ATTR_HTML: :class myclass :id myid
    #+begin_src python
    print(\"Hi\")
    #+end_src
"
  (let* ((old-ret (funcall oldfun src-block contents info))
         (class-tag (org-export-read-attribute :attr_html src-block :class))
         (id-tag (org-export-read-attribute :attr_html src-block :id)))
    (if (or class-tag id-tag)
        (concat
         "<div "
         (if class-tag (format "class=\"%s\" " class-tag))
         (if id-tag (format "id=\"%s\" " id-tag))
         ">"
         old-ret
         "</div>")
      old-ret)))

(advice-add 'org-html-src-block :around #'my-org-html-src-block-advice)

When applied to the sample Org file, it produces the output:

<div class="myclass" id="myid" ><div class="org-src-container">
<pre class="src src-python"><span class="org-keyword">print</span>(<span class="org-string">"Hi"</span>)
</pre>
</div></div>

<div class="org-src-container">
<pre class="src src-python"><span class="org-keyword">print</span>(<span class="org-string">"Bye"</span>)
</pre>
</div>
3
  • Org-mode produces pre elements as HTML output for source blocks. This wraps the output pre in a div and gives the div a class or an id attribute. Is it possible to instead put that id attribute on the pre tag, avoiding to generate an additional wrapping div element? Commented Feb 26, 2023 at 23:57
  • I agree this is not ideal. I think the issue was that I couldn't get access to the specific pre tag in order to give it an id. You might be able to do that using :filter-return instead of :around (for WHERE in advice-add), scan for the specific pretag, and modify the return value so that it has an id. It's not clear to me what you could match on, though. All pretags appear to have the same form, <pre class="src src-python">. Commented Feb 27, 2023 at 14:10
  • The reason why I asked is, that org-mode started to output a random id attribute on the pre tags and that is a diff (for VCS) every single time I export to HTML. Not terrible, but also not great either. But perhaps this solves the problem, have not tried yet: stackoverflow.com/a/37404938/1829329. Commented Feb 27, 2023 at 18:15

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.