Nice. Thanks.
Does anyone know a decent way to work in a call to load precompiled modules (from package compiler) in the startup file? I.e. Start Julia within Julia with the precompiled modules from an image, but only doing this once.
Being new to and super excited by julia, I find these config tips so inspirational that I can’t help bumping this thread by my two cents:
The following config allows individual startup.jl per project.
using Pkg
let proj = Pkg.project()
startupfile = joinpath(dirname(proj.path), "startup.jl")
isfile(startupfile) && include(startupfile)
end
This comes handy when starting julia into a project with julia --project=<dir>
I use tmux
to manage my projects:
## ... to test if environment is OK
# Do I have a session $PROJECT
tmux has-session -t $PROJECT 2>/dev/null
if [ $? = 0 ]; then
tmux attach-session -t $1
else
if [ $TERM = "screen" ]; then # in a tmux session
echo You are now in a tmux session which will be detached.
echo Please run the command again.
tmux detach-client
else
tmux new-session -d -s $PROJECT \; \
splitw -h -p 66 \; \
splitw -h \; \
splitw -v -p 24 \; \
attach-session \; \
select-pane -t 0 \; \
splitw -v -p 89 \; \
send-keys -t 1 cd\ $ddat Enter \; \
send-keys -t 0 figlet\ -cw\ 99\ $PROJECT Enter \; \
send-keys -t 2 cd\ $dprj/src Enter \; \
send-keys -t 3 cd\ $dprj/src Enter \; \
send-keys -t 3 ec\ $PROJECT.jl Enter \; \
send-keys -t 4 cd\ $dprj Enter \; \
send-keys -t 4 julia Enter \; \
send-keys -t 4 ] \; \
send-keys -t 4 update Enter \; \
send-keys -t 4 activate\ . Enter \; \
send-keys -t 4 update Enter \; \
send-keys -t 4 ^h \; \
send-keys -t 4 using\ Revise Enter \; \
send-keys -t 4 using\ $PROJECT Enter \; \
select-pane -t 2
fi
fi
can of course be improved. tmux
grammer is not very good. This is also for a 32’’ screen. I can then have a project title, a data, 2 editor, and 1 repl panes.
I’d been a Julia user for less than a week before the REPL default format for floats drove me insane. So I put this Google search result in my startup.jl and became less insane. I had no idea what these four lines were really doing for several months after that, but they solved my problem.
using Printf
Base.show(io::IO, f::Float64) = @printf(io, "%1.5e", f)
Base.show(io::IO, f::Float32) = @printf(io, "%1.5e", f)
Base.show(io::IO, f::Float16) = @printf(io, "%1.5e", f)
Here is my updated one.
I gave up on updating all packages
# Disable updating registry on `add` (still runs on `up`), as it is slow
using Pkg: Pkg
Pkg.UPDATED_REGISTRY_THIS_SESSION[] = true
# use more colors for displaying Pkg conflicts
if isdefined(Pkg.Resolve, :CONFLICT_COLORS)
append!(Pkg.Resolve.CONFLICT_COLORS, [21:51; 55:119; 124:142; 160:184; 196:220])
end
# Setup Revise.jl
atreplinit() do repl
try
@eval using Revise
@async Revise.wait_steal_repl_backend()
catch err
println("Error starting Revise $err")
end
end
Has anyone configured ENV[EDITOR"] in their startup.jl to use Visual Studio Code as their editor?
Yes I use ENV["JULIA_EDITOR"] = "code"
and works ok
Other than starting Revise and setting the editor I have a macro for partial application:
module My_partial
export @p
function count_(expr::Expr)
count = 0
for arg in expr.args
count += count_(arg)
end
count
end
function count_(expr)
convert(Int64,expr == :_)::Int64
end
function subst_!(expr::Expr,slist)
for i in eachindex(expr.args)
expr.args[i]= subst_!(expr.args[i],slist)
end
expr
end
function subst_!(sym,slist)
if (sym == :_) & (!isempty(slist))
sym = popfirst!(slist)
else
return esc(sym)
end
end
macro p(expr::Expr)
fname = gensym()
symnames = [gensym() for i in 1:My_partial.count_(expr)]
args = copy(symnames)
My_partial.subst_!(expr,symnames)
(quote $fname($(args...)) = $expr end)
end
end
using Main.My_partial
and the obligatory (for me) definitions to stack array of arrays to a matrix:
vstack(v) = permutedims(reduce(hcat,v))
hstack(v) = hcat(v...)
I set the environment variable for my editor in ~/.bashrc
, and I generally launch Julia from bash, so I don’t use startup.jl
to set environment variables like this.
But I think the name code
is absolutely absurd, and it’s not on my PATH
. I use the symlink vscode
, and so my startup.jl
contains:
# `vscode` is my symlink to the Visual Studio Code executable.
# Tell Julia how to open files with `vscode`, modified from: `InteractiveUtils/src/editless.jl`
using InteractiveUtils # `using` instead of `import` due to https://github.com/JuliaLang/julia/issues/40192
InteractiveUtils.define_editor(["vscode"]) do cmd, path, line
`$cmd -g $path:$line`
end
Along the same lines of making things prettier, I keep a pretty_rational
function in my startup to change the default printing of Rational
numbers when I want to. I’m not brave enough to make it my default setting, though.
function pretty_rational()
@eval Base.show(io::IO, x::Rational) =
x.den==1 ? print(io, x.num) : print(io, "$(x.num)/$(x.den)")
end
Now this
julia> a = [x//y for x in 1:10, y in 1:10]
10×10 Matrix{Rational{Int64}}:
1//1 1//2 1//3 1//4 1//5 1//6 1//7 1//8 1//9 1//10
2//1 1//1 2//3 1//2 2//5 1//3 2//7 1//4 2//9 1//5
3//1 3//2 1//1 3//4 3//5 1//2 3//7 3//8 1//3 3//10
4//1 2//1 4//3 1//1 4//5 2//3 4//7 1//2 4//9 2//5
5//1 5//2 5//3 5//4 1//1 5//6 5//7 5//8 5//9 1//2
6//1 3//1 2//1 3//2 6//5 1//1 6//7 3//4 2//3 3//5
7//1 7//2 7//3 7//4 7//5 7//6 1//1 7//8 7//9 7//10
8//1 4//1 8//3 2//1 8//5 4//3 8//7 1//1 8//9 4//5
9//1 9//2 3//1 9//4 9//5 3//2 9//7 9//8 1//1 9//10
10//1 5//1 10//3 5//2 2//1 5//3 10//7 5//4 10//9 1//1
becomes
julia> pretty_rational()
julia> a
10×10 Matrix{Rational{Int64}}:
1 1/2 1/3 1/4 1/5 1/6 1/7 1/8 1/9 1/10
2 1 2/3 1/2 2/5 1/3 2/7 1/4 2/9 1/5
3 3/2 1 3/4 3/5 1/2 3/7 3/8 1/3 3/10
4 2 4/3 1 4/5 2/3 4/7 1/2 4/9 2/5
5 5/2 5/3 5/4 1 5/6 5/7 5/8 5/9 1/2
6 3 2 3/2 6/5 1 6/7 3/4 2/3 3/5
7 7/2 7/3 7/4 7/5 7/6 1 7/8 7/9 7/10
8 4 8/3 2 8/5 4/3 8/7 1 8/9 4/5
9 9/2 3 9/4 9/5 3/2 9/7 9/8 1 9/10
10 5 10/3 5/2 2 5/3 10/7 5/4 10/9 1
On Windows 10, in my case, I need ENV["JULIA_EDITOR"] = "code.cmd -g"
.
Details:
julia> ENV["JULIA_EDITOR"] = "code "
julia> edit("test_4.jl", 7)
ERROR: IOError: could not spawn `code -g test_4.jl:7`: no such file or directory (ENOENT)
julia> ENV["JULIA_EDITOR"] = "code.cmd -g"
"code.cmd -g"
julia> edit("test_4.jl", 7)
julia> split(ENV["PATH"], ';')
12-element Vector{SubString{String}}:
...
"C:\\Users\\f\\AppData\\Local\\Programs\\Microsoft VS Code\\bin"
...
`
I like automatically activating local envs when they exist
if isfile("Project.toml") && isfile("Manifest.toml")
Pkg.activate(".")
end
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
@ianshmean, if you have a minute, could you please add a little preamble of explanation for non-experts.
Thank you!
Happy to. Do you mean about the macros themself, beyond the examples in the docstrings?
Or my rationale for not/abandoning PR-ing them to Base?
Basically, kindly give some hints on: why a lambda user would like to add your code to his startup.jl? What does it accomplish?
Sorry if it is so obvious to you.
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 instance
julia> @repeat 3 foo()
is a little simpler to write than
julia> [foo() for _ in 1:3];
More examples in https://github.com/JuliaLang/julia/pull/41455
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
Enjoy!