Skip to content
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
2 changes: 0 additions & 2 deletions .github/workflows/CI.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,6 @@ jobs:
arch: ${{ matrix.arch }}
- uses: julia-actions/cache@v3
- uses: julia-actions/julia-buildpkg@v1
- name: Use TerminalRegressionTests Julia 1.12 support branch
run: julia --project=. --color=yes -e 'using Pkg; Pkg.add(Pkg.PackageSpec(url="https://github.com/JuliaDebug/TerminalRegressionTests.jl", rev="kc/terminal-1.12-support"))'
- uses: julia-actions/julia-runtest@v1
- uses: julia-actions/julia-processcoverage@v1
- uses: codecov/codecov-action@v7
Expand Down
5 changes: 1 addition & 4 deletions Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,9 @@ PrecompileTools = "aea7be01-6a6a-4083-8856-8a6e6704d82a"
REPL = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb"
tree_sitter_julia_jll = "52be201e-a5e9-5cfe-8bf2-2dc4b062171c"

[sources]
TerminalRegressionTests = {url = "https://github.com/JuliaDebug/TerminalRegressionTests.jl", rev = "kc/terminal-1.12-support"}

[compat]
CodeTracking = "2, 3"
Highlights = "0.6"
Highlights = "0.6.2"
JuliaInterpreter = "0.10, 0.11"
PrecompileTools = "1"
TerminalRegressionTests = "0.3"
Expand Down
5 changes: 1 addition & 4 deletions src/precompile.jl
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,7 @@ end
# active REPL), which the scripted session above does not exercise
precompile(RunDebugger, (Frame,))

# Clean up global state the workload mutated. The highlight cache in
# particular holds tree-sitter pointers that must not be serialized into
# the package image.
_highlight_cache[] = nothing
# Clean up global state the workload mutated.
empty!(WATCH_LIST)
JuliaInterpreter.remove()
_ALT_SCREEN[] = false
Expand Down
43 changes: 8 additions & 35 deletions src/printing.jl
Original file line number Diff line number Diff line change
Expand Up @@ -402,50 +402,23 @@ function compute_source_offsets(code::AbstractString, current_offsetline::Intege
startoffset, stopoffset
end

# `Highlights.highlight` creates a tree-sitter parser and compiles the
# highlight query on every call (~30 ms) — far too slow for a status print
# that highlights every variable line. Cache them for the session.
mutable struct HighlightCache
parser::Any
query::Any
theme::Any
theme_name::String
end
const _highlight_cache = Ref{Union{HighlightCache, Nothing}}(nothing)

function highlight_cache()
cache = _highlight_cache[]
if cache === nothing || cache.theme_name != _current_theme[]
lang = Highlights.resolve_language(:julia)
parser = Highlights.TreeSitter.Parser(lang)
query = Highlights.TreeSitter.Query(lang, ["highlights"])
theme = Highlights.load_theme(_current_theme[])
cache = HighlightCache(parser, query, theme, _current_theme[])
_highlight_cache[] = cache
end
return cache
end
# Pass the grammar module rather than the `:julia` symbol: symbol lookup goes
# through `Base.identify_package`, which only sees the active project's direct
# deps and so fails when Debugger is an indirect dependency.
import tree_sitter_julia_jll

function highlight_code(code; context=nothing)
if context !== nothing && !get(context, :color, false)
return code
end
_syntax_highlighting[] || return code
try
cache = highlight_cache()
tokens = Highlights.highlight_tokens(cache.parser, cache.query, code)
return sprint(context=context) do io
Highlights.format(io, MIME("text/ansi"), tokens, code, cache.theme, :julia)
end
catch
# The fast path uses Highlights internals; fall back to the public API
# if they change
try
return sprint(highlight, MIME("text/ansi"), code, :julia, _current_theme[]; context=context)
catch e
printstyled(stderr, "failed to highlight code, $e\n"; color=Base.warn_color())
return code
Highlights.highlight(io, MIME("text/ansi"), code, tree_sitter_julia_jll, _current_theme[])
end
catch e
printstyled(stderr, "failed to highlight code, $e\n"; color=Base.warn_color())
return code
end
end

Expand Down
23 changes: 23 additions & 0 deletions test/misc.jl
Original file line number Diff line number Diff line change
Expand Up @@ -478,3 +478,26 @@ end
# the session survived: `fr` after the error still prints the locals
@test occursin(r"y.*= .*2", out)
end

# Highlighting must work when the grammar jll is not a direct dep of the active
# project (i.e. Debugger installed as an indirect dependency). An empty active
# project reproduces that; `:julia` symbol lookup would fail there.
@testset "highlighting when grammar jll is not a direct project dep" begin
prev_highlight = Debugger.config().highlight
Debugger.set_highlight(true)
old_project = Base.active_project()
try
mktempdir() do tmp
touch(joinpath(tmp, "Project.toml"))
Base.set_active_project(joinpath(tmp, "Project.toml"))
io = IOContext(IOBuffer(), :color => true)
out = Debugger.highlight_code("x = 1"; context=io)
# ANSI escapes mean it highlighted; the bug silently fell back to
# the un-highlighted source.
@test occursin("\e[", out)
end
finally
Base.set_active_project(old_project)
Debugger.set_highlight(prev_highlight)
end
end