|
@ -1,8 +1,6 @@ |
|
|
# AnsiWrapper cares about Ansi Colour Code \e[... |
|
|
# AnsiWrapper cares about Ansi Colour Code \e[... |
|
|
class AnsiWrapper |
|
|
class AnsiWrapper |
|
|
TAB_TO_SPACES = 2 |
|
|
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) |
|
|
def self.wrap(text, length, prefix = '', continuation = prefix) |
|
|
if visible_length(prefix) != visible_length(continuation) |
|
|
if visible_length(prefix) != visible_length(continuation) |
|
@ -21,21 +19,21 @@ class AnsiWrapper |
|
|
last_ansi = '' |
|
|
last_ansi = '' |
|
|
lines.each_with_index.map do |line, index| |
|
|
lines.each_with_index.map do |line, index| |
|
|
current = index.zero? ? prefix : continuation |
|
|
current = index.zero? ? prefix : continuation |
|
|
current += last_ansi unless last_ansi.empty? || last_ansi == ANSI_RESET |
|
|
|
|
|
|
|
|
current += last_ansi unless last_ansi.empty? || last_ansi == AnsiColors::CLEAR |
|
|
current += line |
|
|
current += line |
|
|
|
|
|
|
|
|
last_ansi = scan_for_actual_ansi(line, last_ansi) |
|
|
last_ansi = scan_for_actual_ansi(line, last_ansi) |
|
|
|
|
|
|
|
|
current += ANSI_RESET if last_ansi.empty? || last_ansi != ANSI_RESET |
|
|
|
|
|
|
|
|
current += AnsiColors::CLEAR if last_ansi.empty? || last_ansi != AnsiColors::CLEAR |
|
|
current |
|
|
current |
|
|
end |
|
|
end |
|
|
end |
|
|
end |
|
|
|
|
|
|
|
|
private_class_method def self.scan_for_actual_ansi(line, last_ansi) |
|
|
private_class_method def self.scan_for_actual_ansi(line, last_ansi) |
|
|
line.scan(ANSI_REGEX).each do |match| |
|
|
|
|
|
|
|
|
line.scan(AnsiCommon::ANSI_REGEX).each do |match| |
|
|
ansi_code = match.to_s |
|
|
ansi_code = match.to_s |
|
|
if ansi_code == ANSI_RESET |
|
|
|
|
|
last_ansi = ANSI_RESET |
|
|
|
|
|
|
|
|
if ansi_code == AnsiColors::CLEAR |
|
|
|
|
|
last_ansi = AnsiColors::CLEAR |
|
|
else |
|
|
else |
|
|
last_ansi += ansi_code |
|
|
last_ansi += ansi_code |
|
|
end |
|
|
end |
|
@ -54,13 +52,13 @@ class AnsiWrapper |
|
|
private_class_method def self.visible_length(line) |
|
|
private_class_method def self.visible_length(line) |
|
|
raise 'line should not contain carriage return character!' if line.match "\n" |
|
|
raise 'line should not contain carriage return character!' if line.match "\n" |
|
|
|
|
|
|
|
|
ansi_code_length = line.scan(ANSI_REGEX).map(&:length).sum |
|
|
|
|
|
|
|
|
ansi_code_length = line.scan(AnsiCommon::ANSI_REGEX).map(&:length).sum |
|
|
line.length - ansi_code_length |
|
|
line.length - ansi_code_length |
|
|
end |
|
|
end |
|
|
|
|
|
|
|
|
# TODO: might be refactored with less complexity |
|
|
# TODO: might be refactored with less complexity |
|
|
private_class_method def self.visible_split(line, length, stack = '') # rubocop:disable Metrics/AbcSize,Metrics/MethodLength |
|
|
private_class_method def self.visible_split(line, length, stack = '') # rubocop:disable Metrics/AbcSize,Metrics/MethodLength |
|
|
before, ansi_code, after = line.partition(ANSI_REGEX) |
|
|
|
|
|
|
|
|
before, ansi_code, after = line.partition(AnsiCommon::ANSI_REGEX) |
|
|
stack_length = visible_length(stack) |
|
|
stack_length = visible_length(stack) |
|
|
visible_length = before.length + stack_length |
|
|
visible_length = before.length + stack_length |
|
|
if visible_length == length |
|
|
if visible_length == length |
|
|