Bash highlight with prepended dollar sign $

For my website, I am using Hextra theme. The live website is Part 2: Configuring VPS and DNS – minhperry's Blog (the one being mentioned here) with a button to “edit this page on github”, which will bring you to the corresponding repo file.

Currently, this code

~~~bash {filename="bash"}
sudo -u www-data stat /absolute/path/to/specified/root
~~~

will be rendered as
[See image 1 below]
I want to prepend something like user@machine:~$, however it would also be considered as content when user copies. I have asked the creator and they said to use codeblock render hook: Bash with $ at front. · imfing/hextra · Discussion #484 · GitHub

After messing around, I found the source for the code rendering of the theme: hexxtra/layouts/_default/_markup/render-codeblock.html

{{- $class := .Attributes.class | default "" -}}
{{- $filename := .Attributes.filename | default "" -}}
{{- $lang := .Attributes.lang | default .Type -}}


<div class="hextra-code-block hx-relative hx-mt-6 first:hx-mt-0 hx-group/code">
  {{ partial "components/codeblock" (dict "filename" $filename "lang" $lang "content" .Inner "options" .Options) }}

  {{- if or (eq site.Params.highlight.copy.enable nil) (site.Params.highlight.copy.enable) }}
    {{- partialCached "components/codeblock-copy-button" (dict "filename" $filename) $filename }}
  {{ end }}
</div>

with the main component being responsible for code highlighting at hextra/layouts/partials/components/codeblock.html:

{{ $filename := .filename | default "" -}}
{{ $lang := .lang | default "" }}
{{ $content := .content }}
{{ $options := .options | default (dict) }}

{{- if $filename -}}
  <div class="filename" dir="auto">{{ $filename }}</div>
{{- end -}}
{{- if transform.CanHighlight $lang -}}
  <div>{{- highlight $content $lang $options -}}</div>
{{- else -}}
  <pre><code>{{ $content }}</code></pre>
{{- end -}}

The highlight function is solely responsible for highlighting the language, so I can’t simply just intercept it by adding some html anywhere.
[See image 2 below]
Is my niche highlighting case even possible?

Image 1

Image 2

You cannot hook in while highlighting, but after you may catch the result and postprocess.

You could override the render hook or the called partial to capture the result html.

  • copy the file you want to your projects root at:

    • layouts/_default/_markup/render-codeblock.html
    • layouts/partials/components/codeblock.html
  • assign the result of the highlighting to a variable

    just a basic example
    {{- $class := .Attributes.class | default "" -}}
    {{- $filename := .Attributes.filename | default "" -}}
    {{- $lang := .Attributes.lang | default .Type -}}
    
    
    <div class="hextra-code-block hx-relative hx-mt-6 first:hx-mt-0 hx-group/code">
    {{ $Code := partial "components/codeblock" (dict "filename" $filename "lang" $lang "content" .Inner "options" .Options) }}
    {{-
       ###
       ### do anything you want with $Code
       ###
    -}}
    {{- $Code -}} 
    {{- if or (eq site.Params.highlight.copy.enable nil) (site.Params.highlight.copy.enable) }}
       {{- partialCached "components/codeblock-copy-button" (dict "filename" $filename) $filename }}
    {{ end }}
    
  • and implement code that does what you want on the captured code using regex/or line parsing…)

    mayba as <span class="prompt">u@m $</span>

Keep in mind that this may be quite complex (or a very special solution for you)

  • if numbering is on, will be HTML different
  • if there’s unknown language the HTML is different
  • you will also have to adjust the “copy function” (probably JS) to not catch your prompt
  • …much more
1 Like

Looking at the HTML generated by your theme, it seems (!) that every line of highlighted code is wrapped in a <span class="line">. Use that to prepend a $ with a ::before pseudo-element in your CSS. Something like

code.language-bash > span.line::before {
  content: "$";
  margin-right: 0.2em;
}

The $ sign will not be copied. That’s the easiest solution, in my opinion.

2 Likes

I just wanted to suggest CSS content. The problem you will run into will be that if you have multiline bash scripts that are separated with \ and a new line you will still get the full content before the line. You could work around that by supplying the n-th numbers of the lines with the content in your shortcode (like first line, fifth line) and then use something along the lines of :first-child or :nth-child(5).

There are highlighting options that will result in rendering a list, which might make this all a bit easier.

3 Likes

Good point, though I don’t quite understand what you are suggesting. The HTML looks like this:

<code class=<language-bash>">
  <span class="line">...</span>
  <span class="line">...</span>
  ...
</code>

In the CSS, you have no way to recognize continuation lines, as you can’t test for the content of the span. And it seems that Chroma has no token for the continuation character.

What is the fifth-line here – the fifth continuation line? And how would you tell the CSS that in this code block it should not prepend a $ to some lines? I don’t see a way short of using inline styles, which is horrible.

1 Like
.language-bash .line:first-child {
color: red;
}

should format the first line red, all others however they are formatted. Using this you can add a content: "$myprompt"; ::before that line.

Using line:nth-child(2) instead will do the same with the second line. Increase the numbers and you know where it goes.

Use nth-child(2n+1) and it will do something to all odd lines… 2n catches the even lines.

and so on.

Creating a shortcode like this:

{{< shortcode fulllines="1,5" >}}

It could then be transformed into a CSS section with .line:nth-child(1), .line:nth-child(5) with a “full bash prompt” content. All other lines receive only the particle that you want to show in continued lines.

PS: By the way I am not saying that I think it’s a good idea to bring the bash prompt into the highlighting. The fact alone that this is solvable with CSS shows us that it’s a design issue, not a code presentation issue or something like that. What will happen with Python code, with CSS, with other code samples? Just an opinion, but I keep that out of my site and have a clear indicator what code or language we are highlighting per highlighting section. This seems more usable.

1 Like

Ah, of course. I was thinking (if I was thinking at all) the other way around: Turning off content for all children but the first one.

I agree. I’ve seen people typing the prompt and then wondering why the command didn’t work.

This topic was automatically closed 2 days after the last reply. New replies are no longer allowed.