Module: Jekyll::Shiki

Defined in:
lib/jekyll-shiki.rb,
lib/version.rb

Overview

module Jekyll::ShikiCodeBlock

Constant Summary collapse

VERSION =
"0.1.1"

Class Method Summary collapse

Class Method Details

.create_wrapper(lan, code, site) ⇒ Object



39
40
41
42
43
44
45
46
47
48
49
50
51
# File 'lib/jekyll-shiki.rb', line 39

def self.create_wrapper(lan, code, site)
  lang = lan.capitalize
  highlighted_code = shiki_highlight(code, lan, site)
  <<~HTML
    <div class="shiki_code" data-shiki-highlighter>
      <div class="code_head">
        <span>#{lan}</span>
        <button type="button" aria-label="Highlight-#{lang}" data-copy-btn></button>
      </div>
      #{highlighted_code}
    </div>
  HTML
end

.full_document?(html_content) ⇒ Boolean

Returns:

  • (Boolean)


66
67
68
# File 'lib/jekyll-shiki.rb', line 66

def self.full_document?(html_content)
  html_content.match?(/\A\s*(<!doctype\s+html|<html\b)/i)
end

.replace_elements(node, site) ⇒ Object



53
54
55
56
57
58
59
60
61
62
63
64
# File 'lib/jekyll-shiki.rb', line 53

def self.replace_elements(node, site)
  code_el = node.at_css('> code[class^="language-"]')
  return unless code_el

  code = code_el.text
  lang = code_el["class"]
         &.split
         &.find { |class_name| class_name.start_with?("language-") }
         &.delete_prefix("language-")
  fragment = Nokogiri::HTML::DocumentFragment.parse(create_wrapper(lang, code, site))
  node.replace(fragment)
end

.resolve_shiki_bundle_path(site) ⇒ Object



16
17
18
19
20
21
22
23
24
# File 'lib/jekyll-shiki.rb', line 16

def self.resolve_shiki_bundle_path(site)
  shiki_config = site.config["shiki"]
  raise "Shiki highlight failed: Shiki config not found in jekyll config" unless shiki_config

  bundle_path = shiki_config["file_path"]
  raise "Shiki highlight failed: Required shiki bundle path." unless bundle_path

  File.join(site.source, bundle_path)
end

.shiki_highlight(code, lang, site) ⇒ Object



26
27
28
29
30
31
32
33
34
35
36
37
# File 'lib/jekyll-shiki.rb', line 26

def self.shiki_highlight(code, lang, site)
  script_path = resolve_shiki_bundle_path(site)

  cache_key = Digest::SHA256.hexdigest("#{lang}::#{code}")
  Jekyll::Cache.new("Shiki").getset(cache_key) do
    input = JSON.generate({ code: code, lang: lang }.compact)
    stdout, stderr, status = Open3.capture3("node", script_path, stdin_data: input)
    raise "Shiki highlight failed: #{stderr}" unless status.success?

    stdout
  end
end

.transform_html(html_content, site) ⇒ Object



70
71
72
73
74
75
76
77
78
79
80
81
# File 'lib/jekyll-shiki.rb', line 70

def self.transform_html(html_content, site)
  doc = if full_document?(html_content)
          Nokogiri::HTML.parse(html_content)
        else
          Nokogiri::HTML::DocumentFragment.parse(html_content)
        end
  elements = doc.css("pre").select { |pre| pre.at_css('> code[class^="language-"]') }
  return html_content if elements.empty?

  elements.each { |node| replace_elements(node, site) }
  doc.to_html
end