ANSI formatter

This commit is contained in:
Roberto Alsina 2024-08-07 17:00:50 -03:00
parent f0d6b01362
commit aa1044ed22
2 changed files with 59 additions and 18 deletions

View File

@ -1,6 +1,7 @@
require "./constants.cr"
require "./styles.cr"
require "./tartrazine.cr"
require "colorize"
module Tartrazine
# This is the base class for all formatters.
@ -11,6 +12,63 @@ module Tartrazine
raise Exception.new("Not implemented")
end
def get_style_defs(theme : Theme) : String
raise Exception.new("Not implemented")
end
end
class Ansi < Formatter
def format(text : String, lexer : Lexer, theme : Theme) : String
output = String.build do |outp|
lexer.tokenize(text).each do |token|
outp << self.colorize(token[:value], token[:type], theme)
end
end
output
end
def colorize(text : String, token : String, theme : Theme) : String
style = theme.styles.fetch(token, nil)
return text if style.nil?
if theme.styles.has_key?(token)
s = theme.styles[token]
else
# 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.
s = theme.styles[theme.style_parents(token).reverse.find { |parent|
theme.styles.has_key?(parent)
}]
end
text.colorize(*rgb(s.color)).back(*rgb(s.background)).to_s
end
def rgb(c : String?)
return {0_u8, 0_u8, 0_u8} unless c
r = c[0..1].to_u8(16)
g = c[2..3].to_u8(16)
b = c[4..5].to_u8(16)
{r, g, b}
end
end
class Html < Formatter
def format(text : String, lexer : Lexer, theme : Theme) : String
output = String.build do |outp|
outp << "<html><head><style>"
outp << get_style_defs(theme)
outp << "</style></head><body>"
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
outp << "</code></pre></body></html>"
end
output
end
# ameba:disable Metrics/CyclomaticComplexity
def get_style_defs(theme : Theme) : String
output = String.build do |outp|
@ -35,23 +93,6 @@ module Tartrazine
end
output
end
end
class Html < Formatter
def format(text : String, lexer : Lexer, theme : Theme) : String
output = String.build do |outp|
outp << "<html><head><style>"
outp << get_style_defs(theme)
outp << "</style></head><body>"
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
outp << "</code></pre></body></html>"
end
output
end
# Given a token type, return the CSS class to use.
def get_css_class(token, theme)

View File

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