What is in your startup.jl?

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.

1 Like

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>

9 Likes

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)
13 Likes

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
6 Likes

Nowadays you can just do using Revise.

4 Likes

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

2 Likes

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...)
2 Likes

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
11 Likes

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"
...
`
4 Likes

I like automatically activating local envs when they exist

if isfile("Project.toml") && isfile("Manifest.toml")
    Pkg.activate(".")
end
17 Likes

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
8 Likes

@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?

1 Like

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

4 Likes

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!

18 Likes