pvincent
7 months ago
6 changed files with 241 additions and 6 deletions
-
10.vscode/settings.json
-
42app/controllers/scores_controller.rb
-
9config/environments/development.rb
-
55lib/formatters/ansi_colors.rb
-
53lib/formatters/ansi_formatter.rb
-
78lib/formatters/ansi_wrapper.rb
@ -0,0 +1,55 @@ |
|||
module AnsiColors |
|||
# FORMAT |
|||
CLEAR = "\e[0m".freeze |
|||
BOLD = "\e[1m".freeze |
|||
UNDERLINE = "\e[4m".freeze |
|||
|
|||
# TEXT |
|||
TEXT_BLACK = "\e[30m".freeze |
|||
TEXT_RED = "\e[31m".freeze |
|||
TEXT_GREEN = "\e[32m".freeze |
|||
TEXT_YELLOW = "\e[33m".freeze |
|||
TEXT_BLUE = "\e[34m".freeze |
|||
TEXT_MAGENTA = "\e[35m".freeze |
|||
TEXT_CYAN = "\e[36m".freeze |
|||
TEXT_WHITE = "\e[37m".freeze |
|||
|
|||
# TEXT GRAY SHADES |
|||
TEXT_GRAY_800 = "\e[38;5;232m".freeze |
|||
TEXT_GRAY_700 = "\e[38;5;233m".freeze |
|||
TEXT_GRAY_600 = "\e[38;5;235m".freeze |
|||
TEXT_GRAY_500 = "\e[38;5;238m".freeze |
|||
TEXT_GRAY_400 = "\e[38;5;241m".freeze |
|||
TEXT_GRAY_300 = "\e[38;5;244m".freeze |
|||
TEXT_GRAY_200 = "\e[38;5;249m".freeze |
|||
TEXT_GRAY_100 = "\e[38;5;252m".freeze |
|||
|
|||
# DARK TEXT |
|||
DARK_TEXT_BLACK = "\e[90m".freeze |
|||
DARK_TEXT_RED = "\e[91m".freeze |
|||
DARK_TEXT_GREEN = "\e[92m".freeze |
|||
DARK_TEXT_YELLOW = "\e[93m".freeze |
|||
DARK_TEXT_BLUE = "\e[94m".freeze |
|||
DARK_TEXT_MAGENTA = "\e[95m".freeze |
|||
DARK_TEXT_CYAN = "\e[96m".freeze |
|||
DARK_TEXT_WHITE = "\e[97m".freeze |
|||
|
|||
# BACKGROUND |
|||
BG_BLACK = "\e[40m".freeze |
|||
BG_WHITE = "\e[47m".freeze |
|||
BG_GRAY = "\e[100m".freeze |
|||
BG_RED = "\e[41m".freeze |
|||
BG_GREEN = "\e[42m".freeze |
|||
BG_YELLOW = "\e[43m".freeze |
|||
BG_BLUE = "\e[44m".freeze |
|||
BG_MAGENTA = "\e[45m".freeze |
|||
BG_CYAN = "\e[46m".freeze |
|||
|
|||
# DARK BACKGROUND |
|||
DARK_BG_RED = "\e[101m".freeze |
|||
DARK_BG_GREEN = "\e[102m".freeze |
|||
DARK_BG_YELLOW = "\e[103m".freeze |
|||
DARK_BG_BLUE = "\e[104m".freeze |
|||
DARK_BG_MAGENTA = "\e[105m".freeze |
|||
DARK_BG_CYAN = "\e[106m".freeze |
|||
end |
@ -0,0 +1,53 @@ |
|||
require_relative 'ansi_wrapper' |
|||
require_relative 'ansi_colors' |
|||
|
|||
require 'io/console' |
|||
require 'amazing_print' |
|||
require 'json' |
|||
|
|||
class AnsiFormatter < SemanticLogger::Formatters::Color |
|||
include AnsiColors |
|||
|
|||
ANSI_DEBUG = CLEAR + TEXT_CYAN |
|||
ANSI_INFO = CLEAR + TEXT_WHITE |
|||
ANSI_WARN = BG_YELLOW + TEXT_BLACK |
|||
ANSI_ERROR = BG_RED + TEXT_BLACK |
|||
ANSI_FATAL = DARK_BG_RED + TEXT_BLACK |
|||
|
|||
def initialize |
|||
super(color_map: ColorMap.new( |
|||
debug: ANSI_DEBUG, |
|||
info: ANSI_INFO, |
|||
warn: ANSI_WARN, |
|||
error: ANSI_ERROR, |
|||
fatal: ANSI_FATAL |
|||
)) |
|||
end |
|||
|
|||
def message |
|||
return unless log.message |
|||
|
|||
colorize(log.message, color_map[log.level]) |
|||
end |
|||
|
|||
def call(log, logger) |
|||
self.log = log |
|||
self.logger = logger |
|||
self.color = color_map[log.level] |
|||
wrap_level(level, message, payload, exception) |
|||
end |
|||
|
|||
private |
|||
|
|||
def colorize(text, color) |
|||
"#{color}#{text}#{color_map.clear}" |
|||
end |
|||
|
|||
def wrap_level(level, *items) |
|||
prefix = " #{colorize('>', color)} " |
|||
continuation = " #{colorize('#', color)} " |
|||
items.map do |item| |
|||
AnsiWrapper.wrap(item, 100, prefix, continuation) |
|||
end.compact.join("\n") # FIXME: previously was: join(' ') |
|||
end |
|||
end |
@ -0,0 +1,78 @@ |
|||
# AnsiWrapper cares about Ansi Colour Code \e[... |
|||
class AnsiWrapper |
|||
TAB_TO_SPACES = 2 |
|||
ANSI_REGEX = /\e\[[0-9;]*m/ # TODO: support for \x1b and \033 |
|||
ANSI_RESET = "\e[0m".freeze |
|||
|
|||
def self.wrap(text, length, prefix = '', continuation = prefix) |
|||
if prefix.length != continuation.length |
|||
raise "continuation <#{continuation}> should have the same length as prefix <#{prefix}>" |
|||
end |
|||
return unless text |
|||
|
|||
text = text.gsub("\t", ' ' * TAB_TO_SPACES) |
|||
|
|||
lines = split_text_to_lines(text, length - prefix.length) |
|||
lines = inject_continuation_and_ansi_colors_to_lines(lines, prefix, continuation) |
|||
lines.join("\n") |
|||
end |
|||
|
|||
private_class_method def self.inject_continuation_and_ansi_colors_to_lines(lines, prefix, continuation) |
|||
last_ansi = '' |
|||
lines.each_with_index.map do |line, index| |
|||
current = index.zero? ? prefix : continuation |
|||
current += last_ansi unless last_ansi.empty? || last_ansi == ANSI_RESET |
|||
current += line |
|||
|
|||
last_ansi = scan_for_actual_ansi(line, last_ansi) |
|||
|
|||
current += ANSI_RESET if last_ansi.empty? || last_ansi != ANSI_RESET |
|||
current |
|||
end |
|||
end |
|||
|
|||
private_class_method def self.scan_for_actual_ansi(line, last_ansi) |
|||
line.scan(ANSI_REGEX).each do |match| |
|||
ansi_code = match.to_s |
|||
if ansi_code == ANSI_RESET |
|||
last_ansi = ANSI_RESET |
|||
else |
|||
last_ansi += ansi_code |
|||
end |
|||
end |
|||
last_ansi |
|||
end |
|||
|
|||
private_class_method def self.split_text_to_lines(text, length) |
|||
lines = text.split("\n") |
|||
sublines = lines.map do |line| |
|||
visible_length(line) > length ? visible_split(line, length) : [line] |
|||
end |
|||
sublines.flatten |
|||
end |
|||
|
|||
private_class_method def self.visible_length(line) |
|||
raise 'line should not contain carriage return character!' if line.match "\n" |
|||
|
|||
ansi_code_length = line.scan(ANSI_REGEX).map(&:length).sum |
|||
line.length - ansi_code_length |
|||
end |
|||
|
|||
# TODO: might be refactored with less complexity |
|||
private_class_method def self.visible_split(line, length, stack = '') # rubocop:disable Metrics/AbcSize,Metrics/MethodLength |
|||
before, ansi_code, after = line.partition(ANSI_REGEX) |
|||
stack_length = visible_length(stack) |
|||
visible_length = before.length + stack_length |
|||
if visible_length == length |
|||
["#{stack}#{before}#{ansi_code}"] + visible_split(after, length) |
|||
elsif visible_length > length |
|||
first_line = stack + before[0...length - stack_length] |
|||
tail = before[length - stack_length..] + ansi_code + after |
|||
[first_line] + visible_split(tail, length) |
|||
elsif ansi_code.length.positive? |
|||
visible_split(after, length, "#{stack}#{before}#{ansi_code}") |
|||
else |
|||
["#{stack}#{before}#{ansi_code}"] |
|||
end |
|||
end |
|||
end |
Write
Preview
Loading…
Cancel
Save
Reference in new issue