import Base.cd """ termtitle(dir) Set the terminal title suffix to `dir`. The home directory is replaced with "~", and trailing slash removed. """ function termtitle(dir) if ENV["TERM"] != "dumb" print("\e]0;Julia ● " * replace(replace(dir, homedir() => "~"), r"/$" => "") * "\a") end end function replsetup() atreplinit() do repl if !isdefined(repl, :interface) repl.interface = REPL.setup_interface(repl) end if Main.InteractiveUtils.editor().exec[1] == "e" Main.InteractiveUtils.define_editor( r"\be", wait=false) do cmd, path, line `$cmd +$line $path` end Main.InteractiveUtils.define_editor( r"\be\b.*\s(-w|--wait|-t|--tty)", wait=true) do cmd, path, line `$cmd +$line $path` end end if get(ENV, "INSIDE_EMACS", nothing) != "vterm" print("\e[5 q") end @static if VERSION >= v"1.9" # Reset title every prompt repl.interface.modes[1].prompt = () -> (termtitle(pwd()); REPL.contextual_prompt(repl, REPL.JULIA_PROMPT)()) end end @eval function Base.cd(dir::AbstractString) err = ccall(:uv_chdir, Cint, (Cstring,), dir) err < 0 && Base.uv_error("cd($(repr(dir)))", err) termtitle(dir) return nothing end end clearterm() = print("\e[2J") function termcode() REPL.Terminals.raw!(REPL.TerminalMenus.terminal, true) print("\eP+q544e\e\\") output = @task readuntil(stdin, "\e\\") schedule(output) Timer(0.05) do _ istaskdone(output) || Base.throwto(output, InterruptException()) end value = try fetch(output) catch "" end REPL.Terminals.raw!(REPL.TerminalMenus.terminal, false) String(hex2bytes(last(split(value, '=')))) end const TERM_COLORS = Ref(Dict{Symbol, @NamedTuple{r::UInt8, g::UInt8, b::UInt8}}()) function termcolors(; refresh::Bool=false) !refresh && !isempty(TERM_COLORS[]) && return TERM_COLORS[] REPL.Terminals.raw!(REPL.TerminalMenus.terminal, true) output = @task _termcolors() schedule(output) Timer(0.5) do _ istaskdone(output) || Base.throwto(output, InterruptException()) end colors = try fetch(output) catch end REPL.Terminals.raw!(REPL.TerminalMenus.terminal, false) if !isnothing(colors) TERM_COLORS[] = colors end TERM_COLORS[] end function termtheme(; refresh::Bool=false) colors = termcolors(; refresh) white = get(colors, :white, (r=0x80, g=0x80, b=0x80)) black = get(colors, :black, (r=0x80, g=0x80, b=0x80)) fglevel, bglevel = sum(values(white)), sum(values(black)) if fglevel > bglevel :dark elseif fglevel < bglevel :light else :unknown end end function _termcolors() RGBTuple = NamedTuple{(:r, :g, :b), NTuple{3, UInt8}} colors = Dict{Symbol, RGBTuple}() function readcolor(io::IO, n::Integer) if read(io, Char) == '\e' entry = readuntil(io, "\e\\") m = match(r"^]4;(\d+);rgb:([0-9a-f]+)/([0-9a-f]+)/([0-9a-f]+)$", entry) if !isnothing(m) && m.captures[1] == string(n) r = parse(UInt8, m.captures[2][1:2], base=16) g = parse(UInt8, m.captures[3][1:2], base=16) b = parse(UInt8, m.captures[4][1:2], base=16) RGBTuple((r, g, b)) end end end colornames = [:black, :red, :green, :yellow, :blue, :magenta, :cyan, :white, :light_black, :light_red, :light_green, :light_yellow, :light_blue, :light_magenta, :light_cyan, :light_white] for (index, color) in enumerate(colornames) print(stdout, "\e]4;$(index-1);?\e\\") flush(stdout) rgb = readcolor(stdin, index - 1) if !isnothing(rgb) colors[color] = rgb end end colors end const TERM_IMAGE_PACKAGES = let pkg(uuid, name) = Base.PkgId(Base.UUID(uuid), name) kitty = (pkg("b7fa5abe-5c7d-46c6-a1ae-1026d0d509b9", "KittyTerminalImages"), :(KittyTerminalImages.pushKittyDisplay!())) # TODO: sixel Dict("xterm-kitty" => kitty) end const ATTEMPTED_TERMIMAGE_LOAD = Ref(false) function load_termimage_pkg(autoinstall::Bool=true) ATTEMPTED_TERMIMAGE_LOAD[] && return pkg, pkgsetup = get(TERM_IMAGE_PACKAGES, Setup.TERM[], (nothing, nothing)) if !isnothing(pkg) && !haskey(Base.loaded_modules, pkg) if !isnothing(Base.find_package(pkg.name)) ATTEMPTED_TERMIMAGE_LOAD[] = true # Don't to this async because it may affect a `display` call # that's just about to occur. Core.eval(Main, :(import $(Symbol(pkg.name)); $pkgsetup)) elseif autoinstall Pkg = lazypkg() currentproj = Pkg.project().path try Pkg.activate() Pkg.add(pkg.name) load_termimage_pkg(false) finally Pkg.activate(currentproj) end else @info "Consider installing $(pkg.name) for better in-terminal image previews" end end end