Skip to content

Commit

Permalink
Merge pull request #499 from kaushalmodi/code-fence-instead-of-highlight
Browse files Browse the repository at this point in the history
Src/Example blocks use code fence instead of `highlight` if Goldmark
  • Loading branch information
kaushalmodi authored Jan 5, 2022
2 parents 3f41412 + 6f04f20 commit ffd5ea8
Show file tree
Hide file tree
Showing 14 changed files with 824 additions and 297 deletions.
118 changes: 72 additions & 46 deletions doc/ox-hugo-manual.org
Original file line number Diff line number Diff line change
Expand Up @@ -1327,11 +1327,19 @@ adding this to the CSS:
possible. It also supports exporting source blocks with line numbers
and/or highlighting enabled for specific lines.
**** Code Fences
By default, the =HUGO_CODE_FENCE= property is set to a non-nil
value. So the code blocks will be exported with GitHub-style
code-fencing with triple-backticks when possible.
By default, the =HUGO_CODE_FENCE= property is non-nil. So the code
blocks will be exported with GitHub-style code-fencing with
triple-backticks when possible.

Example:
For example, below Org source block:

#+begin_src org
,#+begin_src emacs-lisp
(message "Hello")
,#+end_src
#+end_src

will export to:

#+begin_src md
```emacs-lisp
Expand All @@ -1344,17 +1352,8 @@ Example:
least as of [[https://github.com/gohugoio/hugo/commit/bfb9613a14ab2d93a4474e5486d22e52a9d5e2b3][Hugo v0.60.0]]) for syntax highlighting to work for fenced
code blocks.

The Hugo =highlight= shortcode is automatically used instead of code
fences (even with this property at a non-nil value) if:
- Line numbers are enabled using the Org =-n= / =+n= syntax (see
below), or
- Line highlighting is enabled using the =:hl_lines= parameter in the
source block header (see below), or
- =:linenos= parameter is specified in the source block header (see
below).

Set the =HUGO_CODE_FENCE= property to =nil= if you want to *always*
use the Hugo =highlight= shortcode.
If you want to always use the Hugo [[#highlight-shortcode][=highlight= shortcode]], set the
=HUGO_CODE_FENCE= property to =nil=.
**** Line numbers
Line numbers can be enabled/configured using the Org =-n= / =+n=
syntax. See the Info node [[https://orgmode.org/manual/Literal-Examples.html][=(org) Literal Examples=]] for more
Expand All @@ -1364,37 +1363,10 @@ Here are some examples fetched from the "Source blocks with line
number annotation" test case in the {{{ox-hugo-test-file}}}.

#+include: "../test/site/content-org/all-posts.org::#source-block-line-number-cases" :only-contents t
**** Highlighting
Implementing this feature was interesting, because while Org doesn't
have a syntax to enable highlighting only specific lines, the Hugo
=highlight= shortcode does allow that via =hl_lines= argument.

So the challenge was to present that "lines to be highlighted"
information in the Org source in a nice format and then translate that
to the =hl_lines= =highlight= shortcode argument at the time of
exporting.

It involved /hacking/ the =org-babel-exp-code=. See [[https://lists.gnu.org/archive/html/emacs-orgmode/2017-10/msg00300.html][this discussion on
the =emacs-orgmode= thread]] if interested.

This feature is implemented by using a parameter called =:hl_lines= in
the header of source blocks. This parameter is specific to =ox-hugo=,
and that's why implementing this needed that hack.

If a user wants to highlight lines 1, and then 3 to 5, they would add
=:hl_lines 1,3-5= to the source block header.
# Below 2 include statements fetch the noweb references used in the
# code inserted by the following include statements.
#+include: "../test/site/content-org/all-posts.org::#source-block-with-line-numbers-examples"
#+include: "../test/site/content-org/all-posts.org::#source-block-with-line-highlighting-examples"
***** Without line numbers
#+include: "../test/site/content-org/all-posts.org::#source-blocks-with-highlighting-no-linenums" :only-contents t
***** With line numbers
The Org source for the below is similar to the above, except that the
=-n= switch is also added to enable the line numbers.

#+include: "../test/site/content-org/all-posts.org::#source-blocks-with-highlighting-with-linenums-not-starting-from-1" :only-contents t
**** Line number Style (*linenos*)
***** Line number Style (*linenos*)
:PROPERTIES:
:CUSTOM_ID: linenos
:END:
When line numbers are enabled, by default the "table" style is used
for line numbers. This is specified using the [[https://gohugo.io/content-management/syntax-highlighting/#highlight-shortcode][=linenos= argument to
the =highlight= shortcode]].
Expand All @@ -1421,7 +1393,61 @@ by adding =:linenos false= to their headers.
,#+end_src
#+end_src

- Valid values of ~linenos~ :: ~table~ (default), ~true~, ~false~,
~inline~

/The same =:linenos= header arg works for example blocks too./
**** Highlighting
Implementing this feature was interesting, because while Org doesn't
have a syntax to enable highlighting only specific lines, Hugo
supports highlighting using the =hl_lines= attribute to [[https://gohugo.io/content-management/syntax-highlighting#highlighting-in-code-fences][code fences]]
(Hugo v0.60.0+) or its ~highlight~ shortcode.

So the challenge was to present that "lines to be highlighted"
information in the Org source in a nice format and then translate that
to the =hl_lines= attribute with the required format at the time of
exporting.

It involved /hacking/ the =org-babel-exp-code=. See [[https://lists.gnu.org/archive/html/emacs-orgmode/2017-10/msg00300.html][this discussion on
the =emacs-orgmode= thread]] if interested.

This feature is implemented by using a parameter called =:hl_lines= in
the header of source blocks. This parameter is specific to =ox-hugo=,
and that's why implementing this needed that hack.

If a user wants to highlight lines 1, and then 3 to 5, they would add
=:hl_lines 1,3-5= to the source block header.
***** Noweb refences :noexport:
Below 2 include statements fetch the noweb references used in the code
inserted by other include statements in the following sections.

They are included to get the /noweb/ references working but they do
not need to be exported.

#+include: "../test/site/content-org/all-posts.org::#source-block-with-line-numbers-examples"
#+include: "../test/site/content-org/all-posts.org::#source-block-with-line-highlighting-examples"
***** Highlighting without line numbers
#+include: "../test/site/content-org/all-posts.org::#source-blocks-with-highlighting-no-linenums" :only-contents t
***** Highlighting with line numbers
The Org source for the below is similar to the above, except that the
=-n= switch is also added to enable the line numbers.

#+include: "../test/site/content-org/all-posts.org::#source-blocks-with-highlighting-with-linenums-not-starting-from-1" :only-contents t
**** ~highlight~ shortcode
:PROPERTIES:
:CUSTOM_ID: highlight-shortcode
:END:
The Hugo [[https://gohugo.io/content-management/syntax-highlighting#highlight-shortcode][=highlight= shortcode]] is automatically used instead of code
fences (even with this property at a non-nil value) if one of these is
true:
- ~HUGO_CODE_FENCE~ is set to /nil/.
- "Blackfriday mode" is enabled (~HUGO_GOLDMARK~ is /nil/) *and*
either the [[*Line numbers][line numbering]] or [[*Highlighting][highlighting]] feature is enabled, or if
the [[#linenos][=:linenos= parameter]] is specified in the source block header.

By default, ~ox-hugo~ tries to avoid using this shortcode because it's
more bug-prone than the code fences ({{{issue(161)}}}), and also the
code fences are more /Markdownish/ :smile:.
**** Hiding source block caption numbers
The "Code Snippet <number>:" part of the source block captions can be
hidden by adding this to the CSS:
Expand Down
28 changes: 20 additions & 8 deletions ox-blackfriday.el
Original file line number Diff line number Diff line change
Expand Up @@ -641,12 +641,15 @@ information."
(let* ((parent-element (org-export-get-parent example-block))
(parent-type (car parent-element))
(backticks (make-string org-blackfriday--code-block-num-backticks ?`))
(example (org-export-format-code-default example-block info))
(example (or (plist-get info :md-code) ;if set in `org-hugo-example-block'
(org-export-format-code-default example-block info)))
(code-attr (if (plist-get info :md-code-attr) ;if set in `org-hugo-example-block'
(format " { %s }" (plist-get info :md-code-attr))
""))
ret)
;; (message "[ox-bf example-block DBG]")
;; (message "[ox-bf example-block DBG] parent type: %S" parent-type)
(setq ret (org-blackfriday--issue-239-workaround example parent-type))
(setq ret (format "%stext\n%s%s" backticks ret backticks))
(setq ret (format "%stext%s\n%s%s" backticks code-attr ret backticks))
(setq ret (org-blackfriday--div-wrap-maybe example-block ret info))
(when (equal 'quote-block parent-type)
;; If the current example block is inside a quote block, future
Expand All @@ -655,6 +658,9 @@ information."
;; for https://github.com/russross/blackfriday/issues/407.
(setq org-blackfriday--code-block-num-backticks
(1+ org-blackfriday--code-block-num-backticks)))
;; Reset the temp info in the `info' plist.
(plist-put info :md-code nil)
(plist-put info :md-code-attr nil)
ret))

;;;; Fixed Width
Expand Down Expand Up @@ -1054,7 +1060,11 @@ This function is adapted from `org-html-special-block'."
INFO is a plist used as a communication channel."
(let* ((lang (org-element-property :language src-block))
(lang (or (cdr (assoc lang org-blackfriday-syntax-highlighting-langs)) lang))
(code (org-export-format-code-default src-block info))
(code (or (plist-get info :md-code) ;if set in `org-hugo-src-block'
(org-export-format-code-default src-block info)))
(code-attr (if (plist-get info :md-code-attr) ;if set in `org-hugo-src-block'
(format " { %s }" (plist-get info :md-code-attr))
""))
(parent-element (org-export-get-parent src-block))
(parent-type (car parent-element))
(num-backticks-in-code (when (string-match "^[[:blank:]]*\\(`\\{3,\\}\\)" code)
Expand All @@ -1074,19 +1084,21 @@ INFO is a plist used as a communication channel."
(<= org-blackfriday--code-block-num-backticks num-backticks-in-code))
(setq org-blackfriday--code-block-num-backticks (1+ num-backticks-in-code)))
(setq backticks (make-string org-blackfriday--code-block-num-backticks ?`))
;; (message "[ox-bf src-block DBG]")
;; (message "ox-bf [dbg] code: %s" code)
;; (message "[ox-bf src-block DBG] code: %s" code)
;; (message "[ox-bf src-block DBG] parent type: %S" parent-type)
(setq code (org-blackfriday--issue-239-workaround code parent-type))
(prog1
(format "%s%s\n%s%s" backticks lang code backticks)
(format "%s%s%s\n%s%s" backticks lang code-attr code backticks)
(when (equal 'quote-block parent-type)
;; If the current code block is inside a quote block, future
;; example/code blocks (especially the ones outside this quote
;; block) will require higher number of backticks. Workaround
;; for https://github.com/russross/blackfriday/issues/407.
(setq org-blackfriday--code-block-num-backticks
(1+ org-blackfriday--code-block-num-backticks))))))
(1+ org-blackfriday--code-block-num-backticks)))
;; Reset the temp info in the `info' plist.
(plist-put info :md-code nil)
(plist-put info :md-code-attr nil))))

;;;; Strike-Through
(defun org-blackfriday-strike-through (_strike-through contents _info)
Expand Down
Loading

0 comments on commit ffd5ea8

Please sign in to comment.