-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
26 changed files
with
3,085 additions
and
33 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,14 +1,34 @@ | ||
name = "CodeDifferences" | ||
name = "CodeDiffs" | ||
uuid = "0d84036a-ccd8-408b-b2b2-9a2d9429e273" | ||
authors = ["Luc Briand <[email protected]> and contributors"] | ||
version = "1.0.0-DEV" | ||
|
||
[deps] | ||
DeepDiffs = "ab62b9b5-e342-54a8-a765-a90f495de1a6" | ||
InteractiveUtils = "b77e0a4c-d291-57a0-90e8-8db25a27a240" | ||
MacroTools = "1914dd2f-81c6-5fcd-8719-6d5c9610ff09" | ||
Markdown = "d6f4376e-aef5-505a-96c1-9c027394607a" | ||
StringDistances = "88034a9c-02f8-509d-84a9-84ec65e18404" | ||
WidthLimitedIO = "b8c1c048-cf81-46c6-9da0-18c1d99e41f2" | ||
|
||
[compat] | ||
Aqua = "0.7" | ||
DeepDiffs = "1" | ||
InteractiveUtils = "1" | ||
MacroTools = "0.5" | ||
Markdown = "1" | ||
ReferenceTests = "0.10" | ||
StringDistances = "0.11" | ||
Test = "1" | ||
WidthLimitedIO = "1" | ||
julia = "1.6" | ||
|
||
[extras] | ||
Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595" | ||
DeepDiffs = "ab62b9b5-e342-54a8-a765-a90f495de1a6" | ||
InteractiveUtils = "b77e0a4c-d291-57a0-90e8-8db25a27a240" | ||
ReferenceTests = "324d217c-45ce-50fc-942e-d289b448e8cf" | ||
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" | ||
|
||
[targets] | ||
test = ["Aqua", "Test"] | ||
test = ["Aqua", "InteractiveUtils", "ReferenceTests", "Test"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,46 @@ | ||
# CodeDifferences | ||
# CodeDiffs | ||
|
||
[![Stable](https://img.shields.io/badge/docs-stable-blue.svg)](https://Keluaa.github.io/CodeDifferences.jl/stable/) | ||
[![Dev](https://img.shields.io/badge/docs-dev-blue.svg)](https://Keluaa.github.io/CodeDifferences.jl/dev/) | ||
[![Build Status](https://github.com/Keluaa/CodeDifferences.jl/actions/workflows/CI.yml/badge.svg?branch=main)](https://github.com/Keluaa/CodeDifferences.jl/actions/workflows/CI.yml?query=branch%3Amain) | ||
[![Coverage](https://codecov.io/gh/Keluaa/CodeDifferences.jl/branch/main/graph/badge.svg)](https://codecov.io/gh/Keluaa/CodeDifferences.jl) | ||
[![Stable](https://img.shields.io/badge/docs-stable-blue.svg)](https://Keluaa.github.io/CodeDiffs.jl/stable/) | ||
[![Dev](https://img.shields.io/badge/docs-dev-blue.svg)](https://Keluaa.github.io/CodeDiffs.jl/dev/) | ||
[![Build Status](https://github.com/Keluaa/CodeDiffs.jl/actions/workflows/CI.yml/badge.svg?branch=main)](https://github.com/Keluaa/CodeDiffs.jl/actions/workflows/CI.yml?query=branch%3Amain) | ||
[![Coverage](https://codecov.io/gh/Keluaa/CodeDiffs.jl/branch/main/graph/badge.svg)](https://codecov.io/gh/Keluaa/CodeDiffs.jl) | ||
[![Aqua](https://raw.githubusercontent.com/JuliaTesting/Aqua.jl/master/badge.svg)](https://github.com/JuliaTesting/Aqua.jl) | ||
|
||
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 | ||
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 = 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 | ||
|
||
- native CPU assembly (output of `@code_native`) | ||
- LLVM IR (output of `@code_llvm`) | ||
- Typed Julia IR (output of `@code_typed`) | ||
- Julia AST (any `Expr`) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,6 @@ | ||
[deps] | ||
CodeDifferences = "0d84036a-ccd8-408b-b2b2-9a2d9429e273" | ||
CodeDiffs = "0d84036a-ccd8-408b-b2b2-9a2d9429e273" | ||
Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4" | ||
|
||
[compat] | ||
Documenter = "1" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,14 +1,14 @@ | ||
using CodeDifferences | ||
using CodeDiffs | ||
using Documenter | ||
|
||
DocMeta.setdocmeta!(CodeDifferences, :DocTestSetup, :(using CodeDifferences); recursive=true) | ||
DocMeta.setdocmeta!(CodeDiffs, :DocTestSetup, :(using CodeDiffs); recursive=true) | ||
|
||
makedocs(; | ||
modules=[CodeDifferences], | ||
modules=[CodeDiffs], | ||
authors="Luc Briand <[email protected]> and contributors", | ||
sitename="CodeDifferences.jl", | ||
sitename="CodeDiffs.jl", | ||
format=Documenter.HTML(; | ||
canonical="https://Keluaa.github.io/CodeDifferences.jl", | ||
canonical="https://Keluaa.github.io/CodeDiffs.jl", | ||
edit_link="main", | ||
assets=String[], | ||
), | ||
|
@@ -18,6 +18,6 @@ makedocs(; | |
) | ||
|
||
deploydocs(; | ||
repo="github.com/Keluaa/CodeDifferences.jl", | ||
repo="github.com/Keluaa/CodeDiffs.jl", | ||
devbranch="main", | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,14 +1,76 @@ | ||
```@meta | ||
CurrentModule = CodeDifferences | ||
CurrentModule = CodeDiffs | ||
``` | ||
|
||
# CodeDifferences | ||
# CodeDiffs | ||
|
||
Documentation for [CodeDifferences](https://github.com/Keluaa/CodeDifferences.jl). | ||
Compare different types of code and display it in the terminal. | ||
For cleaner results, syntax highlighting is separated from the difference calculation. | ||
|
||
```@index | ||
Supports: | ||
- native CPU assembly (output of `@code_native`, highlighted by `InteractiveUtils.print_native`) | ||
- LLVM IR (output of `@code_llvm`, highlighted by `InteractiveUtils.print_llvm`) | ||
- Typed Julia IR (output of `@code_typed`, highlighted through the `Base.show` method of `Core.CodeInfo`) | ||
- Julia AST (an `Expr`), highlighting is done with: | ||
- OhMyREPL.jl's Julia syntax highlighting in Markdown code blocks | ||
- (Julia ≥ v1.11) [JuliaSyntaxHighlighting.jl](https://github.com/JuliaLang/JuliaSyntaxHighlighting.jl) | ||
|
||
The [`@code_diff`](@ref) 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: | ||
|
||
```jldoctest; setup=:(using CodeDiffs) | ||
Check failure on line 21 in docs/src/index.md
|
||
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 = 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 | ||
} ┃ } | ||
┃ | ||
``` | ||
|
||
```@autodocs | ||
Modules = [CodeDifferences] | ||
Setting the environment variable `"CODE_DIFFS_LINE_NUMBERS"` to `true` will display line | ||
numbers on each side. | ||
|
||
# Main functions | ||
|
||
```@docs | ||
CodeDiff | ||
compare_code_native | ||
compare_code_llvm | ||
compare_code_typed | ||
compare_ast | ||
code_diff(::AbstractString, ::AbstractString) | ||
code_diff(::Markdown.MD, ::Markdown.MD) | ||
@code_diff | ||
``` | ||
|
||
# Display functions | ||
|
||
```@docs | ||
optimize_line_changes! | ||
replace_llvm_module_name | ||
side_by_side_diff | ||
``` | ||
|
||
# Internals | ||
|
||
```@docs | ||
LLVM_MODULE_NAME_REGEX | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
|
||
""" | ||
CodeDiff(code₁, code₂) | ||
CodeDiff(code₁, code₂, highlighted₁, highlighted₂) | ||
A difference between `code₁` and `code₂`. | ||
`code₁` and `code₂` should have no highlighting. Only `highlighted₁` and `highlighted₂` | ||
should have syntax highlighting. When showing the differences, their formatting will be | ||
re-applied. | ||
For cleaner differences, use [`replace_llvm_module_name`](@ref) on all codes. | ||
Use [`optimize_line_changes!`](@ref) to improve the difference. | ||
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} | ||
diff::DeepDiffs.VectorDiff | ||
highlighted_before::String | ||
highlighted_after::String | ||
end | ||
|
||
|
||
function CodeDiff( | ||
diff::DeepDiffs.StringLineDiff, | ||
highlighted_before::AbstractString, highlighted_after::AbstractString | ||
) | ||
return CodeDiff( | ||
diff.before, diff.after, Dict(), Set(), diff.diff, | ||
highlighted_before, highlighted_after | ||
) | ||
end | ||
|
||
function CodeDiff(X, Y, highlighted_X, highlighted_Y) | ||
return CodeDiff(DeepDiffs.deepdiff(X, Y), highlighted_X, highlighted_Y) | ||
end | ||
|
||
CodeDiff(X, Y) = CodeDiff(X, Y, X, Y) | ||
|
||
|
||
DeepDiffs.before(diff::CodeDiff) = diff.before | ||
DeepDiffs.after(diff::CodeDiff) = diff.after | ||
DeepDiffs.added(diff::CodeDiff) = DeepDiffs.added(diff.diff) | ||
DeepDiffs.removed(diff::CodeDiff) = DeepDiffs.removed(diff.diff) | ||
DeepDiffs.changed(diff::CodeDiff) = diff.changed | ||
|
||
issame(diff::CodeDiff) = isempty(DeepDiffs.added(diff)) && isempty(DeepDiffs.removed(diff)) | ||
|
||
Base.:(==)(d1::CodeDiff, d2::CodeDiff) = DeepDiffs.fieldequal(d1, d2) | ||
|
||
Base.show(io::IO, ::MIME"text/plain", diff::CodeDiff) = side_by_side_diff(io, diff) | ||
|
||
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 | ||
printstyled(io, "- ", xlines[idx], color=:red) | ||
elseif state == :added | ||
printstyled(io, "+ ", ylines[idx], color=:green) | ||
else | ||
print(io, " ", xlines[idx]) | ||
end | ||
!last && println(io) | ||
end | ||
end | ||
|
||
|
||
""" | ||
optimize_line_changes!(diff::CodeDiff; dist=Levenshtein(), tol=0.7) | ||
Merges consecutive line removals+additions into single line changes in `diff`, when they | ||
are within the `tol`erance of the normalized string `dist`ance. | ||
This does not aim to produce an optimal `CodeDiff`, but simply improve its display. | ||
""" | ||
function optimize_line_changes!(diff::CodeDiff; dist=StringDistances.Levenshtein(), tol=0.7) | ||
xlines = split(diff.before, '\n') | ||
ylines = split(diff.after, '\n') | ||
|
||
empty!(diff.changed) | ||
empty!(diff.ignore_added) | ||
previously_removed = Vector{Int}() | ||
removed_start = 1 | ||
iadded = 1 | ||
|
||
DeepDiffs.visitall(diff.diff) do idx, state, _ | ||
if state == :removed | ||
# Removed lines are always iterated first, so they are compared against added lines | ||
push!(previously_removed, idx) | ||
elseif state == :added | ||
iadded += 1 | ||
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]) | ||
push!(diff.ignore_added, idx) | ||
removed_start += li # The next added lines will start from the next removed line | ||
break | ||
end | ||
end | ||
else | ||
# Treat conserved lines as a "reset" point | ||
empty!(previously_removed) | ||
removed_start = 1 | ||
end | ||
end | ||
|
||
return diff | ||
end |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
module CodeDiffs | ||
|
||
# TODO: option to ignore differences in code comments (such as when comparing methods in different worlds) | ||
# TODO: add `using CodeTracking: definition`, then do like `Cthuhlu.jl` to retrive the function def from its call: https://github.com/JuliaDebug/Cthulhu.jl/blob/9ba8bfc53efed453cb150c9f3e4c279521c5cb17/src/codeview.jl#L54C9-L54C33 | ||
# TODO: GPU assembly / LLVM IR support | ||
# TODO: explain in the docs how to interface with this package | ||
|
||
using DeepDiffs | ||
using InteractiveUtils | ||
using MacroTools | ||
using Markdown | ||
using StringDistances | ||
using WidthLimitedIO | ||
|
||
export @code_diff | ||
|
||
const ANSI_REGEX = r"(?>\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~]))+" | ||
const OhMYREPL_PKG_ID = Base.PkgId(Base.UUID("5fb14364-9ced-5910-84b2-373655c76a03"), "OhMyREPL") | ||
|
||
include("CodeDiff.jl") | ||
include("compare.jl") | ||
include("display.jl") | ||
|
||
end |
Oops, something went wrong.