Add support for showing code context lines (#181)

* Add support for showing code context lines

* Show context lines only in ExplainFormatter

* Add spec coverage for context_lines option
This commit is contained in:
Sijawusz Pur Rahnama 2021-01-12 16:20:43 +01:00 committed by GitHub
parent 9bc6c13d11
commit c4d34d74d8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 96 additions and 13 deletions

View file

@ -22,7 +22,38 @@ module Ameba::Formatter
a = 1
)
location = Crystal::Location.new("filename", 1, 1)
subject.affected_code(source, location).should eq "> a = 1\n \e[33m^\e[0m"
subject.deansify(subject.affected_code(source, location))
.should eq "> a = 1\n ^"
end
it "returns correct line if it is found" do
source = Source.new <<-EOF
# pre:1
# pre:2
# pre:3
# pre:4
# pre:5
a = 1
# post:1
# post:2
# post:3
# post:4
# post:5
EOF
location = Crystal::Location.new("filename", 6, 1)
subject.deansify(subject.affected_code(source, location, context_lines: 3))
.should eq <<-STR
> # pre:3
> # pre:4
> # pre:5
> a = 1
^
> # post:1
> # post:2
> # post:3
STR
end
end
end

View file

@ -49,7 +49,7 @@ module Ameba::Formatter
@location.to_s.colorize(:cyan).to_s,
]
if affected_code = affected_code(source, @location)
if affected_code = affected_code(source, @location, context_lines: 3)
output_title "AFFECTED CODE"
output_paragraph affected_code
end

View file

@ -1,22 +1,74 @@
module Ameba::Formatter
module Util
def affected_code(source, location, max_length = 100, placeholder = " ...", prompt = "> ")
line, column = location.line_number, location.column_number
affected_line = source.lines[line - 1]?.presence
def deansify(message : String?) : String?
message.try &.gsub(/\x1b[^m]*m/, "").presence
end
return unless affected_line
def affected_code(source, location, context_lines = 0, max_length = 100, placeholder = " ...", prompt = "> ")
lines = source.lines
lineno, column =
location.line_number, location.column_number
if affected_line.size > max_length && column < max_length
affected_line = affected_line[0, max_length - placeholder.size - 1] + placeholder
return unless affected_line = lines[lineno - 1]?.presence
trim_line = Proc(String, String).new do |line|
if line.size > max_length
line = line[0, max_length - placeholder.size - 1] + placeholder
end
line
end
stripped = affected_line.lstrip
position = column - (affected_line.size - stripped.size) + prompt.size
if column < max_length
affected_line = trim_line.call(affected_line)
end
show_context = context_lines > 0
if show_context
pre_context, post_context = %w[], %w[]
lines.each_with_index do |line, i|
case i + 1
when lineno - context_lines...lineno
pre_context << trim_line.call(line)
when lineno
#
when lineno + 1..lineno + context_lines
post_context << trim_line.call(line)
end
end
# remove empty lines at the beginning/end
pre_context.shift? unless pre_context.first?.presence
post_context.pop? unless post_context.last?.presence
end
String.build do |str|
str << prompt << stripped << '\n'
str << " " * (position - 1)
str << "^".colorize(:yellow)
if show_context
pre_context.try &.each do |line|
str << prompt
str.puts(line.colorize(:dark_gray))
end
str << prompt
str.puts(affected_line.colorize(:white))
str << " " * (prompt.size + column - 1)
str.puts("^".colorize(:yellow))
post_context.try &.each do |line|
str << prompt
str.puts(line.colorize(:dark_gray))
end
else
stripped = affected_line.lstrip
position = column - (affected_line.size - stripped.size) + prompt.size
str << prompt
str.puts(stripped)
str << " " * (position - 1)
str << "^".colorize(:yellow)
end
end
end
end