Initial commit
This commit is contained in:
commit
09f905f4ab
|
@ -0,0 +1 @@
|
||||||
|
Manifest.toml
|
|
@ -0,0 +1,42 @@
|
||||||
|
name = "Setup"
|
||||||
|
uuid = "1e701ad1-9860-423b-8651-7f81d307e3cf"
|
||||||
|
authors = ["TEC <git@tecosaur.net>"]
|
||||||
|
version = "0.1.0"
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
BaseDirs = "18cc8868-cbac-4acf-b575-c8ff214dc66f"
|
||||||
|
InteractiveUtils = "b77e0a4c-d291-57a0-90e8-8db25a27a240"
|
||||||
|
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
|
||||||
|
Markdown = "d6f4376e-aef5-505a-96c1-9c027394607a"
|
||||||
|
Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f"
|
||||||
|
REPL = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb"
|
||||||
|
Serialization = "9e88b42a-f829-5b0c-bbe9-9e923198166b"
|
||||||
|
TOML = "fa267f1f-6049-4f14-aa54-33bafae1ed76"
|
||||||
|
|
||||||
|
[weakdeps]
|
||||||
|
CairoMakie = "13f3f980-e62b-5c42-98c6-ff1f3baf88f0"
|
||||||
|
Colors = "5ae59095-9a9b-59fe-a467-6f913c188581"
|
||||||
|
Gadfly = "c91e804a-d5a3-530f-b6f0-dfbca275c004"
|
||||||
|
HDF5 = "f67ccb44-e63f-5c2f-98bd-6dc0ccc4ba2f"
|
||||||
|
JpegTurbo = "b835a17e-a41a-41e7-81f0-2f016b05efe0"
|
||||||
|
KittyTerminalImages = "b7fa5abe-5c7d-46c6-a1ae-1026d0d509b9"
|
||||||
|
Netpbm = "f09324ee-3d7c-5217-9330-fc30815ba969"
|
||||||
|
OhMyREPL = "5fb14364-9ced-5910-84b2-373655c76a03"
|
||||||
|
PNGFiles = "f57f5aa1-a3ce-4bc8-8ab9-96f992907883"
|
||||||
|
QOI = "4b34888f-f399-49d4-9bb3-47ed5cae4e65"
|
||||||
|
TiffImages = "731e570b-9d59-4bfa-96dc-6df516fadf69"
|
||||||
|
|
||||||
|
[extensions]
|
||||||
|
cairomakie = "CairoMakie"
|
||||||
|
gadfly = "Gadfly"
|
||||||
|
hdf5 = "HDF5"
|
||||||
|
image_jpeg = "JpegTurbo"
|
||||||
|
image_netpbm = "Netpbm"
|
||||||
|
image_png = "PNGFiles"
|
||||||
|
image_qoi = "QOI"
|
||||||
|
image_tiff = "TiffImages"
|
||||||
|
ohmyrepl = "OhMyREPL"
|
||||||
|
prettycolors = "Colors"
|
||||||
|
|
||||||
|
[compat]
|
||||||
|
julia = "1.7"
|
|
@ -0,0 +1,85 @@
|
||||||
|
#+title: Setup.jl
|
||||||
|
#+author: TEC
|
||||||
|
|
||||||
|
This is my personal Julia configuration. It has grown far beyond my wildest imagination.
|
||||||
|
|
||||||
|
* Installation
|
||||||
|
|
||||||
|
#+begin_src shell
|
||||||
|
julia --startup-file=no -e 'using Pkg; Pkg.add(url="https://git.tecosaur.net/tec/Setup.jl.git"); using Setup; Setup.install()'
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
* Features
|
||||||
|
** Autoloading
|
||||||
|
|
||||||
|
Instead of loading packages whose functionality might be needed at some point,
|
||||||
|
load them on-demand. Lazy loading for the win!
|
||||||
|
|
||||||
|
The following packages are currently supported:
|
||||||
|
+ The standard library (=Base64=, =CRC32c=, =Dates=, =Distributions=, =Downloads=,
|
||||||
|
=LinearAlgebra=, =Markdown=, =Mmap=, =Pkg=, =Printf=, =REPL=, =Random=, =SHA=, =Serialisation=,
|
||||||
|
=Statistics=, =StatsBase=, =TOML=, =Tar=, =Test=, =Threads=, =UUIDs=)
|
||||||
|
+ =BaseDirs=
|
||||||
|
+ =BenchmarkTools=
|
||||||
|
+ =CSV=
|
||||||
|
+ =Cthulhu=
|
||||||
|
+ =DataFrames=
|
||||||
|
+ =DataToolkit=
|
||||||
|
+ =Debugger=
|
||||||
|
+ =Distributions=
|
||||||
|
+ =JET=
|
||||||
|
+ =JSON3=
|
||||||
|
+ =Org=
|
||||||
|
+ =WhyNotEqual=
|
||||||
|
|
||||||
|
** Function/Structure inspection
|
||||||
|
|
||||||
|
Get a sense of a function or structure with the =about= function/macro.
|
||||||
|
|
||||||
|
** Environment tweaks
|
||||||
|
*** Shorter activation
|
||||||
|
|
||||||
|
Add =a= as a shorthand for =activate=
|
||||||
|
|
||||||
|
*** Easier temp environments
|
||||||
|
|
||||||
|
Add =-t= as a shorthand for =--temp=, with the activate change this means opening a
|
||||||
|
temporary environment is now a bit quicker:
|
||||||
|
|
||||||
|
#+begin_example
|
||||||
|
pkg> a -t
|
||||||
|
#+end_example
|
||||||
|
|
||||||
|
instead of
|
||||||
|
|
||||||
|
#+begin_example
|
||||||
|
pkg> activate --temp
|
||||||
|
#+end_example
|
||||||
|
|
||||||
|
|
||||||
|
*** Environment stack
|
||||||
|
|
||||||
|
Load and unload named environments with the new =pkg> (un)stack= set of commands.
|
||||||
|
|
||||||
|
** Command puns
|
||||||
|
|
||||||
|
For more easily running ~Cmd~s, we now have the following syntactic puns.
|
||||||
|
|
||||||
|
#+begin_src julia
|
||||||
|
~ `cmd` # read to string
|
||||||
|
! `cmd` # print output
|
||||||
|
!~ `cmd` # read and print output
|
||||||
|
`a` | `b` # pipe commands
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** Package configuration
|
||||||
|
|
||||||
|
Thanks to package extensions, it's fairly straightforward to bundle per-package
|
||||||
|
customisation code. Currently this covers the following:
|
||||||
|
|
||||||
|
+ Setting the Makie theme based on the terminal colours when loading =CairoMakie=
|
||||||
|
+ Pushing the =Gadfly= display
|
||||||
|
+ Changing the =HDF5= icons
|
||||||
|
+ Loading =ImageShow= when =JpegTurbo=, =Netpbm=, =PNGFiles=, =QOI=, or =TiffImages= are loaded
|
||||||
|
+ Load an appropriate =OhMyREPL= theme on startup
|
||||||
|
+ Add pretty colour show methods for =Color= types
|
|
@ -0,0 +1,102 @@
|
||||||
|
module cairomakie
|
||||||
|
|
||||||
|
using Setup
|
||||||
|
using CairoMakie
|
||||||
|
import Pkg
|
||||||
|
|
||||||
|
import Setup.theme_term
|
||||||
|
|
||||||
|
import CairoMakie.Colors.FixedPointNumbers.N0f8
|
||||||
|
import CairoMakie.Colors.RGB
|
||||||
|
|
||||||
|
import CairoMakie.Makie: Theme, RGBAf, Attributes, Axis, Axis3, Legend, Colorbar
|
||||||
|
|
||||||
|
function theme_term()
|
||||||
|
termcolors = Setup.termcolors()
|
||||||
|
|
||||||
|
if isempty(termcolors)
|
||||||
|
return CairoMakie.Makie.current_default_theme()
|
||||||
|
end
|
||||||
|
|
||||||
|
function tocolor(name::Symbol)
|
||||||
|
rgb = get(termcolors, name, (r=0x00, g=0x00, b=0x00))
|
||||||
|
RGB(reinterpret(N0f8, rgb.r),
|
||||||
|
reinterpret(N0f8, rgb.g),
|
||||||
|
reinterpret(N0f8, rgb.b))
|
||||||
|
end
|
||||||
|
|
||||||
|
bg, fg, red, green, yellow, blue, magenta, cyan,
|
||||||
|
lbg, lfg, lred, lgreen, lyellow, lblue, lmagenta, lcyan =
|
||||||
|
tocolor.((:black, :white, :red, :green, :yellow, :blue,
|
||||||
|
:magenta, :cyan, :light_black, :light_white,
|
||||||
|
:light_red, :light_green, :light_yellow,
|
||||||
|
:light_blue, :light_magenta, :light_cyan))
|
||||||
|
|
||||||
|
onecolors(α = 1.0) =
|
||||||
|
RGBAf.([blue, yellow, green, magenta, red, cyan, lblue,
|
||||||
|
lyellow, lgreen, lmagenta, lred, lcyan],
|
||||||
|
α)
|
||||||
|
|
||||||
|
Theme(
|
||||||
|
backgroundcolor = bg,
|
||||||
|
textcolor = fg,
|
||||||
|
linecolor = fg,
|
||||||
|
font = :regular,
|
||||||
|
fonts = Attributes(
|
||||||
|
bold = "JetBrains Mono Bold",
|
||||||
|
bold_italic = "JetBrains Mono Bold Italic",
|
||||||
|
italic = "JetBrains Mono Italic",
|
||||||
|
regular = "JetBrains Mono Medium"),
|
||||||
|
palette = merge(Attributes(
|
||||||
|
color = onecolors(1.0),
|
||||||
|
patchcolor = onecolors(0.8)
|
||||||
|
), CairoMakie.Makie.default_palettes),
|
||||||
|
Axis = (
|
||||||
|
backgroundcolor = :transparent,
|
||||||
|
bottomspinecolor = fg,
|
||||||
|
topspinecolor = fg,
|
||||||
|
leftspinecolor = fg,
|
||||||
|
rightspinecolor = fg,
|
||||||
|
xgridcolor = RGBAf(1, 1, 1, 0.16),
|
||||||
|
ygridcolor = RGBAf(1, 1, 1, 0.16),
|
||||||
|
xtickcolor = fg,
|
||||||
|
ytickcolor = fg),
|
||||||
|
Legend = (
|
||||||
|
framecolor = fg,
|
||||||
|
bgcolor = bg),
|
||||||
|
Axis3 = (
|
||||||
|
xgridcolor = RGBAf(1, 1, 1, 0.16),
|
||||||
|
ygridcolor = RGBAf(1, 1, 1, 0.16),
|
||||||
|
zgridcolor = RGBAf(1, 1, 1, 0.16),
|
||||||
|
xspinecolor_1 = fg,
|
||||||
|
yspinecolor_1 = fg,
|
||||||
|
zspinecolor_1 = fg,
|
||||||
|
xspinecolor_2 = fg,
|
||||||
|
yspinecolor_2 = fg,
|
||||||
|
zspinecolor_2 = fg,
|
||||||
|
xspinecolor_3 = fg,
|
||||||
|
yspinecolor_3 = fg,
|
||||||
|
zspinecolor_3 = fg,
|
||||||
|
xticklabelpad = 3,
|
||||||
|
yticklabelpad = 3,
|
||||||
|
zticklabelpad = 6,
|
||||||
|
xtickcolor = fg,
|
||||||
|
ytickcolor = fg,
|
||||||
|
ztickcolor = fg),
|
||||||
|
Colorbar = (
|
||||||
|
tickcolor = fg,
|
||||||
|
spinecolor = fg,
|
||||||
|
topspinecolor = fg,
|
||||||
|
bottomspinecolor = fg,
|
||||||
|
leftspinecolor = fg,
|
||||||
|
rightspinecolor = fg))
|
||||||
|
end
|
||||||
|
|
||||||
|
function __init__()
|
||||||
|
if isinteractive()
|
||||||
|
Setup.load_termimage_pkg()
|
||||||
|
CairoMakie.set_theme!(theme_term())
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
|
@ -0,0 +1,9 @@
|
||||||
|
module gadfly
|
||||||
|
|
||||||
|
using Gadfly
|
||||||
|
|
||||||
|
function __init__()
|
||||||
|
pushdisplay(Gadfly.GadflyDisplay())
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
|
@ -0,0 +1,22 @@
|
||||||
|
module hdf5
|
||||||
|
|
||||||
|
using HDF5
|
||||||
|
|
||||||
|
import HDF5._tree_icon
|
||||||
|
|
||||||
|
function __init__()
|
||||||
|
_tree_icon(::Type{HDF5.Attribute}) =
|
||||||
|
HDF5.SHOW_TREE_ICONS[] ? "\e[33m\e[39m" : "[A]"
|
||||||
|
_tree_icon(::Type{HDF5.Group}) =
|
||||||
|
HDF5.SHOW_TREE_ICONS[] ? "\e[34m\e[39m" : "[G]"
|
||||||
|
_tree_icon(::Type{HDF5.Dataset}) =
|
||||||
|
HDF5.SHOW_TREE_ICONS[] ? "\e[35m\e[39m" : "[D]"
|
||||||
|
_tree_icon(::Type{HDF5.Datatype}) =
|
||||||
|
HDF5.SHOW_TREE_ICONS[] ? "\e[36m\e[39m" : "[T]"
|
||||||
|
_tree_icon(::Type{HDF5.File}) =
|
||||||
|
HDF5.SHOW_TREE_ICONS[] ? "\e[34m\e[39m" : "[F]"
|
||||||
|
_tree_icon(::Type) =
|
||||||
|
HDF5.SHOW_TREE_ICONS[] ? "\e[31m❓\e[39m" : "[?]"
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
|
@ -0,0 +1,3 @@
|
||||||
|
module image_jpeg
|
||||||
|
include("images.jl")
|
||||||
|
end
|
|
@ -0,0 +1,3 @@
|
||||||
|
module image_netpbm
|
||||||
|
include("images.jl")
|
||||||
|
end
|
|
@ -0,0 +1,3 @@
|
||||||
|
module image_png
|
||||||
|
include("images.jl")
|
||||||
|
end
|
|
@ -0,0 +1,3 @@
|
||||||
|
module image_qoi
|
||||||
|
include("images.jl")
|
||||||
|
end
|
|
@ -0,0 +1,3 @@
|
||||||
|
module image_tiff
|
||||||
|
include("images.jl")
|
||||||
|
end
|
|
@ -0,0 +1,29 @@
|
||||||
|
# This is loaded by all other `image_*.jl` files
|
||||||
|
|
||||||
|
using Setup
|
||||||
|
|
||||||
|
const IMAGE_SHOW_PKG, IMAGE_IO_PKG, IMAGE_MAGICK_PKG = splat(Base.PkgId).([
|
||||||
|
(Base.UUID("4e3cecfd-b093-5904-9786-8bbb286a6a31"), "ImageShow"),
|
||||||
|
(Base.UUID("82e4d734-157c-48bb-816b-45c225c6df19"), "ImageIO"),
|
||||||
|
(Base.UUID("6218d12a-5da1-5696-b52f-db25d2ecc6d1"), "ImageMagick")])
|
||||||
|
|
||||||
|
function __init__()
|
||||||
|
if isinteractive()
|
||||||
|
Setup.load_termimage_pkg()
|
||||||
|
if !haskey(Base.loaded_modules, IMAGE_SHOW_PKG) &&
|
||||||
|
!isnothing(Base.find_package(IMAGE_SHOW_PKG.name)) &&
|
||||||
|
(!isnothing(Base.find_package(IMAGE_IO_PKG.name)) ||
|
||||||
|
!isnothing(Base.find_package(IMAGE_MAGICK_PKG.name)))
|
||||||
|
# Don't to this async because it may affect a `display` call
|
||||||
|
# that's just about to occur.
|
||||||
|
if !isnothing(Base.find_package(IMAGE_IO_PKG.name))
|
||||||
|
Base.require(IMAGE_IO_PKG)
|
||||||
|
elseif !isnothing(Base.find_package(IMAGE_MAGICK_PKG.name))
|
||||||
|
Base.require(IMAGE_MAGICK_PKG)
|
||||||
|
else
|
||||||
|
return
|
||||||
|
end
|
||||||
|
Base.require(IMAGE_SHOW_PKG)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,28 @@
|
||||||
|
module ohmyrepl
|
||||||
|
|
||||||
|
using Setup
|
||||||
|
using OhMyREPL
|
||||||
|
|
||||||
|
function __init__()
|
||||||
|
theme = Setup.termtheme()
|
||||||
|
if theme == :dark
|
||||||
|
OhMyREPL.colorscheme!("OneDark")
|
||||||
|
elseif theme == :light
|
||||||
|
OhMyREPL.colorscheme!("TomorrowDay")
|
||||||
|
else theme == :unknown
|
||||||
|
OhMyREPL.colorscheme!("Monokai16")
|
||||||
|
end
|
||||||
|
|
||||||
|
if Setup.TERM[] == "xterm-kitty"
|
||||||
|
OhMyREPL.input_prompt!(:green) do
|
||||||
|
print("\e]133;A\e\\")
|
||||||
|
"julia> "
|
||||||
|
end
|
||||||
|
OhMyREPL.output_prompt!(:red) do
|
||||||
|
print("\e]133;C\e\\")
|
||||||
|
""
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
|
@ -0,0 +1,58 @@
|
||||||
|
module prettycolors
|
||||||
|
|
||||||
|
using Colors
|
||||||
|
using LinearAlgebra # for the Adjoint type
|
||||||
|
|
||||||
|
import Base.show
|
||||||
|
|
||||||
|
colorcode(rgb::Vector{<:Integer}, background=false) =
|
||||||
|
string("\e[", if background "48" else "38" end,
|
||||||
|
";2;", rgb[1], ";", rgb[2], ";", rgb[3], "m")
|
||||||
|
|
||||||
|
colorcode(c::Union{RGB, RGB24}, background=false) =
|
||||||
|
colorcode(reinterpret.([red(c), green(c), blue(c)]), background)
|
||||||
|
|
||||||
|
colorcode(c::RGB{Float64}, background=false) =
|
||||||
|
colorcode(round.(Int, 255 .* [red(c), green(c), blue(c)]), background)
|
||||||
|
|
||||||
|
colorcode(c::Colorant, background=false) =
|
||||||
|
colorcode(convert(RGB24, c), background)
|
||||||
|
|
||||||
|
function show(io::IO, ::MIME"text/plain", c::Colorant)
|
||||||
|
if get(io, :color, false) && get(ENV, "COLORTERM", nothing) == "truecolor"
|
||||||
|
print(colorcode(c, true), " \e[0m ")
|
||||||
|
end
|
||||||
|
show(io, c)
|
||||||
|
end
|
||||||
|
|
||||||
|
function show(io::IO, ::MIME"text/plain", cs::Adjoint{<:Colorant, <:Vector{<:Colorant}})
|
||||||
|
summary(io, cs)
|
||||||
|
print(":\n")
|
||||||
|
if get(io, :color, false) && get(ENV, "COLORTERM", nothing) == "truecolor"
|
||||||
|
print(" ", join(colorcode.(cs,true), if length(cs) <= 40 " " else " " end),
|
||||||
|
if length(cs) <= 40 " \e[0m" else " \e[0m" end)
|
||||||
|
else
|
||||||
|
Base.print_array(IOContext(io, :SHOWN_SET => cs), cs)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function show(io::IO, ::MIME"text/plain", cs::Matrix{<:Colorant})
|
||||||
|
summary(io, cs)
|
||||||
|
print(":\n")
|
||||||
|
if get(io, :color, false) && *(size(cs)...) <= 1000 && get(ENV, "COLORTERM", nothing) == "truecolor"
|
||||||
|
for csrow in eachrow(cs)
|
||||||
|
println(" ", join(colorcode.(csrow,true),
|
||||||
|
if size(cs,2) <= 40 " " else " " end),
|
||||||
|
if size(cs,2) <= 40 " \e[0m" else " \e[0m" end)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
Base.print_array(IOContext(io, :SHOWN_SET => cs), cs)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function Base.display(c::Colorant)
|
||||||
|
show(stdout, MIME("text/plain"), c)
|
||||||
|
print('\n')
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
|
@ -0,0 +1,80 @@
|
||||||
|
module Setup
|
||||||
|
|
||||||
|
import REPL
|
||||||
|
import Pkg
|
||||||
|
|
||||||
|
export about, @about
|
||||||
|
|
||||||
|
@static if VERSION >= v"1.8"
|
||||||
|
TERM::Ref{String} = get(ENV, "TERM", "")
|
||||||
|
IS_SSH::Ref{Bool} = Ref(false)
|
||||||
|
else
|
||||||
|
TERM = get(ENV, "TERM", "")
|
||||||
|
IS_SSH = Ref(false)
|
||||||
|
end
|
||||||
|
|
||||||
|
include("install.jl")
|
||||||
|
|
||||||
|
include("cmdpuns.jl")
|
||||||
|
include("termsetup.jl")
|
||||||
|
include("about.jl")
|
||||||
|
include("pkgstack.jl")
|
||||||
|
|
||||||
|
include("autoloads.jl")
|
||||||
|
using .Autoloads
|
||||||
|
include("autoload_data.jl")
|
||||||
|
|
||||||
|
include("sessions.jl")
|
||||||
|
using .Sessions
|
||||||
|
|
||||||
|
using .PkgStack
|
||||||
|
|
||||||
|
function ensurepkg(pkg::String)
|
||||||
|
if isnothing(Base.find_package(pkg))
|
||||||
|
@info "Installing $pkg"
|
||||||
|
Pkg.add(pkg)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function theme_term end # For cairomakie.jl
|
||||||
|
|
||||||
|
function __init__()
|
||||||
|
IS_SSH[] = haskey(ENV, "SSH_CLIENT") || haskey(ENV, "SSH_TTY")
|
||||||
|
if isinteractive()
|
||||||
|
TERM[] = termcode()
|
||||||
|
|
||||||
|
Main.Threads.@spawn if TERM[] == "xterm-kitty"
|
||||||
|
if isnothing(Base.find_package("KittyTerminalImages"))
|
||||||
|
@info "Installing KittyTerminalImages"
|
||||||
|
currentproj = Pkg.project().path
|
||||||
|
try
|
||||||
|
Pkg.activate()
|
||||||
|
# Pkg.add("KittyTerminalImages")
|
||||||
|
finally
|
||||||
|
Pkg.activate(currentproj)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
termtitle(pwd())
|
||||||
|
end
|
||||||
|
|
||||||
|
if ENV["TERM"] != "dumb"
|
||||||
|
replsetup()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
precompile(termtitle, ())
|
||||||
|
precompile(replsetup, ())
|
||||||
|
precompile(_termcolors, ())
|
||||||
|
precompile(termcolors, ())
|
||||||
|
precompile(termtheme, ())
|
||||||
|
|
||||||
|
precompile(Autoloads.autoload_loadpkg, (Symbol,))
|
||||||
|
precompile(Autoloads.autoload_scan!, (Expr,))
|
||||||
|
precompile(Autoloads.autoload_scan!, (Symbol,))
|
||||||
|
precompile(Autoloads.autoload_scan!, (Any,))
|
||||||
|
precompile(Autoloads.read_named_envs!, ())
|
||||||
|
precompile(Autoloads.repl_scan_autoloads!, (Expr,))
|
||||||
|
precompile(Autoloads.repl_scan_autoloads!, (Nothing,))
|
||||||
|
|
||||||
|
end
|
|
@ -0,0 +1,256 @@
|
||||||
|
using InteractiveUtils
|
||||||
|
|
||||||
|
const colorcycle = [:light_blue, :light_green, :light_yellow, :light_magenta]
|
||||||
|
|
||||||
|
function humansize(bytes::Integer)
|
||||||
|
units = ("B", "kB", "MB", "GB")
|
||||||
|
magnitude = floor(Int, log(1024, 1 + bytes))
|
||||||
|
if 10 < bytes < 10*1024^magnitude
|
||||||
|
round(bytes / 1024^magnitude, digits=1)
|
||||||
|
else
|
||||||
|
round(Int, bytes / 1024^magnitude)
|
||||||
|
end, units[1+magnitude]
|
||||||
|
end
|
||||||
|
|
||||||
|
function about(obj::Any)
|
||||||
|
print(Base.summary(obj))
|
||||||
|
size, units = humansize(Base.summarysize(obj))
|
||||||
|
if ismutable(obj)
|
||||||
|
print(" (mutable)")
|
||||||
|
end
|
||||||
|
print(", ", size, units, "\n\n")
|
||||||
|
printstyled("Fields:\n", bold=true)
|
||||||
|
memorylayout(obj)
|
||||||
|
end
|
||||||
|
|
||||||
|
function about(type::Type)
|
||||||
|
if isprimitivetype(type)
|
||||||
|
print("Primitive ")
|
||||||
|
elseif isconcretetype(type)
|
||||||
|
print("Concrete ")
|
||||||
|
if Base.datatype_haspadding(type)
|
||||||
|
printstyled("(padded) ", color=:light_black)
|
||||||
|
end
|
||||||
|
elseif isabstracttype(type)
|
||||||
|
print("Abstract ")
|
||||||
|
end
|
||||||
|
if Base.issingletontype(type)
|
||||||
|
print("singleton ")
|
||||||
|
end
|
||||||
|
print(Base.summary(type))
|
||||||
|
print(" defined in ")
|
||||||
|
printstyled(type.name.module, color=:light_red)
|
||||||
|
size, units = humansize(Base.summarysize(type))
|
||||||
|
selfsize, selfunits = try
|
||||||
|
st = humansize(sizeof(type))
|
||||||
|
print(", ", st...)
|
||||||
|
st
|
||||||
|
catch _; (0, "") end
|
||||||
|
if (size, units) != (selfsize, selfunits)
|
||||||
|
print(" referencing ", size, units)
|
||||||
|
end
|
||||||
|
println("\n ", join(string.(supertypes(type)), " \e[31m<:\e[m "))
|
||||||
|
if isstructtype(type) && fieldcount(type) > 0
|
||||||
|
println("\nStruct with \e[1m", fieldcount(type), "\e[m fields:")
|
||||||
|
if type isa DataType
|
||||||
|
for (i, (fname, ftype)) in enumerate(zip(fieldnames(type), fieldtypes(type)))
|
||||||
|
color = colorcycle[i % length(colorcycle) + 1]
|
||||||
|
print(" • ")
|
||||||
|
printstyled(fname; color)
|
||||||
|
printstyled("::", string(ftype), color=:light_black)
|
||||||
|
print('\n')
|
||||||
|
end
|
||||||
|
print('\n')
|
||||||
|
memorylayout(type)
|
||||||
|
else
|
||||||
|
println(" • ",
|
||||||
|
join(string.(fieldnames(type), "\e[90m::",
|
||||||
|
fieldtypes(type), "\e[m"),
|
||||||
|
"\n • "))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function structinfo(T::DataType)
|
||||||
|
map(1:fieldcount(T)) do i
|
||||||
|
size = Int(if i < fieldcount(T) fieldoffset(T, i+1)
|
||||||
|
else sizeof(T) end - fieldoffset(T, i))
|
||||||
|
contentsize=try sizeof(fieldtype(T, i)) catch _ 0 end
|
||||||
|
(; i, offset=fieldoffset(T, i) |> Int,
|
||||||
|
size, contentsize,
|
||||||
|
pointer=contentsize == 0,
|
||||||
|
name=fieldname(T, i),
|
||||||
|
type=fieldtype(T, i))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function memorylayout(type::DataType)
|
||||||
|
cpad(s, n::Integer, p=" ") = rpad(lpad(s,div(n+textwidth(s),2),p),n,p)
|
||||||
|
si = structinfo(type)
|
||||||
|
!isempty(si) || return
|
||||||
|
memstep = memstep = gcd((getfield.(si, :size), getfield.(si, :contentsize)) |>
|
||||||
|
Iterators.flatten |> collect)
|
||||||
|
memscale = max(1, floor(Int, 70/(sizeof(type)/memstep)))
|
||||||
|
print(' ')
|
||||||
|
for (; i, size, contentsize, pointer) in si
|
||||||
|
color = colorcycle[i % length(colorcycle) + 1]
|
||||||
|
contentwidth = memscale * contentsize÷memstep
|
||||||
|
printstyled('■'^contentwidth; color)
|
||||||
|
if contentsize < size
|
||||||
|
paddwidth = memscale * (size - contentsize)÷memstep
|
||||||
|
printstyled('■'^paddwidth;
|
||||||
|
color=if pointer; :cyan else :light_black end)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
print("\n ")
|
||||||
|
for (; i, size, contentsize, pointer) in si
|
||||||
|
width = memscale * size÷memstep
|
||||||
|
color = colorcycle[i % length(colorcycle) + 1]
|
||||||
|
fsize, funits = humansize(size)
|
||||||
|
if pointer
|
||||||
|
printstyled(cpad("*", width); color)
|
||||||
|
elseif contentsize < size
|
||||||
|
csize, cunits = humansize(contentsize)
|
||||||
|
psize, punits = humansize(size - contentsize)
|
||||||
|
csizestr, psizestr = string(csize, cunits), string(psize, punits)
|
||||||
|
cwidth = div(width + textwidth(csizestr) - textwidth(psizestr) - 1, 2)
|
||||||
|
pwidth = width - cwidth
|
||||||
|
printstyled(lpad(csizestr, cwidth); color)
|
||||||
|
printstyled(rpad('+' * psizestr, pwidth); color=:light_black)
|
||||||
|
else
|
||||||
|
printstyled(cpad(string(fsize, funits), width); color)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if any(getfield.(si, :pointer))
|
||||||
|
printstyled("\n\n * = Pointer (8B)", color=:cyan)
|
||||||
|
end
|
||||||
|
print('\n')
|
||||||
|
end
|
||||||
|
|
||||||
|
function memorylayout(val::T) where {T}
|
||||||
|
si = structinfo(T)
|
||||||
|
!isempty(si) || return memorylayout(T)
|
||||||
|
rows = Vector{NamedTuple}()
|
||||||
|
for (; name, size, contentsize, pointer, type) in si
|
||||||
|
fsize, funits = humansize(size)
|
||||||
|
fbits = if isprimitivetype(type)
|
||||||
|
bitstring(getfield(val, name)) * '-'^(8*(size-contentsize))
|
||||||
|
elseif pointer
|
||||||
|
"Pointer"
|
||||||
|
else
|
||||||
|
""
|
||||||
|
end
|
||||||
|
fshow = sprint(show, getfield(val, name), context=:compact => true)
|
||||||
|
push!(rows, (; fname=string(name), fsize=string(fsize), funits,
|
||||||
|
fbits, fshow, ftype=string(type)))
|
||||||
|
end
|
||||||
|
widths = Dict(c => maximum(length.(getfield.(rows, c)))
|
||||||
|
for c in fieldnames(typeof(first(rows)))) |>
|
||||||
|
NamedTuple
|
||||||
|
for (i, (; fname, fsize, funits, fbits, fshow, ftype)) in enumerate(rows)
|
||||||
|
color = colorcycle[i % length(colorcycle) + 1]
|
||||||
|
printstyled(' ', lpad(fname, widths.fname), "::",
|
||||||
|
rpad(ftype, widths.ftype); color)
|
||||||
|
printstyled(" ", lpad(fsize, widths.fsize),
|
||||||
|
rpad(funits, widths.funits), ' '; color)
|
||||||
|
print(replace(rpad(fbits, widths.fbits), r"0|\-" => s"\e[90m\0\e[m"), ' ')
|
||||||
|
printstyled(rpad(fshow, widths.fshow); color)
|
||||||
|
print('\n')
|
||||||
|
end
|
||||||
|
print('\n')
|
||||||
|
memorylayout(T)
|
||||||
|
end
|
||||||
|
|
||||||
|
function about(fn::Function)
|
||||||
|
source = Main.InteractiveUtils.which(Main, Symbol(fn))
|
||||||
|
methodmodules = getproperty.(methods(fn).ms, :module)
|
||||||
|
others = setdiff(methodmodules, [source])
|
||||||
|
print(Base.summary(fn))
|
||||||
|
print("\n\nDefined in ")
|
||||||
|
printstyled(source, color=:light_red)
|
||||||
|
if length(others) > 0
|
||||||
|
printstyled("(", sum(Ref(source) .=== methodmodules), ")",
|
||||||
|
color=:light_black)
|
||||||
|
print(" extended in ")
|
||||||
|
for (i, oth) in enumerate(others)
|
||||||
|
printstyled(oth, color=:light_red)
|
||||||
|
printstyled("(", sum(Ref(oth) .=== methodmodules), ")",
|
||||||
|
color=:light_black)
|
||||||
|
if length(others) == 2 && i == 1
|
||||||
|
print(" and ")
|
||||||
|
elseif length(others) > 2 && i < length(others)-1
|
||||||
|
print(", ")
|
||||||
|
elseif length(others) > 2 && i == length(others)-1
|
||||||
|
print(", and ")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
print(".\n")
|
||||||
|
end
|
||||||
|
|
||||||
|
function about(fn::Union{Function, Type}, typesig::Type{<:Tuple})
|
||||||
|
about(Base.unwrap_unionall(fn))
|
||||||
|
print("\n")
|
||||||
|
matchedmethods = methods(fn, typesig)
|
||||||
|
printstyled("Matching methods ($(length(matchedmethods.ms))):\n", bold=true)
|
||||||
|
for method in matchedmethods.ms
|
||||||
|
println(" ", sprint(show, method, context=IOContext(stdout)))
|
||||||
|
end
|
||||||
|
print('\n')
|
||||||
|
printstyled("Effects:\n", bold=true)
|
||||||
|
effects = Base.infer_effects(fn, typesig)
|
||||||
|
trichar(t::UInt8) =
|
||||||
|
Dict(Core.Compiler.ALWAYS_TRUE => '✔',
|
||||||
|
# Core.Compiler.TRISTATE_UNKNOWN => '?',
|
||||||
|
Core.Compiler.ALWAYS_FALSE => '✗')[t]
|
||||||
|
trichar(b::Bool) = ifelse(b, '✔', '✗')
|
||||||
|
tricolor(t::UInt8) =
|
||||||
|
Dict(Core.Compiler.ALWAYS_TRUE => :green,
|
||||||
|
# Core.Compiler.TRISTATE_UNKNOWN => :yellow,
|
||||||
|
Core.Compiler.ALWAYS_FALSE => :red)[t]
|
||||||
|
tricolor(b::Bool) = ifelse(b, :green, :red)
|
||||||
|
hedge(t::UInt8) =
|
||||||
|
Dict(Core.Compiler.ALWAYS_TRUE => "guaranteed to",
|
||||||
|
# Core.Compiler.TRISTATE_UNKNOWN => "might",
|
||||||
|
Core.Compiler.ALWAYS_FALSE => "not guaranteed to")[t]
|
||||||
|
hedge(b::Bool) = ifelse(b, "guaranteed to", "not guaranteed to")
|
||||||
|
for (effect, description) in
|
||||||
|
[(:consistent, "return or terminate consistently"),
|
||||||
|
(:effect_free, "be free from externally semantically visible side effects"),
|
||||||
|
(:nothrow, "never throw an exception"),
|
||||||
|
(:terminates, "terminate")]
|
||||||
|
e = getfield(effects, effect)
|
||||||
|
print(" "); printstyled(trichar(e), ' ', string(effect), color=tricolor(e))
|
||||||
|
print(" "); printstyled(hedge(e), ' ', description, color=:light_black);
|
||||||
|
print('\n')
|
||||||
|
end
|
||||||
|
if !effects.nonoverlayed
|
||||||
|
print(" "); printstyled(trichar(Core.Compiler.ALWAYS_FALSE), " nonoverlayed",
|
||||||
|
color=tricolor(Core.Compiler.ALWAYS_FALSE))
|
||||||
|
print(" "); printstyled("methods within this method are not defined in an overlayed method table",
|
||||||
|
color=:light_black);
|
||||||
|
print('\n')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
macro about(obj::Symbol, types::Union{Symbol, Expr}...)
|
||||||
|
if Core.eval(Main, obj) isa Function && length(types) == 1 &&
|
||||||
|
types[1] == :(())
|
||||||
|
:(about($obj, Tuple{}))
|
||||||
|
elseif Core.eval(Main, obj) isa Function && length(types) > 0
|
||||||
|
:(about($obj, $(Tuple{Core.eval.(Main, types)...})))
|
||||||
|
else
|
||||||
|
:(about($obj))
|
||||||
|
end |> esc
|
||||||
|
end
|
||||||
|
|
||||||
|
macro about(qobj::Union{QuoteNode, Expr}, types::Union{Symbol, Expr}...)
|
||||||
|
if Core.eval(Main, Core.eval(Main, qobj)) isa Function && length(types) == 1 &&
|
||||||
|
types[1] == :(())
|
||||||
|
:(about($(Core.eval(Main, qobj)), Tuple{}))
|
||||||
|
elseif length(types) > 0
|
||||||
|
:(about($(Core.eval(Main, qobj)), $(Tuple{Core.eval.(Main, types)...})))
|
||||||
|
else
|
||||||
|
:(about($(Core.eval(Main, qobj))))
|
||||||
|
end |> esc
|
||||||
|
end
|
|
@ -0,0 +1,258 @@
|
||||||
|
foreach(add_autoloads!, [
|
||||||
|
PkgAutoloads(
|
||||||
|
:(Base.Threads),
|
||||||
|
exported = Bindings(
|
||||||
|
macros = ["@spawn", "@threads"],
|
||||||
|
callables = [
|
||||||
|
:Atomic, :Event, :SpinLock, :Threads, :atomic_add!,
|
||||||
|
:atomic_and!, :atomic_cas!, :atomic_fence, :atomic_max!,
|
||||||
|
:atomic_min!, :atomic_nand!, :atomic_or!, :atomic_sub!,
|
||||||
|
:atomic_xchg!, :atomic_xor!, :nthreadpools, :nthreads,
|
||||||
|
:threadid, :threadpool])),
|
||||||
|
PkgAutoloads(:Base64, exported = Bindings(callables = [
|
||||||
|
:Base64DecodePipe, :Base64EncodePipe, :base64decode, :base64encode,
|
||||||
|
:stringmime])),
|
||||||
|
PkgAutoloads(:BaseDirs),
|
||||||
|
PkgAutoloads(
|
||||||
|
:BenchmarkTools,
|
||||||
|
exported = Bindings(macros = [
|
||||||
|
"@ballocated", "@belapsed", "@benchmark", "@benchmarkable",
|
||||||
|
"@benchmarkset", "@bprofile", "@btime", "@case", "@tagged"])),
|
||||||
|
PkgAutoloads(:CRC32c, exported = Bindings(callables = [:crc32c])),
|
||||||
|
PkgAutoloads(:CSV),
|
||||||
|
PkgAutoloads(:Cthulhu, exported = Bindings(
|
||||||
|
macros = ["@decend", "@decend_code_typed", "@decend_code_warntype"],
|
||||||
|
callables = [:ascend, :descend, :descend_code_typed, :descend_code_warntype])),
|
||||||
|
PkgAutoloads(
|
||||||
|
:DataFrames,
|
||||||
|
exported = Bindings(callables = [
|
||||||
|
:AbstractDataFrame, :All, :AsTable, :Between, :ByRow, :Cols,
|
||||||
|
:DataFrame, :DataFrameRow, :DataFrames, :GroupedDataFrame,
|
||||||
|
:InvertedIndex, :InvertedIndices, :Missing, :MissingException,
|
||||||
|
:Missings, :Not, :PrettyTables, :SubDataFrame, :Tables, :aggregate,
|
||||||
|
:allcombinations, :allowmissing, :allowmissing!, :antijoin, :by,
|
||||||
|
:coalesce, :colmetadata, :colmetadata!, :colmetadatakeys,
|
||||||
|
:columnindex, :combine, :completecases, :crossjoin, :delete!,
|
||||||
|
:deletecolmetadata!, :deletemetadata!, :disallowmissing,
|
||||||
|
:disallowmissing!, :dropmissing, :dropmissing!, :emptycolmetadata!,
|
||||||
|
:emptymetadata!, :emptymissing, :fillcombinations, :flatten,
|
||||||
|
:groupby, :groupcols, :groupindices, :innerjoin, :insertcols,
|
||||||
|
:insertcols!, :ismissing, :leftjoin, :leftjoin!, :levels, :mapcols,
|
||||||
|
:mapcols!, :metadata, :metadata!, :metadatakeys, :missing,
|
||||||
|
:missings, :ncol, :nonmissingtype, :nonunique, :nrow, :order,
|
||||||
|
:outerjoin, :passmissing, :proprow, :rename, :rename!, :repeat!,
|
||||||
|
:rightjoin, :rownumber, :select, :select!, :semijoin, :skipmissings,
|
||||||
|
:subset, :subset!, :transform, :transform!, :unique!, :unstack,
|
||||||
|
:valuecols])),
|
||||||
|
PkgAutoloads(
|
||||||
|
:DataToolkit,
|
||||||
|
exported = Bindings(
|
||||||
|
macros = ["@d_str", "@data_cmd", "@import"],
|
||||||
|
callables = [:DataSet, :DataToolkit, :dataset, :loadcollection!])),
|
||||||
|
PkgAutoloads(
|
||||||
|
:Dates,
|
||||||
|
exported = Bindings(
|
||||||
|
macros = ["@dateformat_str"],
|
||||||
|
callables = [
|
||||||
|
:Apr, :April, :Aug, :August, :Date, :DateFormat, :DatePeriod,
|
||||||
|
:DateTime, :Dates, :Day, :Dec, :December, :Feb, :February, :Fri,
|
||||||
|
:Friday, :Hour, :ISODateFormat, :ISODateTimeFormat,
|
||||||
|
:ISOTimeFormat, :Jan, :January, :Jul, :July, :Jun, :June, :Mar,
|
||||||
|
:March, :May, :Microsecond, :Millisecond, :Minute, :Mon,
|
||||||
|
:Monday, :Month, :Nanosecond, :Nov, :November, :Oct, :October,
|
||||||
|
:Period, :Quarter, :RFC1123Format, :Sat, :Saturday, :Second,
|
||||||
|
:Sep, :September, :Sun, :Sunday, :Thu, :Thursday, :Time,
|
||||||
|
:TimePeriod, :TimeType, :TimeZone, :Tue, :Tuesday, :UTC, :Wed,
|
||||||
|
:Wednesday, :Week, :Year, :adjust, :canonicalize,
|
||||||
|
:datetime2julian, :datetime2rata, :datetime2unix, :day,
|
||||||
|
:dayabbr, :dayname, :dayofmonth, :dayofquarter, :dayofweek,
|
||||||
|
:dayofweekofmonth, :dayofyear, :daysinmonth, :daysinyear,
|
||||||
|
:daysofweekinmonth, :firstdayofmonth, :firstdayofquarter,
|
||||||
|
:firstdayofweek, :firstdayofyear, :hour, :isleapyear,
|
||||||
|
:julian2datetime, :lastdayofmonth, :lastdayofquarter,
|
||||||
|
:lastdayofweek, :lastdayofyear, :microsecond, :millisecond,
|
||||||
|
:minute, :month, :monthabbr, :monthday, :monthname, :nanosecond,
|
||||||
|
:now, :quarterofyear, :rata2datetime, :second, :today, :tofirst,
|
||||||
|
:tolast, :tonext, :toprev, :unix2datetime, :week, :year,
|
||||||
|
:yearmonth, :yearmonthday])),
|
||||||
|
PkgAutoloads(:Debugger, exported = Bindings(macros = ["@enter", "@run"])),
|
||||||
|
PkgAutoloads(
|
||||||
|
:Distributed,
|
||||||
|
exported = Bindings(
|
||||||
|
macros = ["@distributed", "@everywhere", "@fetch", "@fetchfrom", "@spawnat"],
|
||||||
|
callables = [
|
||||||
|
:AbstractWorkerPool, :CachingPool, :ClusterManager, :Future,
|
||||||
|
:ProcessExitedException, :RemoteChannel, :RemoteException,
|
||||||
|
:WorkerConfig, :WorkerPool, :addprocs, :channel_from_id,
|
||||||
|
:check_same_host, :clear!, :cluster_cookie,
|
||||||
|
:default_worker_pool, :init_worker, :interrupt, :launch,
|
||||||
|
:manage, :myid, :nprocs, :nworkers, :pmap, :process_messages,
|
||||||
|
:procs, :remote, :remote_do, :remotecall, :remotecall_fetch,
|
||||||
|
:remotecall_wait, :remoteref_id, :rmprocs, :start_worker,
|
||||||
|
:worker_id_from_socket, :workers])),
|
||||||
|
PkgAutoloads(
|
||||||
|
:Distributions,
|
||||||
|
exported = Bindings(callables = [
|
||||||
|
:AbstractMixtureModel, :AbstractMvNormal, :Arcsine,
|
||||||
|
:ArrayLikeVariate, :Bernoulli, :BernoulliLogit, :Beta,
|
||||||
|
:BetaBinomial, :BetaPrime, :Binomial, :Biweight, :Categorical,
|
||||||
|
:Cauchy, :Chernoff, :Chi, :Chisq, :CholeskyVariate, :Continuous,
|
||||||
|
:ContinuousDistribution, :ContinuousMatrixDistribution,
|
||||||
|
:ContinuousMultivariateDistribution,
|
||||||
|
:ContinuousUnivariateDistribution, :Cosine, :DiagNormal,
|
||||||
|
:DiagNormalCanon, :Dirac, :Dirichlet, :DirichletMultinomial,
|
||||||
|
:Discrete, :DiscreteDistribution, :DiscreteMatrixDistribution,
|
||||||
|
:DiscreteMultivariateDistribution, :DiscreteNonParametric,
|
||||||
|
:DiscreteUniform, :DiscreteUnivariateDistribution, :Distribution,
|
||||||
|
:DoubleExponential, :EdgeworthMean, :EdgeworthSum, :EdgeworthZ,
|
||||||
|
:Epanechnikov, :Erlang, :Estimator, :Exponential, :FDist,
|
||||||
|
:FisherNoncentralHypergeometric, :Frechet, :FullNormal,
|
||||||
|
:FullNormalCanon, :Gamma, :GeneralizedExtremeValue,
|
||||||
|
:GeneralizedPareto, :Geometric, :Gumbel, :Hypergeometric,
|
||||||
|
:InverseGamma, :InverseGaussian, :InverseWishart, :IsoNormal,
|
||||||
|
:IsoNormalCanon, :JohnsonSU, :JointOrderStatistics, :KSDist,
|
||||||
|
:KSOneSided, :Kolmogorov, :Kumaraswamy, :LKJ, :LKJCholesky,
|
||||||
|
:Laplace, :Levy, :Lindley, :LocationScale, :LogNormal, :LogUniform,
|
||||||
|
:Logistic, :LogitNormal, :MLEstimator, :MatrixBeta,
|
||||||
|
:MatrixDistribution, :MatrixFDist, :MatrixNormal, :MatrixReshaped,
|
||||||
|
:MatrixTDist, :Matrixvariate, :MixtureModel, :Multinomial,
|
||||||
|
:Multivariate, :MultivariateDistribution, :MultivariateMixture,
|
||||||
|
:MultivariateNormal, :MvLogNormal, :MvNormal, :MvNormalCanon,
|
||||||
|
:MvNormalKnownCov, :MvTDist, :NegativeBinomial,
|
||||||
|
:NonMatrixDistribution, :NoncentralBeta, :NoncentralChisq,
|
||||||
|
:NoncentralF, :NoncentralHypergeometric, :NoncentralT, :Normal,
|
||||||
|
:NormalCanon, :NormalInverseGaussian, :OrderStatistic,
|
||||||
|
:PGeneralizedGaussian, :Pareto, :Poisson, :PoissonBinomial,
|
||||||
|
:Product, :QQPair, :Rayleigh, :RealInterval, :Rician, :Sampleable,
|
||||||
|
:Semicircle, :Skellam, :SkewNormal, :SkewedExponentialPower,
|
||||||
|
:Soliton, :StudentizedRange, :SufficientStats, :SymTriangularDist,
|
||||||
|
:TDist, :TriangularDist, :Triweight, :Truncated, :TruncatedNormal,
|
||||||
|
:Uniform, :Univariate, :UnivariateDistribution, :UnivariateGMM,
|
||||||
|
:UnivariateMixture, :ValueSupport, :VariateForm, :VonMises,
|
||||||
|
:VonMisesFisher, :WalleniusNoncentralHypergeometric, :Weibull,
|
||||||
|
:Wishart, :ZeroMeanDiagNormal, :ZeroMeanDiagNormalCanon,
|
||||||
|
:ZeroMeanFullNormal, :ZeroMeanFullNormalCanon, :ZeroMeanIsoNormal,
|
||||||
|
:ZeroMeanIsoNormalCanon, :canonform, :ccdf, :cdf, :censored, :cf,
|
||||||
|
:cgf, :circvar, :component, :components, :componentwise_logpdf,
|
||||||
|
:componentwise_pdf, :concentration, :convolve, :cquantile,
|
||||||
|
:estimate, :expected_logdet, :failprob, :fit_mle, :gradlogpdf,
|
||||||
|
:hasfinitesupport, :insupport, :invcov, :invlogccdf, :invlogcdf,
|
||||||
|
:invscale, :isbounded, :isleptokurtic, :islowerbounded,
|
||||||
|
:ismesokurtic, :isplatykurtic, :isprobvec, :isupperbounded,
|
||||||
|
:location, :location!, :logccdf, :logcdf, :logdetcov, :logdiffcdf,
|
||||||
|
:logpdf, :logpdf!, :meandir, :meanform, :meanlogx, :mgf,
|
||||||
|
:ncategories, :ncomponents, :nsamples, :ntrials, :partype, :pdf,
|
||||||
|
:pdfsquaredL2norm, :probs, :probval, :product_distribution,
|
||||||
|
:qqbuild, :rate, :sampler, :scale, :scale!, :shape, :sqmahal,
|
||||||
|
:sqmahal!, :stdlogx, :succprob, :suffstats, :support, :truncated,
|
||||||
|
:varlogx])),
|
||||||
|
PkgAutoloads(
|
||||||
|
:Downloads,
|
||||||
|
exported = Bindings(callables = [
|
||||||
|
:Downloader, :RequestError, :Response, :download, :request])),
|
||||||
|
PkgAutoloads(:JET, exported = Bindings(
|
||||||
|
macros = ["@report_call", "@report_opt", "@test_call", "@test_opt"],
|
||||||
|
callables = [:AnyFrameModule, :LastFrameModule, :report_call,
|
||||||
|
:report_file, :report_opt, :report_package, :report_text,
|
||||||
|
:test_call, :test_file, :test_opt, :test_package,
|
||||||
|
:test_text, :watch_file])),
|
||||||
|
PkgAutoloads(:JSON3),
|
||||||
|
PkgAutoloads(
|
||||||
|
:LinearAlgebra,
|
||||||
|
exported = Bindings(callables = [
|
||||||
|
:Adjoint, :BLAS, :Bidiagonal, :BunchKaufman, :Cholesky,
|
||||||
|
:CholeskyPivoted, :ColumnNorm, :Diagonal, :Eigen, :Factorization,
|
||||||
|
:GeneralizedEigen, :GeneralizedSVD, :GeneralizedSchur, :Hermitian,
|
||||||
|
:Hessenberg, :I, :LAPACK, :LAPACKException, :LDLt, :LQ, :LU,
|
||||||
|
:LinearAlgebra, :LowerTriangular, :NoPivot, :PosDefException, :QR,
|
||||||
|
:QRPivoted, :RankDeficientException, :RowMaximum, :RowNonZero, :SVD,
|
||||||
|
:Schur, :SingularException, :SymTridiagonal, :Symmetric, :Transpose,
|
||||||
|
:Tridiagonal, :UniformScaling, :UnitLowerTriangular,
|
||||||
|
:UnitUpperTriangular, :UpperHessenberg, :UpperTriangular,
|
||||||
|
:ZeroPivotException, :adjoint!, :axpby!, :axpy!, :bunchkaufman,
|
||||||
|
:bunchkaufman!, :cholesky, :cholesky!, :cond, :condskeel,
|
||||||
|
:copy_transpose!, :copyto!, :cross, :det, :diag, :diagind, :diagm,
|
||||||
|
:dot, :eigen, :eigen!, :eigmax, :eigmin, :eigvals, :eigvals!,
|
||||||
|
:eigvecs, :factorize, :givens, :hessenberg, :hessenberg!, :isdiag,
|
||||||
|
:ishermitian, :isposdef, :isposdef!, :issuccess, :issymmetric,
|
||||||
|
:istril, :istriu, :kron, :kron!, :ldiv!, :ldlt, :ldlt!, :lmul!,
|
||||||
|
:logabsdet, :logdet, :lowrankdowndate, :lowrankdowndate!,
|
||||||
|
:lowrankupdate, :lowrankupdate!, :lq, :lq!, :lu, :lu!, :lyap, :mul!,
|
||||||
|
:norm, :normalize, :normalize!, :nullspace, :opnorm, :ordschur,
|
||||||
|
:ordschur!, :pinv, :qr, :qr!, :rank, :rdiv!, :reflect!, :rmul!,
|
||||||
|
:rotate!, :schur, :schur!, :svd, :svd!, :svdvals, :svdvals!,
|
||||||
|
:sylvester, :tr, :transpose, :transpose!, :tril, :tril!, :triu,
|
||||||
|
:triu!, :×, :⋅])),
|
||||||
|
PkgAutoloads(:Markdown, exported =
|
||||||
|
Bindings(macros = ["@doc_str", "@md_str"],
|
||||||
|
callables = [:html, :latex])),
|
||||||
|
PkgAutoloads(:Mmap, exported = Bindings(callables = [:mmap])),
|
||||||
|
PkgAutoloads(:Org, exported = Bindings(
|
||||||
|
macros = ["@org_str"],
|
||||||
|
callables = [:Org, :OrgDoc, :org, :parsetree, :tableofcontents, :term])),
|
||||||
|
PkgAutoloads(:Pkg, exported = Bindings(macros = ["@pkg_str"])),
|
||||||
|
PkgAutoloads(:Printf, exported = Bindings(macros = ["@printf"])),
|
||||||
|
PkgAutoloads(:Random, exported = Bindings(callables = [
|
||||||
|
:AbstractRNG, :MersenneTwister, :Random, :RandomDevice, :TaskLocalRNG,
|
||||||
|
:Xoshiro, :bitrand, :rand!, :randcycle, :randcycle!, :randexp,
|
||||||
|
:randexp!, :randn!, :randperm, :randperm!, :randstring, :randsubseq,
|
||||||
|
:randsubseq!, :shuffle, :shuffle!])),
|
||||||
|
PkgAutoloads(:REPL, exported = Bindings(callables =
|
||||||
|
[:AbstractREPL, :BasicREPL, :LineEditREPL, :StreamREPL])),
|
||||||
|
PkgAutoloads(:SHA, exported = Bindings(callables =
|
||||||
|
[:HMAC_CTX, :SHA1_CTX, :SHA224_CTX, :SHA256_CTX, :SHA2_224_CTX,
|
||||||
|
:SHA2_256_CTX, :SHA2_384_CTX, :SHA2_512_CTX, :SHA384_CTX, :SHA3_224_CTX,
|
||||||
|
:SHA3_256_CTX, :SHA3_384_CTX, :SHA3_512_CTX, :SHA512_CTX, :digest!,
|
||||||
|
:hmac_sha1, :hmac_sha224, :hmac_sha256, :hmac_sha2_224, :hmac_sha2_256,
|
||||||
|
:hmac_sha2_384, :hmac_sha2_512, :hmac_sha384, :hmac_sha3_224,
|
||||||
|
:hmac_sha3_256, :hmac_sha3_384, :hmac_sha3_512, :hmac_sha512, :sha1,
|
||||||
|
:sha224, :sha256, :sha2_224, :sha2_256, :sha2_384, :sha2_512, :sha384,
|
||||||
|
:sha3_224, :sha3_256, :sha3_384, :sha3_512, :sha512, :update!])),
|
||||||
|
PkgAutoloads(:Serialization, exported = Bindings(callables = [
|
||||||
|
:AbstractSerializer, :Serializer, :deserialize, :serialize])),
|
||||||
|
PkgAutoloads(
|
||||||
|
:Statistics,
|
||||||
|
exported = Bindings(callables = [
|
||||||
|
:cor, :cov, :mean, :mean!, :median, :median!, :middle, :quantile,
|
||||||
|
:quantile!, :std, :stdm, :var, :varm])),
|
||||||
|
PkgAutoloads(
|
||||||
|
:StatsBase,
|
||||||
|
exported = Bindings(callables = [
|
||||||
|
:AbstractDataTransform, :AbstractHistogram, :AbstractWeights,
|
||||||
|
:AnalyticWeights, :CoefTable, :ConvergenceException,
|
||||||
|
:CovarianceEstimator, :CronbachAlpha, :ECDF, :FrequencyWeights,
|
||||||
|
:Histogram, :L1dist, :L2dist, :Linfdist, :ProbabilityWeights,
|
||||||
|
:SimpleCovariance, :UnitRangeTransform, :UnitWeights, :Weights,
|
||||||
|
:ZScoreTransform, :addcounts!, :autocor, :autocor!, :autocov,
|
||||||
|
:autocov!, :aweights, :competerank, :cor2cov, :corkendall,
|
||||||
|
:corspearman, :counteq, :countmap, :countne, :counts, :cov2cor,
|
||||||
|
:cronbachalpha, :crosscor, :crosscor!, :crosscov, :crosscov!,
|
||||||
|
:crossentropy, :cumulant, :denserank, :ecdf, :entropy, :eweights,
|
||||||
|
:fweights, :genmean, :genvar, :geomean, :gkldiv, :harmmean,
|
||||||
|
:indexmap, :indicatormat, :inverse_rle, :iqr, :kldivergence,
|
||||||
|
:kurtosis, :levelsmap, :mad, :mad!, :maxad, :mean_and_cov,
|
||||||
|
:mean_and_std, :mean_and_var, :meanad, :midpoints, :mode,
|
||||||
|
:model_response, :modes, :moment, :msd, :norepeats, :nquantile,
|
||||||
|
:ordinalrank, :pacf, :pacf!, :partialcor, :percentile,
|
||||||
|
:percentilerank, :proportionmap, :proportions, :psnr, :pweights,
|
||||||
|
:quantilerank, :renyientropy, :rle, :rmsd, :sample, :sample!,
|
||||||
|
:samplepair, :scattermat, :scattermat_zm, :scattermatm, :sem,
|
||||||
|
:skewness, :span, :sqL2dist, :standardize, :summarystats, :tiedrank,
|
||||||
|
:totalvar, :trim, :trim!, :trimvar, :uweights, :variation, :winsor,
|
||||||
|
:winsor!, :wmedian, :wquantile, :wsample, :wsample!, :wsum, :wsum!,
|
||||||
|
:zscore, :zscore!])),
|
||||||
|
PkgAutoloads(:TOML),
|
||||||
|
PkgAutoloads(:Tar),
|
||||||
|
PkgAutoloads(:Test, exported =
|
||||||
|
Bindings(macros = ["@inferred", "@test", "@test_broken",
|
||||||
|
"@test_deprecated", "@test_logs", "@test_nowarn",
|
||||||
|
"@test_skip", "@test_throws", "@test_warn",
|
||||||
|
"@testset"],
|
||||||
|
callables = [:GenericArray, :GenericDict, :GenericOrder,
|
||||||
|
:GenericSet, :GenericString, :LogRecord,
|
||||||
|
:TestLogger, :TestSetException,
|
||||||
|
:detect_ambiguities, :detect_unbound_args])),
|
||||||
|
PkgAutoloads(:UUIDs, exported = Bindings(callables = [
|
||||||
|
:uuid1, :uuid4, :uuid5, :uuid_version])),
|
||||||
|
PkgAutoloads(:WhyNotEqual, exported = Bindings(callables = [:whynot])),
|
||||||
|
])
|
|
@ -0,0 +1,270 @@
|
||||||
|
module Autoloads
|
||||||
|
|
||||||
|
using TOML
|
||||||
|
using REPL
|
||||||
|
|
||||||
|
export Bindings, AutoDot, PkgAutoloads, add_autoloads!
|
||||||
|
|
||||||
|
function __init__()
|
||||||
|
if isinteractive()
|
||||||
|
read_named_envs!()
|
||||||
|
repl_apply_autoloads!()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
struct Bindings
|
||||||
|
macros::Vector{Symbol}
|
||||||
|
callables::Vector{Symbol}
|
||||||
|
variables::Vector{Symbol}
|
||||||
|
end
|
||||||
|
|
||||||
|
struct AutoDot end
|
||||||
|
|
||||||
|
Bindings(; macros::Vector{<:Union{Symbol, String}}=Symbol[],
|
||||||
|
callables::Vector{Symbol}=Symbol[], variables=Symbol[]) =
|
||||||
|
Bindings(Symbol.(macros), callables, variables)
|
||||||
|
|
||||||
|
struct PkgAutoloads
|
||||||
|
pkg::Union{Symbol, Expr}
|
||||||
|
exported::Bindings
|
||||||
|
unexported::Union{Bindings, AutoDot}
|
||||||
|
partial::Bool
|
||||||
|
end
|
||||||
|
|
||||||
|
PkgAutoloads(pkg::Union{Symbol, Expr};
|
||||||
|
exported::Bindings = Bindings(Symbol[], Symbol[], Symbol[]),
|
||||||
|
unexported::Union{Bindings, AutoDot} = AutoDot(),
|
||||||
|
partial::Bool = false) =
|
||||||
|
PkgAutoloads(pkg, exported, unexported, partial)
|
||||||
|
|
||||||
|
function PkgAutoloads(mod::Module)
|
||||||
|
hasparent(u::Union, m::Module) =
|
||||||
|
hasparent(u.a, m) && hasparent(u.b, m)
|
||||||
|
hasparent(x::Any, m::Module) =
|
||||||
|
parentmodule(x) === m
|
||||||
|
macros = Symbol[]
|
||||||
|
callables = Symbol[]
|
||||||
|
variables = Symbol[]
|
||||||
|
for symb in names(mod)
|
||||||
|
obj = getglobal(mod, symb)
|
||||||
|
if !hasparent(obj, mod) || obj === mod
|
||||||
|
elseif startswith(String(symb), '@')
|
||||||
|
push!(macros, symb)
|
||||||
|
elseif obj isa Function || obj isa Type
|
||||||
|
push!(callables, symb)
|
||||||
|
else
|
||||||
|
push!(variables, symb)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
PkgAutoloads(nameof(mod),
|
||||||
|
exported = Bindings(
|
||||||
|
macros, callables, variables))
|
||||||
|
end
|
||||||
|
|
||||||
|
const AUTOLOADS =
|
||||||
|
(sources = Dict{Symbol, PkgAutoloads}(),
|
||||||
|
pkgs = Dict{Symbol, Expr}(),
|
||||||
|
exported = (
|
||||||
|
macros = Dict{Symbol, Symbol}(),
|
||||||
|
callables = Dict{Symbol, Symbol}(),
|
||||||
|
variables = Dict{Symbol, Symbol}()),
|
||||||
|
bindings = (
|
||||||
|
macros = Dict{Symbol, Set{Symbol}}(),
|
||||||
|
callables = Dict{Symbol, Set{Symbol}}(),
|
||||||
|
variables = Dict{Symbol, Set{Symbol}}()),
|
||||||
|
ondotaccess = Set{Symbol}(),
|
||||||
|
loaded = Set{Symbol}(),
|
||||||
|
partloaded = Dict{Symbol, Set{Symbol}}())
|
||||||
|
|
||||||
|
function add_autoloads!(autos::PkgAutoloads)
|
||||||
|
!haskey(AUTOLOADS.sources, autos.pkg) ||
|
||||||
|
error("Autoloads for $(autos.pkg) have already been registered")
|
||||||
|
pkgsym, pkg = if autos.pkg isa Symbol
|
||||||
|
autos.pkg, Expr(:., autos.pkg)
|
||||||
|
elseif autos.pkg isa Expr &&
|
||||||
|
Meta.isexpr(autos.pkg, :(.)) &&
|
||||||
|
length(autos.pkg.args) == 2 &&
|
||||||
|
autos.pkg.args[1] isa Symbol &&
|
||||||
|
autos.pkg.args[2] isa QuoteNode &&
|
||||||
|
autos.pkg.args[2].value isa Symbol
|
||||||
|
autos.pkg.args[2].value,
|
||||||
|
Expr(:., autos.pkg.args[1], autos.pkg.args[2].value)
|
||||||
|
end
|
||||||
|
AUTOLOADS.sources[pkgsym] = autos
|
||||||
|
AUTOLOADS.pkgs[pkgsym] = pkg
|
||||||
|
autos.partial && (AUTOLOADS.partloaded[pkgsym] = Set{Symbol}())
|
||||||
|
AUTOLOADS.exported.variables[pkgsym] = pkgsym
|
||||||
|
for category in (:macros, :callables, :variables)
|
||||||
|
autodot = autos.unexported isa AutoDot
|
||||||
|
bindings = autodot || Set(getfield(autos.unexported, category))
|
||||||
|
slots = getfield(AUTOLOADS.exported, category)
|
||||||
|
for binding in getfield(autos.exported, category)
|
||||||
|
if haskey(slots, binding)
|
||||||
|
@warn "An autload for $(String(category)[1:end-1]) $binding already exists"
|
||||||
|
else
|
||||||
|
slots[binding] = pkgsym
|
||||||
|
end
|
||||||
|
autodot || push!(bindings, binding)
|
||||||
|
end
|
||||||
|
if !autodot && !isempty(bindings)
|
||||||
|
getfield(AUTOLOADS.bindings, category)[pkgsym] = bindings
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
const NAMED_ENVS = Vector{Pair{String, Vector{Symbol}}}()
|
||||||
|
|
||||||
|
function read_named_envs!()
|
||||||
|
empty!(NAMED_ENVS)
|
||||||
|
for depot in Base.DEPOT_PATH
|
||||||
|
envdir = joinpath(depot, "environments")
|
||||||
|
isdir(envdir) || continue
|
||||||
|
for env in readdir(envdir)
|
||||||
|
if !isnothing(match(r"^__", env))
|
||||||
|
elseif !isnothing(match(r"^v\d+\.\d+$", env))
|
||||||
|
elseif isfile(joinpath(envdir, env, "Project.toml"))
|
||||||
|
proj = open(TOML.parse, joinpath(envdir, env, "Project.toml"))
|
||||||
|
pkgs = get(proj, "deps", Dict{String, Any}()) |>
|
||||||
|
keys |> collect |> sort .|> Symbol
|
||||||
|
push!(NAMED_ENVS, '@' * env => pkgs)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function find_named_env(pkg::Symbol)
|
||||||
|
for (env, pkgs) in NAMED_ENVS
|
||||||
|
if pkg in pkgs
|
||||||
|
return env
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function autoload_loadpkg(name::Symbol, thing::Union{Symbol, Nothing}=nothing)
|
||||||
|
if name ∉ AUTOLOADS.loaded && haskey(AUTOLOADS.pkgs, name)
|
||||||
|
AUTOLOADS.sources[name].partial && thing in AUTOLOADS.partloaded[name] &&
|
||||||
|
return
|
||||||
|
pkg = AUTOLOADS.pkgs[name]
|
||||||
|
if length(pkg.args) == 1 && isnothing(Base.find_package(String(first(pkg.args))))
|
||||||
|
named_env = find_named_env(name)
|
||||||
|
if !isnothing(named_env)
|
||||||
|
autoload_loadpkg_namedenv(name, named_env, thing)
|
||||||
|
else
|
||||||
|
@warn "Cannot autoload $name, as it is not availible in the current environment stack"
|
||||||
|
end
|
||||||
|
return
|
||||||
|
end
|
||||||
|
try
|
||||||
|
if !isnothing(thing) && AUTOLOADS.sources[name].partial
|
||||||
|
Core.eval(Main, Expr(:import, Expr(:., pkg.args..., thing)))
|
||||||
|
push!(AUTOLOADS.partloaded[name], thing)
|
||||||
|
else
|
||||||
|
Core.eval(Main, Expr(:using, pkg))
|
||||||
|
push!(AUTOLOADS.loaded, name)
|
||||||
|
end
|
||||||
|
nothing
|
||||||
|
catch err
|
||||||
|
@warn "Failed to automatically load $name" err
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function autoload_loadpkg_namedenv(name::Symbol, env::String, thing::Union{Symbol, Nothing}=nothing)
|
||||||
|
pkg = AUTOLOADS.pkgs[name]
|
||||||
|
if Base.active_project() == Base.load_path_expand("@v#.#")
|
||||||
|
pushfirst!(LOAD_PATH, env)
|
||||||
|
try
|
||||||
|
if !isnothing(thing) && AUTOLOADS.sources[name].partial
|
||||||
|
Core.eval(Main, Expr(:import, Expr(:., pkg.args..., thing)))
|
||||||
|
push!(AUTOLOADS.partloaded[name], thing)
|
||||||
|
else
|
||||||
|
Core.eval(Main, Expr(:using, pkg))
|
||||||
|
push!(AUTOLOADS.loaded, name)
|
||||||
|
end
|
||||||
|
finally
|
||||||
|
popfirst!(LOAD_PATH)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
@warn "Cannot autoload $name, but it is availible in the $env environment"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function autoload_scan!(ast::Expr, localbindings::Vector{Symbol}=Symbol[])
|
||||||
|
if Meta.isexpr(ast, :macrocall)
|
||||||
|
pkg = if first(ast.args) isa Symbol && first(ast.args) ∉ localbindings
|
||||||
|
get(AUTOLOADS.exported.macros, first(ast.args), nothing)
|
||||||
|
elseif Meta.isexpr(first(ast.args), :(.)) &&
|
||||||
|
length(first(ast.args).args) == 2 &&
|
||||||
|
(root = first(ast.args).args[1]) isa Symbol &&
|
||||||
|
first(ast.args).args[2] isa QuoteNode &&
|
||||||
|
(child = first(ast.args).args[2].value) isa Symbol &&
|
||||||
|
haskey(AUTOLOADS.bindings.macros, root) &&
|
||||||
|
haskey(AUTOLOADS.bindings.macros[root], child)
|
||||||
|
AUTOLOADS.bindings.macros[root]
|
||||||
|
end
|
||||||
|
if !isnothing(pkg) autoload_loadpkg(pkg, first(ast.args)) end
|
||||||
|
elseif Meta.isexpr(ast, :call)
|
||||||
|
pkg = if first(ast.args) isa Symbol && first(ast.args) ∉ localbindings
|
||||||
|
get(AUTOLOADS.exported.callables, first(ast.args), nothing)
|
||||||
|
elseif Meta.isexpr(first(ast.args), :(.)) &&
|
||||||
|
(root = first(ast.args).args[1]) isa Symbol &&
|
||||||
|
root ∈ AUTOLOADS.ondotaccess
|
||||||
|
root
|
||||||
|
elseif Meta.isexpr(first(ast.args), :(.)) &&
|
||||||
|
length(first(ast.args).args) == 2 &&
|
||||||
|
(root = first(ast.args).args[1]) isa Symbol &&
|
||||||
|
first(ast.args).args[2] isa QuoteNode &&
|
||||||
|
(child = first(ast.args).args[2].value) isa Symbol &&
|
||||||
|
haskey(AUTOLOADS.bindings.callables, root) &&
|
||||||
|
child ∈ AUTOLOADS.bindings.callables[root]
|
||||||
|
root
|
||||||
|
end
|
||||||
|
isnothing(pkg) || autoload_loadpkg(pkg, first(ast.args))
|
||||||
|
elseif Meta.isexpr(ast, :(.)) &&
|
||||||
|
length(ast.args) == 2 &&
|
||||||
|
(root = ast.args[1]) isa Symbol &&
|
||||||
|
ast.args[2] isa QuoteNode &&
|
||||||
|
(child = ast.args[2].value) isa Symbol &&
|
||||||
|
(root ∈ AUTOLOADS.ondotaccess ||
|
||||||
|
(haskey(AUTOLOADS.bindings.variables, root) &&
|
||||||
|
child ∈ AUTOLOADS.bindings.variables[root]) ||
|
||||||
|
(haskey(AUTOLOADS.bindings.callables, root) &&
|
||||||
|
child ∈ AUTOLOADS.bindings.callables[root]))
|
||||||
|
autoload_loadpkg(root)
|
||||||
|
elseif ast.head ∈ (:using, :import, :quote)
|
||||||
|
return
|
||||||
|
elseif Meta.isexpr(ast, :(=)) && first(ast.args) isa Symbol
|
||||||
|
push!(localbindings, first(ast.args))
|
||||||
|
end
|
||||||
|
for arg in ast.args
|
||||||
|
autoload_scan!(arg, localbindings)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function autoload_scan!(var::Symbol, localbindings::Vector{Symbol}=Symbol[])
|
||||||
|
if var ∉ localbindings && var ∉ names(Main)
|
||||||
|
pkg = @something(get(AUTOLOADS.exported.variables, var, nothing),
|
||||||
|
get(AUTOLOADS.exported.callables, var, nothing),
|
||||||
|
Some(nothing))
|
||||||
|
if !isnothing(pkg) autoload_loadpkg(pkg, var) end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
autoload_scan!(::Any, ::Vector{Symbol}=Symbol[]) = nothing
|
||||||
|
|
||||||
|
function repl_scan_autoloads!(ast::Expr)
|
||||||
|
@static if VERSION < v"1.9"
|
||||||
|
autoload_scan!(ast)
|
||||||
|
else
|
||||||
|
if Base.active_module() == Main
|
||||||
|
autoload_scan!(ast)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
ast
|
||||||
|
end
|
||||||
|
repl_scan_autoloads!(val::Any) = val
|
||||||
|
|
||||||
|
repl_apply_autoloads!() =
|
||||||
|
pushfirst!(REPL.repl_ast_transforms, repl_scan_autoloads!)
|
||||||
|
|
||||||
|
end
|
|
@ -0,0 +1,71 @@
|
||||||
|
import Base.!, Base.~
|
||||||
|
|
||||||
|
"""
|
||||||
|
~(cmd::AbstractCmd)
|
||||||
|
|
||||||
|
Run `cmd` and return the output as a string.
|
||||||
|
|
||||||
|
```julia-repl
|
||||||
|
julia> ~ `ls /home`
|
||||||
|
"doe"
|
||||||
|
```
|
||||||
|
"""
|
||||||
|
function ~(c::Base.AbstractCmd)
|
||||||
|
strip(read(c, String), '\n')
|
||||||
|
end
|
||||||
|
|
||||||
|
"""
|
||||||
|
!(cmd::AbstractCmd)
|
||||||
|
|
||||||
|
Run `cmd` and print the output to stdout.
|
||||||
|
|
||||||
|
```julia-repl
|
||||||
|
julia> ! `ls /home`
|
||||||
|
doe
|
||||||
|
```
|
||||||
|
|
||||||
|
This can also be combined with `~ cmd` to print and return
|
||||||
|
the output by using `!~ cmd`.
|
||||||
|
```julia-repl
|
||||||
|
julia> !~ `ls /home`
|
||||||
|
doe
|
||||||
|
"doe"
|
||||||
|
```
|
||||||
|
"""
|
||||||
|
function !(c::Base.AbstractCmd)
|
||||||
|
println(~c)
|
||||||
|
end
|
||||||
|
function !(o::SubString{String})
|
||||||
|
println(o)
|
||||||
|
o
|
||||||
|
end
|
||||||
|
|
||||||
|
struct PipeCmds <: Base.AbstractCmd
|
||||||
|
cmds::Vector{<:Base.AbstractCmd}
|
||||||
|
PipeCmds(left::Base.AbstractCmd, right::Base.AbstractCmd) = new([left, right])
|
||||||
|
PipeCmds(left::PipeCmds, right::Base.AbstractCmd) = new([left.cmds; right])
|
||||||
|
PipeCmds(left::Base.AbstractCmd, right::PipeCmds) = new([left; right.cmds])
|
||||||
|
end
|
||||||
|
|
||||||
|
import Base.|
|
||||||
|
|
||||||
|
"""
|
||||||
|
cmd1::AbstractCmd | cmd2::AbstractCmd
|
||||||
|
|
||||||
|
Create a pipleine from `cmd1` to `cmd2`.
|
||||||
|
|
||||||
|
```julia-repl
|
||||||
|
julia> `cat .zshenv` | `wc -l`
|
||||||
|
PipeCmds(Cmd[`cat .zshenv`, `wc -l`])
|
||||||
|
|
||||||
|
When `PipeCmds` are passed to `!` or `~`, the commands contained are
|
||||||
|
expanded inside a `pipeline` call.
|
||||||
|
```
|
||||||
|
"""
|
||||||
|
function (|)(left::Base.AbstractCmd, right::Base.AbstractCmd)
|
||||||
|
PipeCmds(left, right)
|
||||||
|
end
|
||||||
|
|
||||||
|
function ~(c::PipeCmds)
|
||||||
|
strip(read(pipeline(c.cmds...), String), '\n')
|
||||||
|
end
|
|
@ -0,0 +1,79 @@
|
||||||
|
const SETUP_GIT_URL = "https://git.tecosaur.net/tec/Startup.jl"
|
||||||
|
|
||||||
|
const STARTUP_MANAGED_MESSAGE =
|
||||||
|
"# !! Managed by the Setup package !!"
|
||||||
|
|
||||||
|
const STARTUP_CONTENT = """
|
||||||
|
$STARTUP_MANAGED_MESSAGE
|
||||||
|
if VERSION < v"1.7"
|
||||||
|
@warn "Setup disabled as Julia \$VERSION < 1.7 is unsupported"
|
||||||
|
else
|
||||||
|
let pkg_id = Base.PkgId(Base.UUID("44cfe95a-1eb2-52ea-b672-e2afdf69b78f"), "Pkg")
|
||||||
|
Pkg = Base.loaded_modules[pkg_id]
|
||||||
|
isnothing(Base.find_package("Setup")) &&
|
||||||
|
Pkg.develop(path=joinpath(@__DIR__, "Setup"))
|
||||||
|
end
|
||||||
|
|
||||||
|
using Setup
|
||||||
|
|
||||||
|
Setup.ensurepkg("Revise")
|
||||||
|
@async @eval using Revise
|
||||||
|
end
|
||||||
|
"""
|
||||||
|
|
||||||
|
function _install_paths()
|
||||||
|
config = joinpath(first(Base.DEPOT_PATH), "config")
|
||||||
|
startup = joinpath(config, "startup.jl")
|
||||||
|
setup = joinpath(config, "Setup")
|
||||||
|
(; config, startup, setup)
|
||||||
|
end
|
||||||
|
|
||||||
|
function install()
|
||||||
|
(; config, startup, setup) = _install_paths()
|
||||||
|
isdir(config) || mkpath(config)
|
||||||
|
if isfile(startup)
|
||||||
|
if readline(startup) == STARTUP_MANAGED_MESSAGE
|
||||||
|
isdir(setup) && update()
|
||||||
|
else
|
||||||
|
@info "Moving original startup file to $(startup).old"
|
||||||
|
mv(startup, startup * ".old")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
write(startup, STARTUP_CONTENT)
|
||||||
|
if isdir(setup) && !isdir(joinpath(setup, ".git"))
|
||||||
|
@warn "Setup folder exists, but it is not a git repository. Re-creating..."
|
||||||
|
rm(setup, recursive=true)
|
||||||
|
end
|
||||||
|
if !isdir(setup)
|
||||||
|
success(`git clone $SETUP_GIT_URL $setup`) ||
|
||||||
|
@error "Failed to clone $SETUP_GIT_URL"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function uninstall()
|
||||||
|
(; startup, setup) = _install_paths()
|
||||||
|
isfile(startup) && readline(startup) != STARTUP_MANAGED_MESSAGE &&
|
||||||
|
rm(startup)
|
||||||
|
isfile(startup * ".old") && !isfile(startup) && mv(startup * ".old", startup)
|
||||||
|
if isdir(joinpath(setup, ".git")) && !isempty(read(Cmd(`git status --porcelain=v1`, dir=setup)))
|
||||||
|
@warn "Unstaged changes in $(setup)! Manually fix this and try again."
|
||||||
|
elseif isdir(setup)
|
||||||
|
rm(setup, recursive=true, force=true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function update()
|
||||||
|
(; startup, setup) = _install_paths()
|
||||||
|
if readline(startup) != STARTUP_MANAGED_MESSAGE
|
||||||
|
@warn "Startup.jl is not managed by Setup, re-installing"
|
||||||
|
return install()
|
||||||
|
else
|
||||||
|
write(startup, STARTUP_CONTENT)
|
||||||
|
end
|
||||||
|
if !ispath(setup) || !isdir(joinpath(setup, ".git"))
|
||||||
|
ispath(setup) || @warn "Setup missing, re-installing"
|
||||||
|
return install()
|
||||||
|
end
|
||||||
|
success(Cmd(`git pull`, dir=setup)) ||
|
||||||
|
@error "Failed to update Setup"
|
||||||
|
end
|
|
@ -0,0 +1,133 @@
|
||||||
|
module PkgStack
|
||||||
|
|
||||||
|
import Pkg
|
||||||
|
import Markdown: @md_str
|
||||||
|
|
||||||
|
function stack(envs)
|
||||||
|
if isempty(envs)
|
||||||
|
printstyled(" The current stack:\n", bold=true)
|
||||||
|
println.(" " .* LOAD_PATH)
|
||||||
|
else
|
||||||
|
for env in envs
|
||||||
|
if env ∉ LOAD_PATH
|
||||||
|
push!(LOAD_PATH, env)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
const STACK_SPEC = Pkg.REPLMode.CommandSpec(
|
||||||
|
name = "stack",
|
||||||
|
api = stack,
|
||||||
|
help = md"""
|
||||||
|
stack envs...
|
||||||
|
|
||||||
|
Stack another environment.
|
||||||
|
""",
|
||||||
|
description = "Stack another environment",
|
||||||
|
completions = Pkg.REPLMode.complete_activate,
|
||||||
|
should_splat = false,
|
||||||
|
arg_count = 0 => Inf)
|
||||||
|
|
||||||
|
function unstack(envs)
|
||||||
|
if isempty(envs)
|
||||||
|
printstyled(" The current stack:\n", bold=true)
|
||||||
|
println.(" " .* LOAD_PATH)
|
||||||
|
else
|
||||||
|
deleteat!(LOAD_PATH, sort(filter(!isnothing, indexin(envs, LOAD_PATH))))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
const UNSTACK_SPEC = Pkg.REPLMode.CommandSpec(
|
||||||
|
name = "unstack",
|
||||||
|
api = unstack,
|
||||||
|
help = md"""
|
||||||
|
unstack envs...
|
||||||
|
|
||||||
|
Unstack a previously stacked environment.
|
||||||
|
""",
|
||||||
|
description = "Unstack an environment",
|
||||||
|
completions = (_, partial, _, _) ->
|
||||||
|
filter(p -> startswith(p, partial), LOAD_PATH),
|
||||||
|
should_splat = false,
|
||||||
|
arg_count = 0 => Inf)
|
||||||
|
|
||||||
|
function environments()
|
||||||
|
envs = String[]
|
||||||
|
for depot in Base.DEPOT_PATH
|
||||||
|
envdir = joinpath(depot, "environments")
|
||||||
|
isdir(envdir) || continue
|
||||||
|
for env in readdir(envdir)
|
||||||
|
if !isnothing(match(r"^__", env))
|
||||||
|
elseif !isnothing(match(r"^v\d+\.\d+$", env))
|
||||||
|
else
|
||||||
|
push!(envs, '@' * env)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
envs = Base.DEFAULT_LOAD_PATH ∪ LOAD_PATH ∪ envs
|
||||||
|
for env in envs
|
||||||
|
if env in LOAD_PATH
|
||||||
|
print(" ", env)
|
||||||
|
else
|
||||||
|
printstyled(" ", env, color=:light_black)
|
||||||
|
if env in Base.DEFAULT_LOAD_PATH
|
||||||
|
printstyled(" (unloaded)", color=:light_red)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if env == "@"
|
||||||
|
printstyled(" [current environment]", color=:light_black)
|
||||||
|
elseif env == "@v#.#"
|
||||||
|
printstyled(" [global environment]", color=:light_black)
|
||||||
|
elseif env == "@stdlib"
|
||||||
|
printstyled(" [standard library]", color=:light_black)
|
||||||
|
elseif env in LOAD_PATH
|
||||||
|
printstyled(" (loaded)", color=:green)
|
||||||
|
end
|
||||||
|
print('\n')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
const ENVS_SPEC = Pkg.REPLMode.CommandSpec(
|
||||||
|
name = "environments",
|
||||||
|
short_name = "envs",
|
||||||
|
api = environments,
|
||||||
|
help = md"""
|
||||||
|
environments|envs
|
||||||
|
|
||||||
|
List all known named environments.
|
||||||
|
""",
|
||||||
|
description = "List all known named environments",
|
||||||
|
arg_count = 0 => 0)
|
||||||
|
|
||||||
|
const SPECS = Dict(
|
||||||
|
"stack" => STACK_SPEC,
|
||||||
|
"unstack" => UNSTACK_SPEC,
|
||||||
|
"environments" => ENVS_SPEC,
|
||||||
|
"envs" => ENVS_SPEC)
|
||||||
|
|
||||||
|
function __init__()
|
||||||
|
# add the commands to the repl
|
||||||
|
activate = Pkg.REPLMode.SPECS["package"]["activate"]
|
||||||
|
let temp = Pkg.REPLMode.OptionSpec("temp", "t", :temp => true, false)
|
||||||
|
activate.option_specs["temp"] = temp
|
||||||
|
activate.option_specs["t"] = temp
|
||||||
|
end
|
||||||
|
activate_modified = Pkg.REPLMode.CommandSpec(
|
||||||
|
activate.canonical_name,
|
||||||
|
"a", # Modified entry, short name
|
||||||
|
activate.api,
|
||||||
|
activate.should_splat,
|
||||||
|
activate.argument_spec,
|
||||||
|
activate.option_specs,
|
||||||
|
activate.completions,
|
||||||
|
activate.description,
|
||||||
|
activate.help)
|
||||||
|
SPECS["activate"] = activate_modified
|
||||||
|
SPECS["a"] = activate_modified
|
||||||
|
Pkg.REPLMode.SPECS["package"] = merge(Pkg.REPLMode.SPECS["package"], SPECS)
|
||||||
|
# update the help with the new commands
|
||||||
|
copy!(Pkg.REPLMode.help.content, Pkg.REPLMode.gen_help().content)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
|
@ -0,0 +1,153 @@
|
||||||
|
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
|
Loading…
Reference in New Issue