My startup.jl has become a place for tools that are too simple to be behind an import, and probably too opinionated for Base
"""
@subprocess ex
@subprocess ex wait=false
Execute `ex` in a subprocess that mimics the current process configuration.
Returns the constructed `Process`.
See [`Base.julia_cmd`](@ref) for the subprocess configuration forwarding that is used.
```julia-repl
julia> println("hello from $(Base.getpid())")
hello from 35640
julia> @subprocess println("hello from $(Base.getpid())")
hello from 43056
Process(`/home/user/julia/julia -Cnative -J/home/user/julia/usr/lib/julia/sys.dylib -g1 -e 'println("hello from $(Base.getpid())")'`, ProcessExited(0))
```
"""
macro subprocess(ex, wait=true)
quote
local ex_str = $(esc(sprint(Base.show_unquoted,ex)))
run(`$(Base.julia_cmd()) -e "$(ex_str)"`, wait = $(wait))
end
end
# See: https://github.com/IanButterworth/julia/tree/ib/subprocess_macro
"""
@repeat call
@repeat n call
@repeat expr call
Repeat `call` until interrupt, or `n` times, and discard the output.
If an expression is given that returns an Integer, repeat that many times.
If an expression is given that returns a Bool, repeat until false.
```julia
julia> @repeat println("hello")
hello
hello
^ChelloERROR: InterruptException:
...
julia> @repeat 3 println("hello")
hello
hello
hello
julia> @repeat 2 + 1 println("hello")
hello
hello
hello
julia> @repeat rand() > 0.5 println("hello")
hello
hello
```
"""
macro repeat(exs...)
if length(exs) == 1
quote
while true
$(esc(first(exs)))
end
end
elseif length(exs) == 2
terms = first(exs)
ex = last(exs)
if terms <: Integer
quote
for _ = 1:$(esc(terms))
$(esc(ex))
end
end
elseif terms isa Expr
quote
local terms_eval = $(esc(terms))
if terms_eval isa Bool
if terms_eval
$(esc(ex)) # do once given that terms has been evaled once already
while $(esc(terms))
$(esc(ex))
end
end
elseif terms_eval isa Integer
for _ in 1:terms_eval
$(esc(ex))
end
else
throw(ArgumentError("@repeat first argument must return an Integer or a Bool"))
end
end
else
throw(ArgumentError("@repeat first argument must be an Integer literal, or an expression that returns an Integer or Bool"))
end
else
throw(ArgumentError("Too many arguments passed to @repeat"))
end
end
# See: https://github.com/JuliaLang/julia/pull/41455
For @repeat Iβve found the occasional need to quickly run some functions n times, or until something is false, or timedout, particularly when developing hardware controls.
For @subprocess if I wanted to do something in a clean julia session quickly I added that largely because I never set up julia symlinks to julia binaries, so never have a simple julia pointing to the right place.
So
julia> @subprocess println("hello from a new session")
is easier than
julia> run(`$(Base.julia_cmd()) -e "println(\"hello from a new session\")"`
or
shell> /long/path/to/julia -e "println(\"hello from a new session\")"
The first PR wasnβt very popular. The second doesnβt feel like it would be used widely enough for inclusion in Base (?), so I just kept them local
As seen on twitter, a few people have been adding Term.jl to their startup to style logging, errors and repr. Leaving this here in case anyone finds it useful.
try
import Term: install_term_stacktrace, install_term_logger, install_term_repr
install_term_stacktrace()
install_term_logger()
install_term_repr()
catch e
@warn "Error initializing term" exception=(e, catch_backtrace())
end
Since this thread seems to still be alive, I might as well toss what Iβve currently got going on.
import Pkg as var"#Pkg" # Don't import globally
isnothing(Base.find_package("Setup")) &&
var"#Pkg".develop(path=joinpath(@__DIR__, "Setup"))
using Setup
@async let
ESSENTIAL_PACKAGES =
["Revise", "DataFrames", "CSV", "BenchmarkTools"]
EAGER_PACKAGES =
["DataFrames", "Statistics", "StatsBase", "BenchmarkTools"]
for pkg in ESSENTIAL_PACKAGES
if isnothing(Base.find_package(pkg))
var"#Pkg".add(pkg)
end
end
@eval using Revise
for pkg in EAGER_PACKAGES
if !isnothing(Base.find_package(pkg))
Core.eval(Main, :(using $(Symbol(pkg))))
end
end
Setup.termtitle(pwd())
end
where Setup is a whole bunch of setup bundled as a module.
Post-1.9 I donβt have any sysimages, instead I have an environment stack and auto-loading (e.g. starting with nothing loaded, running CSV.read("some/path", DataFrame) in the REPL will automatically load CSV and DataFrames before execution).
I might make my setup public at some point, once Iβve tinkered on it a bit more.