154 lines
4.9 KiB
Julia
154 lines
4.9 KiB
Julia
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()
|
|
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))
|
|
else
|
|
@info "Consider installing $(pkg.name) for better in-terminal image previews"
|
|
end
|
|
end
|
|
end
|