Comparison entry points

CodeDiffs.@code_diffMacro
@code_diff [type=:native] [color=true] [cleanup=true] [dbinfo=true] [option=value...] f₁(...) f₂(...)
@code_diff [option=value...] :(expr₁) :(expr₂)

Compare the methods called by the f₁(...) and f₂(...) or the expressions expr₁ and expr₂, then return a CodeDiff.

options are passed to get_code. Option names ending with _1 or _2 are passed to the call of get_code for f₁ and f₂ respectively. They can also be packed into extra_1 and extra_2.

To compare Expr in variables, use @code_diff :($a) :($b).

cleanup == true will use cleanup_code to make the codes more prone to comparisons (e.g. by renaming variables with names which change every time).

dbinfo is a broader version of the debuginfo option of @code_typed and @code_llvm. dbinfo works for all code types. dbinfo=true is equivalent to debuginfo=:source (or :default) and dbinfo=false is debuginfo=:none. For code types with no option to control the verbosity of the output, dbinfo is silently ignored.

# Default comparison
@code_diff type=:native f() g()

# No debuginfo for `f()` and `g()`
@code_diff type=:native debuginfo=:none f() g()

# No debuginfo for `f()`
@code_diff type=:native debuginfo_1=:none f() g()

# No debuginfo for `g()`
@code_diff type=:native debuginfo_2=:none f() g()

# Options can be passed from variables with `extra_1` and `extra_2`
opts = (; debuginfo=:none, world=Base.get_world_counter())
@code_diff type=:native extra_1=opts extra_2=opts f() g()

# `type` and `color` can also be made different in each side
@code_diff type_1=:native type_2=:llvm f() f()
source
CodeDiffs.code_diffFunction
code_diff(args₁::Tuple, args₂::Tuple; extra_1=(;), extra_2=(;), kwargs...)

Function equivalent to @code_diff(extra_1, extra_2, kwargs..., args₁, args₂). kwargs are common to both sides, while extra_1 and extra_2 are passed to code_for_diff only with args₁ and args₂ respectively.

julia> diff_1 = @code_diff debuginfo_1=:none f() g();

julia> diff_2 = code_diff((f, Tuple{}), (g, Tuple{}); extra_1=(; debuginfo=:none));

julia> diff_1 == diff_2
true
source
CodeDiffs.code_for_diffFunction
code_for_diff(f, types::Type{<:Tuple};
    type=:native, color=true, dbinfo=true, cleanup=true, cleanup_opts=(;), kwargs...
)
code_for_diff(expr::Expr; type=:ast, color=true, kwargs...)

Fetches the code of f with get_code(Val(type), f, types; dbinfo, kwargs...), cleans it up with cleanup_code(Val(type), code, dbinfo, cleanup_opts) and highlights it using the appropriate code_highlighter(Val(type)). The result is two Strings: one without and the other with highlighting.

source
CodeDiffs.CodeDiffType
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 cleanup_code on all codes.

Use optimize_line_changes! to improve the difference.

Fancy REPL output is done with side_by_side_diff.

source

Code fetching

CodeDiffs.@code_forMacro
@code_for [type=:native] [color=true] [io=stdout] [cleanup=true] [dbinfo=true] [option=value...] f(...)
@code_for [option=value...] :(expr)

Display the code of f(...) to io for the given code type, or the expression expr (AST only).

options are passed to get_code. To display an Expr in a variable, use @code_for :($expr).

io defaults to stdout. If io == String, then the code is not printed and is simply returned.

If the type option is the first option, "type" can be omitted: i.e. @code_for :llvm f() is valid.

cleanup == true will use cleanup_code on the code.

dbinfo is a broader version of the debuginfo option of @code_typed and @code_llvm. dbinfo works for all code types. dbinfo=true is equivalent to debuginfo=:source (or :default) and dbinfo=false is debuginfo=:none. For code types with no option to control the verbosity of the output, dbinfo is silently ignored.

# Default display
@code_for type=:native f()

# Without debuginfo
@code_for type=:llvm debuginfo=:none f()

# Options sets can be passed from variables with the `extra` options
opts = (; debuginfo=:none, world=Base.get_world_counter())
@code_for type=:typed extra=opts f()

# Same as above, but shorter since we can omit "type"
@code_for :typed extra=opts f()
source
CodeDiffs.code_nativeFunction
code_native(f, types; world=nothing, kwargs...)

The native code of the method of f called with types (a Tuple type), as a string. world defaults to the current world age. kwargs are forwarded to InteractiveUtils.code_native.

source
CodeDiffs.code_llvmFunction
code_llvm(f, types; world=nothing, kwargs...)

The LLVM-IR code of the method of f called with types (a Tuple type), as a string. world defaults to the current world age. kwargs are forwarded to InteractiveUtils.code_native.

source
CodeDiffs.code_typedFunction
code_typed(f, types; world=nothing, kwargs...)

The Julia-IR code (aka 'typed code') of the method of f called with types (a Tuple type), as a Core.CodeInfo. world defaults to the current world age. kwargs are forwarded to Base.code_typed.

The function call should only match a single method.

source
CodeDiffs.code_astFunction
code_ast(f, types; world=nothing, prettify=true, lines=false, alias=false)

The Julia AST of the method of f called with types (a Tuple type), as a Expr. Revise.jl is used to get those definitions, and it must be loaded before the definition of f's method to get the AST for.

world defaults to the current world age. Since Revise.jl does not keep track of all definitions in all world ages, it is very likely that the only retrievable definition is the most recent one.

If prettify == true, then MacroTools.prettify(code; lines, alias) is used to cleanup the AST. lines == true will keep the LineNumberNodes and alias == true will replace mangled names (or gensyms) by more readable names.

source
CodeDiffs.get_codeFunction
get_code(::Val{code_type}, f, types; world=nothing, dbinfo=true, kwargs...)

The code object of code_type for f. Dispatch depends on code_type:

world is the world age of the code to get. If unsupported by code_type and !isnothing(world), an error is raised.

dbinfo is a superset of the debuginfo=:source or debuginfo=:none options for code_llvm and code_typed. If unsupported by code_type, it should be ignored. The debuginfo option takes precedence over dbinfo if code_type supports it.

source

Highlighting

CodeDiffs.code_highlighterFunction
code_highlighter(::Val{code_type}) where {code_type}

Return a function of signature (io::IO, code_obj) which prints code_obj to io with highlighting/decorations. By default print(io, code_obj) is used for AbstractStrings and Base.show(io, MIME"text/plain"(), code_obj) otherwise.

The highlighting function is called twice: once for color-less text and again with color.

source

Diff display

CodeDiffs.optimize_line_changes!Function
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 tolerance of the normalized string distance.

This does not aim to produce an optimal CodeDiff, but simply improve its display.

source
CodeDiffs.side_by_side_diffFunction
side_by_side_diff([io::IO,] diff::CodeDiff; tab_width=4, width=nothing, line_numbers=nothing)

Side by side display of a CodeDiff to io (defaults to stdout).

width defaults to the width of the terminal. It is 80 by default for non-terminal io.

tab_width is the number of spaces tabs are replaced with.

line_numbers=true will add line numbers on each side of the columns. It defaults to the environment variable "CODE_DIFFS_LINE_NUMBERS", which itself defaults to false.

source