Starting to add options to HTML formatter: standalone

This commit is contained in:
Roberto Alsina 2024-08-09 11:57:23 -03:00
parent 47237eecc3
commit fd5af6ba3b
2 changed files with 87 additions and 54 deletions

View File

@ -1,59 +1,90 @@
require "../formatter" require "../formatter"
module Tartrazine module Tartrazine
class Html < Formatter class Html < Formatter
def format(text : String, lexer : Lexer, theme : Theme) : String # Not all of these options are implemented
output = String.build do |outp|
outp << "<html><head><style>" property? standalone : Bool = false
outp << get_style_defs(theme)
outp << "</style></head><body>" # property class_prefix : String = ""
outp << "<pre class=\"#{get_css_class("Background", theme)}\"><code class=\"#{get_css_class("Background", theme)}\">" # property with_classes : Bool = true
lexer.tokenize(text).each do |token| # property tab_width = 8
fragment = "<span class=\"#{get_css_class(token[:type], theme)}\">#{token[:value]}</span>" # property surrounding_pre : Bool = true
outp << fragment # property wrap_long_lines : Bool = false
end # property line_numbers : Bool = false
outp << "</code></pre></body></html>" # property line_number_in_table : Bool = false
end # property linkable_line_numbers : Bool = false
output # property highlight_lines : Array(Range(Int32, Int32)) = [] of Range(Int32, Int32)
# property base_line_number : Int32 = 1
def format(text : String, lexer : Lexer, theme : Theme) : String
text = format_text(text, lexer, theme)
if standalone?
text = wrap_standalone(text, theme)
end
text
end
# Wrap text into a full HTML document, including the CSS for the theme
def wrap_standalone(text, theme) : String
output = String.build do |outp|
outp << "<!DOCTYPE html><html><head><style>"
outp << get_style_defs(theme)
outp << "</style></head><body>"
outp << text
outp << "</body></html>"
end
output
end
def format_text(text : String, lexer : Lexer, theme : Theme) : String
output = String.build do |outp|
outp << "<pre class=\"#{get_css_class("Background", theme)}\"><code class=\"#{get_css_class("Background", theme)}\">"
lexer.tokenize(text).each do |token|
fragment = "<span class=\"#{get_css_class(token[:type], theme)}\">#{token[:value]}</span>"
outp << fragment
end end
outp << "</code></pre>"
end
output
end
# ameba:disable Metrics/CyclomaticComplexity # ameba:disable Metrics/CyclomaticComplexity
def get_style_defs(theme : Theme) : String def get_style_defs(theme : Theme) : String
output = String.build do |outp| output = String.build do |outp|
theme.styles.each do |token, style| theme.styles.each do |token, style|
outp << ".#{get_css_class(token, theme)} {" outp << ".#{get_css_class(token, theme)} {"
# These are set or nil # These are set or nil
outp << "color: #{style.color.try &.hex};" if style.color outp << "color: ##{style.color.try &.hex};" if style.color
outp << "background-color: #{style.background.try &.hex};" if style.background outp << "background-color: ##{style.background.try &.hex};" if style.background
outp << "border: 1px solid #{style.border.try &.hex};" if style.border outp << "border: 1px solid ##{style.border.try &.hex};" if style.border
# These are true/false/nil # These are true/false/nil
outp << "border: none;" if style.border == false outp << "border: none;" if style.border == false
outp << "font-weight: bold;" if style.bold outp << "font-weight: bold;" if style.bold
outp << "font-weight: 400;" if style.bold == false outp << "font-weight: 400;" if style.bold == false
outp << "font-style: italic;" if style.italic outp << "font-style: italic;" if style.italic
outp << "font-style: normal;" if style.italic == false outp << "font-style: normal;" if style.italic == false
outp << "text-decoration: underline;" if style.underline outp << "text-decoration: underline;" if style.underline
outp << "text-decoration: none;" if style.underline == false outp << "text-decoration: none;" if style.underline == false
outp << "}" outp << "}"
end
end
output
end
# Given a token type, return the CSS class to use.
def get_css_class(token, theme)
return Abbreviations[token] if theme.styles.has_key?(token)
# Themes don't contain information for each specific
# token type. However, they may contain information
# for a parent style. Worst case, we go to the root
# (Background) style.
Abbreviations[theme.style_parents(token).reverse.find { |parent|
theme.styles.has_key?(parent)
}]
end end
end end
output
end
# Given a token type, return the CSS class to use.
def get_css_class(token, theme)
return Abbreviations[token] if theme.styles.has_key?(token)
# Themes don't contain information for each specific
# token type. However, they may contain information
# for a parent style. Worst case, we go to the root
# (Background) style.
Abbreviations[theme.style_parents(token).reverse.find { |parent|
theme.styles.has_key?(parent)
}]
end
end
end end

View File

@ -2,4 +2,6 @@ require "./**"
lexer = Tartrazine.lexer("crystal") lexer = Tartrazine.lexer("crystal")
theme = Tartrazine.theme(ARGV[1]) theme = Tartrazine.theme(ARGV[1])
puts Tartrazine::Html.new.format(File.read(ARGV[0]), lexer, theme) formatter = Tartrazine::Html.new
formatter.standalone = true
puts formatter.format(File.read(ARGV[0]), lexer, theme)