Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ci fixes #2

Merged
merged 10 commits into from
Apr 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 10 additions & 3 deletions .github/workflows/CI.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ jobs:
matrix:
version:
- '1.10'
- '1.6'
- '1.7'
- 'nightly'
os:
- ubuntu-latest
Expand All @@ -40,12 +40,18 @@ jobs:
- uses: julia-actions/julia-buildpkg@v1
- uses: julia-actions/julia-runtest@v1
- uses: julia-actions/julia-processcoverage@v1
- uses: codecov/codecov-action@v3
- uses: codecov/codecov-action@v4
with:
files: lcov.info
docs:
name: Documentation
runs-on: ubuntu-latest
runs-on: ${{ matrix.os }}
strategy:
matrix:
os:
- ubuntu-latest
arch:
- x64
permissions:
actions: write # needed to allow julia-actions/cache to proactively delete old caches that it has created
contents: write
Expand All @@ -55,6 +61,7 @@ jobs:
- uses: julia-actions/setup-julia@v1
with:
version: '1'
arch: ${{ matrix.arch }}
- uses: julia-actions/cache@v1
- name: Configure doc environment
shell: julia --project=docs --color=yes {0}
Expand Down
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ ReferenceTests = "0.10"
StringDistances = "0.11"
Test = "1"
WidthLimitedIO = "1"
julia = "1.6"
julia = "1.7"

[extras]
Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595"
Expand Down
8 changes: 2 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,33 +9,29 @@
Compare code and display the difference in the terminal side-by-side.
Supports syntax highlighting.

The [`@code_diff`](@ref) macro is the main entry point. If possible, the code type will be
The `@code_diff` macro is the main entry point. If possible, the code type will be
detected automatically, otherwise add e.g. `type=:native` for native assembly comparison:
```julia
julia> f1(a) = a + 1
f1 (generic function with 1 method)

julia> @code_diff type=:llvm debuginfo=:none f1(Int64(1)) f1(Int8(1))
; Function Attrs: uwtable ┃ ; Function Attrs: uwtable
define i64 @f1(i64 signext %0) #0 { ⟪╋⟫define i64 @f1(i8 signext %0) #0 {
top: ┃ top:
┣⟫ %1 = sext i8 %0 to i64
%1 = add i64 %0, 1 ⟪╋⟫ %2 = add nsw i64 %1, 1
ret i64 %1 ⟪╋⟫ ret i64 %2
┣⟫ %1 = sext i8 %0 to i64
} ┃ }

julia> f2(a) = a - 1
f2 (generic function with 1 method)

julia> @code_diff type=:llvm debuginfo=:none f1(1) f2(1)
; Function Attrs: uwtable ┃ ; Function Attrs: uwtable
define i64 @f1(i64 signext %0) #0 { ⟪╋⟫define i64 @f2(i64 signext %0) #0 {
top: ┃ top:
%1 = add i64 %0, 1 ⟪╋⟫ %1 = add i64 %0, -1
ret i64 %1 ┃ ret i64 %1
} ┃ }
```

## Supported languages
Expand Down
3 changes: 3 additions & 0 deletions docs/make.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ using Documenter

DocMeta.setdocmeta!(CodeDiffs, :DocTestSetup, :(using CodeDiffs); recursive=true)

can_doctest = Sys.islinux() && Sys.ARCH === :x86_84

makedocs(;
modules=[CodeDiffs],
authors="Luc Briand <[email protected]> and contributors",
Expand All @@ -15,6 +17,7 @@ makedocs(;
pages=[
"Home" => "index.md",
],
doctest = can_doctest
)

deploydocs(;
Expand Down
6 changes: 1 addition & 5 deletions docs/src/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,26 +23,22 @@ julia> f1(a) = a + 1
f1 (generic function with 1 method)

julia> @code_diff type=:llvm debuginfo=:none color=false f1(Int64(1)) f1(Int8(1))
; Function Attrs: uwtable ┃ ; Function Attrs: uwtable
define i64 @f1(i64 signext %0) #0 { ⟪╋⟫define i64 @f1(i8 signext %0) #0 {
top: ┃ top:
┣⟫ %1 = sext i8 %0 to i64
%1 = add i64 %0, 1 ⟪╋⟫ %2 = add nsw i64 %1, 1
ret i64 %1 ⟪╋⟫ ret i64 %2
┣⟫ %1 = sext i8 %0 to i64
} ┃ }

julia> f2(a) = a - 1
f2 (generic function with 1 method)

julia> @code_diff type=:llvm debuginfo=:none color=false f1(1) f2(1)
; Function Attrs: uwtable ┃ ; Function Attrs: uwtable
define i64 @f1(i64 signext %0) #0 { ⟪╋⟫define i64 @f2(i64 signext %0) #0 {
top: ┃ top:
%1 = add i64 %0, 1 ⟪╋⟫ %1 = add i64 %0, -1
ret i64 %1 ┃ ret i64 %1
} ┃ }
```

Setting the environment variable `"CODE_DIFFS_LINE_NUMBERS"` to `true` will display line
Expand Down
1 change: 1 addition & 0 deletions generated.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
test/reference/** linguist-generated
49 changes: 43 additions & 6 deletions src/CodeDiff.jl
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ Fancy REPL output is done with [`side_by_side_diff`](@ref).
struct CodeDiff <: DeepDiffs.DeepDiff
before::String
after::String
changed::Dict{Int, DeepDiffs.StringDiff}
ignore_added::Set{Int}
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
diff::DeepDiffs.VectorDiff
highlighted_before::String
highlighted_after::String
Expand Down Expand Up @@ -58,11 +58,17 @@ Base.show(io::IO, ::MIME"text/plain", diff::CodeDiff) = side_by_side_diff(io, di
function Base.show(io::IO, diff::CodeDiff)
xlines = split(diff.before, '\n')
ylines = split(diff.after, '\n')
DeepDiffs.visitall(diff.diff) do idx, state, last
if state == :removed
DeepDiffs.visitall(diff) do idx, state, last
if state === :removed
printstyled(io, "- ", xlines[idx], color=:red)
elseif state == :added
elseif state === :added
printstyled(io, "+ ", ylines[idx], color=:green)
elseif state === :changed
printstyled(io, "~ ", color=:yellow)
io_buf = IOBuffer()
io_ctx = IOContext(io_buf, io)
Base.show(io_ctx, diff.changed[idx][2])
printstyled(io, String(take!(io_buf))[2:end-1]) # unquote the line diff
else
print(io, " ", xlines[idx])
end
Expand All @@ -86,6 +92,7 @@ function optimize_line_changes!(diff::CodeDiff; dist=StringDistances.Levenshtein
empty!(diff.changed)
empty!(diff.ignore_added)
previously_removed = Vector{Int}()
added_before = Vector{Int}()
removed_start = 1
iadded = 1

Expand All @@ -95,20 +102,50 @@ function optimize_line_changes!(diff::CodeDiff; dist=StringDistances.Levenshtein
push!(previously_removed, idx)
elseif state == :added
iadded += 1
changed = false
for (li, removed_line) in enumerate(previously_removed[removed_start:end])
if StringDistances.compare(xlines[removed_line], ylines[idx], dist) ≥ tol
diff.changed[removed_line] = DeepDiffs.deepdiff(xlines[removed_line], ylines[idx])
# `(lines added before this changed line, change diff)`
diff.changed[removed_line] = (copy(added_before), DeepDiffs.deepdiff(xlines[removed_line], ylines[idx]))
if !isempty(added_before)
push!(diff.ignore_added, added_before...)
empty!(added_before)
end
push!(diff.ignore_added, idx)
removed_start += li # The next added lines will start from the next removed line
changed = true
break
end
end
!changed && push!(added_before, idx)
else
# Treat conserved lines as a "reset" point
empty!(previously_removed)
empty!(added_before)
removed_start = 1
end
end

return diff
end


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]
for line_idx in added_lines_before
f(line_idx, :added, false)
end
f(idx, :changed, last)
else
f(idx, :removed, last)
end
elseif state == :added
idx ∉ diff.ignore_added && f(idx, state, last)
else
f(idx, state, last)
end
end
end
17 changes: 16 additions & 1 deletion src/compare.jl
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,13 @@ function compare_code(code₁::AbstractString, code₂::AbstractString, highligh
code₂_colored = code₂
end

if endswith(code₁, '\n') && endswith(code₂, '\n')
code₁ = rstrip(==('\n'), code₁)
code₁_colored = rstrip(==('\n'), code₁_colored)
code₂ = rstrip(==('\n'), code₂)
code₂_colored = rstrip(==('\n'), code₂_colored)
end

diff = CodeDiff(code₁, code₂, code₁_colored, code₂_colored)
optimize_line_changes!(diff)
return diff
Expand Down Expand Up @@ -130,6 +137,13 @@ function compare_show(code₁, code₂; color=true, force_no_ansi=false)
code₂_colored = code_str₂
end

if endswith(code_str₁, '\n') && endswith(code_str₂, '\n')
code_str₁ = rstrip(==('\n'), code_str₁)
code₁_colored = rstrip(==('\n'), code₁_colored)
code_str₂ = rstrip(==('\n'), code_str₂)
code₂_colored = rstrip(==('\n'), code₂_colored)
end

diff = CodeDiff(code_str₁, code_str₂, code₁_colored, code₂_colored)
optimize_line_changes!(diff)
return diff
Expand Down Expand Up @@ -488,7 +502,8 @@ might be inferred automatically.
"""
macro code_diff(args...)
length(args) < 2 && throw(ArgumentError("@code_diff takes at least 2 arguments"))
options..., code₁, code₂ = args
options = args[1:end-2]
code₁, code₂ = args[end-1:end]

options = map(options) do option
!(option isa Expr && option.head === :(=)) &&
Expand Down
61 changes: 29 additions & 32 deletions src/display.jl
Original file line number Diff line number Diff line change
Expand Up @@ -128,12 +128,14 @@ Side by side display of a [`CodeDiff`](@ref) to `io` (defaults to `stdout`).
environment variable `"CODE_DIFFS_LINE_NUMBERS"`, which itself defaults to `false`.
"""
function side_by_side_diff(io::IO, diff::CodeDiff; tab_width=4, width=nothing, line_numbers=nothing)
line_numbers = @something line_numbers parse(Bool, get(ENV, "CODE_DIFFS_LINE_NUMBERS", "false"))
line_numbers = !isnothing(line_numbers) ? line_numbers : parse(Bool, get(ENV, "CODE_DIFFS_LINE_NUMBERS", "false"))

# TODO: `tab_width` shouldn't simply replace '\t' by spaces, but rather pad mod `tab_width`

xlines = split(diff.highlighted_before, '\n')
ylines = split(diff.highlighted_after, '\n')

width = @something width displaysize(io)[2]
width = !isnothing(width) ? width : displaysize(io)[2]
if line_numbers
max_line = length(xlines) + length(DeepDiffs.added(diff))
line_num_width = length(string(max_line))
Expand All @@ -156,42 +158,37 @@ function side_by_side_diff(io::IO, diff::CodeDiff; tab_width=4, width=nothing, l

left_line = 1
right_line = 1
DeepDiffs.visitall(diff.diff) do idx, state, last
if line_numbers
if state !== :added
line_num = lpad(string(left_line), line_num_width)
printstyled(io, line_num, ' '; color=:light_black)
left_line += 1
end
end

right_printed = true
if state == :removed
if haskey(diff.changed, idx)
line_diff = diff.changed[idx]
print_columns_change(io, column_width, line_diff, xlines[idx],
sep_changed_to, empty_column, tab)
else
print_columns(io, column_width, xlines[idx], sep_removed, "", empty_column, tab)
right_printed = false
end
elseif state == :added
if idx ∈ diff.ignore_added
return
else
printstyled(io, empty_line_num)
print_columns(io, column_width, "", sep_added, ylines[idx], empty_column, tab)
end
function print_line_num(side)
!line_numbers && return
if side === :left
line_num = lpad(string(left_line), line_num_width)
printstyled(io, line_num, ' '; color=:light_black)
left_line += 1
else
print_columns(io, column_width, xlines[idx], sep_same, xlines[idx], empty_column, tab)
end

if line_numbers && right_printed
line_num = rpad(string(right_line), line_num_width)
printstyled(io, line_num; color=:light_black)
right_line += 1
end
end

DeepDiffs.visitall(diff) do idx, state, last
if state === :removed
print_line_num(:left)
print_columns(io, column_width, xlines[idx], sep_removed, "", empty_column, tab)
elseif state === :added
printstyled(io, empty_line_num)
print_columns(io, column_width, "", sep_added, ylines[idx], empty_column, tab)
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)
print_line_num(:right)
else
print_line_num(:left)
print_columns(io, column_width, xlines[idx], sep_same, xlines[idx], empty_column, tab)
print_line_num(:right)
end
!last && println(io)
end
end
Expand Down
8 changes: 8 additions & 0 deletions test/references/a_vs_b.jl_ast
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
quote ┃ quote
┣⟫ println("B")
1 + 2 ⟪╋⟫ 1 + 3
f(a, b) ⟪╋⟫ f(a, d)
g(c, d) ⟪╋⟫ g(c, b)
┣⟫ h(x, y)
"test" ⟪╋⟫ "test2"
end ┃ end
8 changes: 8 additions & 0 deletions test/references/a_vs_b_COLOR.jl_ast
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
 begin  ┃  begin
  ┣⟫ println("B")
 1 + 2 ⟪╋⟫ 1 + 3
 f(a, b) ⟪╋⟫ f(a, d)
 g(c, d) ⟪╋⟫ g(c, b)
  ┣⟫ h(x, y)
 "test" ⟪╋⟫ "test2"
 end  ┃  end
8 changes: 8 additions & 0 deletions test/references/a_vs_b_LINES.jl_ast
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
1 quote ┃ quote 1
┣⟫ println("B") 2
2 1 + 2 ⟪╋⟫ 1 + 3 3
3 f(a, b) ⟪╋⟫ f(a, d) 4
4 g(c, d) ⟪╋⟫ g(c, b) 5
┣⟫ h(x, y) 6
5 "test" ⟪╋⟫ "test2" 7
6 end ┃ end 8
8 changes: 8 additions & 0 deletions test/references/a_vs_b_PRINT.jl_ast
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
quote
+ println("B")
~ 1 + {-2-}{+3+}
~ f(a, {-b-}{+d+})
~ g(c, {-d-}{+b+})
+ h(x, y)
~ "test{+2+}"
end
3 changes: 0 additions & 3 deletions test/references/f1.jl_typed

This file was deleted.

3 changes: 0 additions & 3 deletions test/references/f1_COLOR.jl_typed

This file was deleted.

Loading
Loading