Skip to content

Commit

Permalink
Change undecorate to recognise nested colors and assign correct attri…
Browse files Browse the repository at this point in the history
…butes (closes #24)
  • Loading branch information
piotrmurach committed Jul 3, 2020
1 parent 79b50ce commit 446f7a1
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 10 deletions.
21 changes: 11 additions & 10 deletions lib/pastel/color_parser.rb
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,13 @@ def self.parse(text)
char = scanner.getch
# match control
if char == ESC && (delim = scanner.getch) == CSI
if scanner.scan(/^0m/)
if scanner.scan(/^0?m/) # reset
unpack_ansi(ansi_stack) { |attr, name| state[attr] = name }
ansi_stack = []
elsif scanner.scan(/^([1-9;:]+)m/)
# ansi codes separated by text
if !text_chunk.empty? && !ansi_stack.empty?
unpack_ansi(ansi_stack) { |attr, name| state[attr] = name }
ansi_stack = []
end
scanner[1].split(/:|;/).each do |code|
ansi_stack << code
Expand All @@ -74,7 +73,7 @@ def self.parse(text)
if !ansi_stack.empty?
unpack_ansi(ansi_stack) { |attr, name| state[attr] = name}
end
if state.values.any? { |val| !val.empty? }
if !state[:text].to_s.empty?
result.push(state)
end
result
Expand All @@ -89,10 +88,8 @@ def self.parse(text)
#
# @api private
def self.unpack_ansi(ansi_stack)
ansi_stack.each do |ansi|
name = ansi_for(ansi)
attr = attribute_for(ansi)
yield attr, name
ansi_stack.each do |code|
yield(attribute_name(code), color_name(code))
end
end

Expand All @@ -104,7 +101,7 @@ def self.unpack_ansi(ansi_stack)
# @return [Symbol]
#
# @api private
def self.attribute_for(ansi)
def self.attribute_name(ansi)
if ANSI.foreground?(ansi)
:foreground
elsif ANSI.background?(ansi)
Expand All @@ -114,9 +111,13 @@ def self.attribute_for(ansi)
end
end

# Convert ANSI code to color name
#
# @return [String]
#
# @api private
def self.ansi_for(ansi)
ATTRIBUTES.key(ansi.to_i)
def self.color_name(ansi_code)
ATTRIBUTES.key(ansi_code.to_i)
end
end # Parser
end # Pastel
40 changes: 40 additions & 0 deletions spec/unit/color_parser_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -64,4 +64,44 @@
{text: "\eA foo bar ESC\e"}
])
end

it "parses styles from parent text in nested text" do
pastel = Pastel.new
colored = pastel.bold.on_yellow("foo" + pastel.blue("bar") + "baz")
parsed = parser.parse(colored)

expect(parsed).to eq([
{text: "foo", style: :bold, background: :on_yellow},
{text: "bar", foreground: :blue, style: :bold, background: :on_yellow},
{text: "baz", style: :bold, background: :on_yellow}
])
end

it "parses color when overriden in nested text" do
pastel = Pastel.new
colored = pastel.yellow.on_red("foo" + pastel.green.bold.on_cyan("bar") + "baz")
parsed = parser.parse(colored)

expect(parsed).to eq([
{text: "foo", foreground: :yellow, background: :on_red},
{text: "bar", foreground: :green, style: :bold, background: :on_cyan},
{text: "baz", foreground: :yellow, background: :on_red}
])
end

it "parses colors nested with blocks" do
pastel = Pastel.new
colored = pastel.red.on_green("foo") do
green.on_red("bar ", "baz") do
yellow("qux")
end
end

parsed = parser.parse(colored)
expect(parsed).to eq([
{text: "foo", foreground: :red, background: :on_green},
{text: "bar baz", foreground: :green, background: :on_red},
{text: "qux", foreground: :yellow, background: :on_red}
])
end
end

0 comments on commit 446f7a1

Please sign in to comment.