Implemented decent version of the CLI

This commit is contained in:
Roberto Alsina 2024-08-11 11:49:42 -03:00
parent e40c8b586c
commit e295256573
4 changed files with 111 additions and 30 deletions

View File

@ -1,5 +1,5 @@
build: $(wildcard src/**/*.cr) $(wildcard lexers/*xml) $(wildcard styles/*xml) shard.yml
shards build -Dstrict_multi_assign -Dno_number_autocast
shards build -Dstrict_multi_assign -Dno_number_autocast -d --error-trace
release: $(wildcard src/**/*.cr) $(wildcard lexers/*xml) $(wildcard styles/*xml) shard.yml
shards build --release
static: $(wildcard src/**/*.cr) $(wildcard lexers/*xml) $(wildcard styles/*xml) shard.yml

View File

@ -5,6 +5,22 @@ module Tartrazine
bake_folder "../lexers", __DIR__
end
# Get the lexer object for a language name
# FIXME: support aliases, paths, mimetypes, etc
def self.lexer(name : String) : Lexer
Lexer.from_xml(LexerFiles.get("/#{name}.xml").gets_to_end)
end
# Return a list of all lexers
# FIXME: support aliases
def self.lexers : Array(String)
lexers = Set(String).new
LexerFiles.files.each do |file|
lexers << file.path.split("/").last.split(".").first
end
lexers.to_a.sort!
end
# This implements a lexer for Pygments RegexLexers as expressed
# in Chroma's XML serialization.
#
@ -173,8 +189,4 @@ module Tartrazine
# A token, the output of the tokenizer
alias Token = NamedTuple(type: String, value: String)
def self.lexer(name : String) : Lexer
Lexer.from_xml(LexerFiles.get("/#{name}.xml").gets_to_end)
end
end

View File

@ -1,35 +1,92 @@
require "docopt"
require "./**"
HELP = <<-HELP
tartrazine: a syntax highlighting tool
Usage:
tartrazine FILE -f html [-t theme][--standalone][--line-numbers]
[-l lexer] [-o output][--css]
tartrazine (-h, --help)
tartrazine FILE -f html [-t theme][--standalone][--line-numbers][-l lexer] [-o output]
tartrazine -f html -t theme --css
tartrazine FILE -f terminal [-t theme][-l lexer][-o output]
tartrazine FILE -f json [-o output]
tartrazine --list-themes
tartrazine --list-lexers
tartrazine --list-formatters
tartrazine --version
-f <formatter> Format to use (html, terminal, json)
-t <theme> Theme to use (see --list-themes)
-l <lexer> Lexer (language) to use (see --list-lexers)
-o <output> Output file (default: stdout)
--standalone Generate a standalone HTML file
--css Generate a CSS file for the theme
--line-numbers Include line numbers in the output
Options:
-f <formatter> Format to use (html, terminal, json)
-t <theme> Theme to use, see --list-themes [default: default-dark]
-l <lexer> Lexer (language) to use, see --list-lexers [default: plaintext]
-o <output> Output file. Default is stdout.
--standalone Generate a standalone HTML file, which includes
all style information. If not given, it will generate just
a HTML fragment ready to include in your own page.
--css Generate a CSS file for the theme called <theme>.css
--line-numbers Include line numbers in the output
-h, --help Show this screen
-v, --version Show version number
HELP
lexer = Tartrazine.lexer("crystal")
theme = Tartrazine.theme(ARGV[1])
# formatter = Tartrazine::Json.new
formatter = Tartrazine::Html.new
formatter.standalone = true
formatter.class_prefix = "hl-"
formatter.line_number_id_prefix = "ln-"
formatter.line_numbers = true
formatter.highlight_lines = [3..7, 20..30]
formatter.linkable_line_numbers = false
formatter.wrap_long_lines = false
puts formatter.format(File.read(ARGV[0]), lexer, theme)
options = Docopt.docopt(HELP, ARGV)
# Handle version manually
if options["--version"]
puts "tartrazine #{Tartrazine::VERSION}"
exit 0
end
if options["--list-themes"]
puts Tartrazine.themes.join("\n")
exit 0
end
if options["--list-lexers"]
puts Tartrazine.lexers.join("\n")
exit 0
end
if options["--list-formatters"]
puts "html\njson\nterminal"
exit 0
end
if options["-f"]
formatter = options["-f"].as(String)
case formatter
when "html"
formatter = Tartrazine::Html.new
formatter.standalone = options["--standalone"] != nil
formatter.line_numbers = options["--line-numbers"] != nil
when "terminal"
formatter = Tartrazine::Ansi.new
when "json"
formatter = Tartrazine::Json.new
else
puts "Invalid formatter: #{formatter}"
exit 1
end
theme = Tartrazine.theme(options["-t"].as(String))
if formatter.is_a?(Tartrazine::Html) && options["--css"]
File.open("#{options["-t"].as(String)}.css", "w") do |outf|
outf.puts formatter.get_style_defs(theme)
end
exit 0
end
lexer = Tartrazine.lexer(options["-l"].as(String))
input = File.open(options["FILE"].as(String)).gets_to_end
output = formatter.format(input, lexer, theme)
if options["-o"].nil?
puts output
else
File.open(options["-o"].as(String), "w") do |outf|
outf.puts output
end
end
end

View File

@ -10,6 +10,11 @@ require "xml"
module Tartrazine
alias Color = Sixteen::Color
class ThemeFiles
extend BakedFileSystem
bake_folder "../styles", __DIR__
end
def self.theme(name : String) : Theme
begin
return Theme.from_base16(name)
@ -23,9 +28,16 @@ module Tartrazine
end
end
class ThemeFiles
extend BakedFileSystem
bake_folder "../styles", __DIR__
# Return a list of all themes
def self.themes
themes = Set(String).new
ThemeFiles.files.each do |file|
themes << file.path.split("/").last.split(".").first
end
Sixteen::DataFiles.files.each do |file|
themes << file.path.split("/").last.split(".").first
end
themes.to_a.sort!
end
class Style