Skip to content

Commit

Permalink
Fix highlighting display with unicode chars
Browse files Browse the repository at this point in the history
  • Loading branch information
Keluaa committed Jun 15, 2024
1 parent 63c34fc commit f874b09
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 30 deletions.
16 changes: 10 additions & 6 deletions src/CodeDiff.jl
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,11 @@ Fancy REPL output is done with [`side_by_side_diff`](@ref).
struct CodeDiff <: DeepDiffs.DeepDiff
before::String
after::String
changed::Dict{Int, Tuple{Vector{Int}, DeepDiffs.StringDiff}} # line idx => (line idxs added before the change, change diff)
ignore_added::Set{Int} # Line idxs which are part of `changed`, including line idxs added before changes
# line idx => (line idxs added before the change, line after change, change diff)
changed::Dict{Int, Tuple{Vector{Int}, Int, DeepDiffs.StringDiff}}
# Line idxs which are part of `changed`, including line idxs added before changes
ignore_added::Set{Int}
# Line by line diff, without highlighting
diff::DeepDiffs.VectorDiff
highlighted_before::String
highlighted_after::String
Expand Down Expand Up @@ -67,7 +70,7 @@ function Base.show(io::IO, diff::CodeDiff)
printstyled(io, "~ ", color=:yellow)
io_buf = IOBuffer()
io_ctx = IOContext(io_buf, io)
Base.show(io_ctx, diff.changed[idx][2])
Base.show(io_ctx, diff.changed[idx][3])
printstyled(io, String(take!(io_buf))[2:end-1]) # unquote the line diff
else
print(io, " ", xlines[idx])
Expand Down Expand Up @@ -105,8 +108,9 @@ function optimize_line_changes!(diff::CodeDiff; dist=StringDistances.Levenshtein
changed = false
for (li, removed_line) in enumerate(previously_removed[removed_start:end])
if StringDistances.compare(xlines[removed_line], ylines[idx], dist) tol
# `(lines added before this changed line, change diff)`
diff.changed[removed_line] = (copy(added_before), DeepDiffs.deepdiff(xlines[removed_line], ylines[idx]))
# `(lines added before this changed line, ylines idx, change diff)`
diff.changed[removed_line] =
(copy(added_before), idx, DeepDiffs.deepdiff(xlines[removed_line], ylines[idx]))
if !isempty(added_before)
push!(diff.ignore_added, added_before...)
empty!(added_before)
Expand Down Expand Up @@ -134,7 +138,7 @@ function DeepDiffs.visitall(f, diff::CodeDiff)
DeepDiffs.visitall(diff.diff) do idx, state, last
if state == :removed
if haskey(diff.changed, idx)
added_lines_before, _ = diff.changed[idx]
added_lines_before, _, _ = diff.changed[idx]
for line_idx in added_lines_before
f(line_idx, :added, false)
end
Expand Down
55 changes: 33 additions & 22 deletions src/display.jl
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,9 @@ function print_columns(io, width, left_line, sep, right_line, empty_line, tab_re
end


function print_columns_change(io, width, line_diff, highlighted_left, sep, empty_line, tab_replacement)
function print_columns_change(
io, width, line_diff, highlighted_left, highlighted_right, sep, empty_line, tab_replacement
)
wio = TextWidthLimiter(IOBuffer(), width)
wio_ctx = IOContext(wio, io)

Expand All @@ -52,7 +54,7 @@ function print_columns_change(io, width, line_diff, highlighted_left, sep, empty

printstyled(io, sep)

printstyled_code_line_diff(wio_ctx, line_diff, highlighted_left, false, tab_replacement)
printstyled_code_line_diff(wio_ctx, line_diff, highlighted_right, false, tab_replacement)
right_len = wio.width
printstyled(io, String(take!(wio)))
if right_len < width
Expand All @@ -62,8 +64,8 @@ function print_columns_change(io, width, line_diff, highlighted_left, sep, empty
end


function next_ansi_sequence(str, idx, str_len)
m = (1 idx str_len) ? match(ANSI_REGEX, str, idx) : nothing
function next_ansi_sequence(str, idx)
m = (1 idx ncodeunits(str)) ? match(ANSI_REGEX, str, idx) : nothing
if m === nothing
return typemax(idx), ""
else
Expand All @@ -82,9 +84,10 @@ const ANSI_GREEN_FGR = "\e[32m"


function printstyled_code_line_diff(
io::IO, diff::DeepDiffs.StringDiff, highlighted_left, removed_only::Bool,
io::IO, diff::DeepDiffs.StringDiff, highlighted_side, removed_only::Bool,
tab_replacement
)
# Vectors of `Char`
xchars = DeepDiffs.before(diff.diff)
ychars = DeepDiffs.after(diff.diff)

Expand All @@ -98,38 +101,46 @@ function printstyled_code_line_diff(
added_bkg_color = ""
end

hl_length = length(highlighted_left)
idx_before_next_ansi, ansi_seq = next_ansi_sequence(highlighted_left, 1, hl_length)
idx_before_next_ansi, ansi_seq = next_ansi_sequence(highlighted_side, 1)
highlighted_offset = 0
cu_idx = 0

full_tab_len = length(tab_replacement)
column_pos = 1
tmp_io = IOBuffer()
prev_state = :same
DeepDiffs.visitall(diff.diff) do idx, state, _
if idx + highlighted_offset idx_before_next_ansi
write(tmp_io, ansi_seq)
if prev_state !== :same && occursin("\e[0m", ansi_seq)
prev_state = :same
end
highlighted_offset += length(ansi_seq)
idx_before_next_ansi, ansi_seq =
next_ansi_sequence(highlighted_left, idx + highlighted_offset, hl_length)
end
# `idx` is a character index, not a code unit index

if state === :removed
!removed_only && return
prev_state !== :removed && write(tmp_io, removed_bkg_color)
c = xchars[idx]
elseif state === :added
removed_only && return
prev_state !== :added && write(tmp_io, added_bkg_color)
c = ychars[idx]
else
prev_state !== :same && write(tmp_io, default_bkg)
c = xchars[idx]
end

cu_idx += ncodeunits(c) # `cu_idx` is `idx` in code units

if cu_idx + highlighted_offset idx_before_next_ansi
write(tmp_io, ansi_seq)
if prev_state !== :same && occursin("\e[0m", ansi_seq)
prev_state = :same # this will make sure the next char will have the right background
end
highlighted_offset += ncodeunits(ansi_seq)
idx_before_next_ansi, ansi_seq =
next_ansi_sequence(highlighted_side, idx_before_next_ansi + ncodeunits(ansi_seq))
end

if state !== prev_state
if state === :removed write(tmp_io, removed_bkg_color)
elseif state === :added write(tmp_io, added_bkg_color)
else#= state === :same =# write(tmp_io, default_bkg)
end
end

if c == '\t'
tab_len = full_tab_len - mod(column_pos - 1, full_tab_len)
write(tmp_io, @view(tab_replacement[1:tab_len]))
Expand All @@ -143,7 +154,7 @@ function printstyled_code_line_diff(
end

prev_state !== :same && write(tmp_io, default_bkg)
write(tmp_io, @view highlighted_left[idx_before_next_ansi:end])
write(tmp_io, @view highlighted_side[idx_before_next_ansi:end])

printstyled(io, String(take!(tmp_io)))
end
Expand Down Expand Up @@ -230,8 +241,8 @@ function side_by_side_diff(io::IO, diff::CodeDiff; tab_width=4, width=nothing, l
print_line_num(:right)
elseif state === :changed
print_line_num(:left)
_, line_diff = diff.changed[idx]
print_columns_change(io, column_width, line_diff, xlines[idx], sep_changed_to, empty_column, tab)
_, y_idx, line_diff = diff.changed[idx]
print_columns_change(io, column_width, line_diff, xlines[idx], ylines[y_idx], sep_changed_to, empty_column, tab)
print_line_num(:right)
else
print_line_num(:left)
Expand Down
2 changes: 1 addition & 1 deletion test/references/a_vs_b_COLOR.jl_ast
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@
 f(a, b) ⟪╋⟫ f(a, d)
 g(c, d) ⟪╋⟫ g(c, b)
  ┣⟫ h(x, y)
 "test" ⟪╋⟫ "test2"
 "test" ⟪╋⟫ "test2"
end  ┃ end
2 changes: 1 addition & 1 deletion test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ function check_diff_display_order(diff::CodeDiffs.CodeDiff, order::Vector{<:Pair
@test first(order[order_idx]) === nothing
@test occursin(last(order[order_idx]), ylines[idx])
elseif state === :changed
line_diff = diff.changed[idx][2]
line_diff = diff.changed[idx][3]
@test occursin(first(order[order_idx]), line_diff.before)
@test occursin(last(order[order_idx]), line_diff.after)
else
Expand Down

0 comments on commit f874b09

Please sign in to comment.