Functional syntax highlighting for rust

This commit is contained in:
Nathan McCarty 2025-02-07 05:48:05 -05:00
parent 731d7aa19c
commit 19e06488c4
7 changed files with 299 additions and 5 deletions

View file

@ -1,9 +1,13 @@
use v6.e.PREVIEW;
use Pandoc;
use JSON::Class:auth<zef:vrurg>;
use Pygments;
use DB::Post;
use JSON::Class:auth<zef:vrurg>;
use File::Temp;
#| A plain markdown post
unit class MarkdownPost does Post is json(:pretty);
@ -20,7 +24,17 @@ method title(--> Str:D) {
# Simply provide our source file to pandoc
method render-html(--> Str:D) {
markdown-to-html $!source
# Test to see if this posts contains any fenced code blocks, if so,
# pygmentize it through a temporary file
my $contents = $!source.slurp;
if $contents ~~ /'```'/ {
my $output = highlight-code $contents;
my ($filename, $filehandle) = tempfile;
$filehandle.spurt: $output, :close;
markdown-to-html $filename.IO
} else {
markdown-to-html $!source
}
}
# Return our summary, if we have one, otherwise extract the first paragraph of

View file

@ -6,7 +6,7 @@ use JSON::Fast;
#| Run pandoc with the given arguments, dieing on failure
sub pandoc(*@args --> Str:D) {
# Call into pandoc
my $pandoc = run 'pandoc', @args, :out, :err;
my $pandoc = run 'pandoc', '--no-highlight', @args, :out, :err;
# Collect the output
my $output = $pandoc.out.slurp: :close;

40
lib/Pygments.rakumod Normal file
View file

@ -0,0 +1,40 @@
#| Interaction with pygments
unit module Pygments;
my token fence { '```' }
my token info-string { \w+ }
# TODO: Be more precise about this so we can handle backticks in code blocks
my token code { <-[`]>+ }
my token code-block {
<&fence> <info-string> \h* \v
<code>
<&fence>
}
sub pygment(Str:D $code, Str:D $lang --> Str:D) {
my $pygments = run <pygmentize -f html -l>, $lang, :out, :in;
$pygments.in.spurt: $code, :close;
$pygments.out.slurp: :close;
}
sub highlight-code(Str:D $input --> Str:D) is export {
my $text = $input;
# TODO: Figure out a way to exclude idris code so we can process both in the
# same file
while $text ~~ &code-block {
my $match = $/;
# Extract the match and have pygments colorize the code
my $code = $match<code>.Str;
my $lang = $match<info-string>.Str;
my $out = pygment $code, $lang;
## Mangle the html to meet our needs
# Delete the existing div and construct a <code></code> inside the <pre>
$out ~~ s:g/'<' \/? 'div' <-[>]>* '>'//;
$out ~~ s:g/'<pre>'/<pre><code class="{$lang}-code">/;
$out ~~ s:g/'</pre>'/<\/code><\/pre>/;
# Rename the classes to match our needs
$out ~~ s:g/'span class="' (\w+) '"'/span class="hl-{$/[0].lc}"/;
$text = $match.replace-with: $out;
}
$text
}