I’m announcing a new package that may speed up your development: https://github.com/timholy/Revise.jl. Revise makes it easier to update code and have the changes take effect immediately, without having to restart Julia. Please see the README for more information.
This package revolutionized my workflow in a few days. Thanks!
Glad to hear it! I find that old habits die hard—I still sometimes restart Julia unnecessarily—but it’s been very good for my workflow too.
Thanks to good feedback from users, v0.0.3
has been released with better support for vim, IJulia, and a broader collection of Julia packages. If it doesn’t work for your use-cases, please continue to report issues.
Suggestion for even smoother workflow if you are working with Juno:
Besides working with Revise or CloberringReload(if you are on 0.5), set Juno to cycler mode
this way it makes a Julia instance ready in the background.
Moreover add a .junorc.jl in your home folder and have it import any commonly used packages.
This saves additional few seconds of start-up time
I also added an asynchronous task with many yields , that does a “workout” for commonly used functions
that are slow the first time… many yields because I want it to be responsive even if it didn’t finish its workout.
This way when I do restart Julia , it starts in a nice warm and nimble state.
To break my habit I wanted ctrl-d to ask Exit? [Y/n]
before exiting. I came up with this .juliarc.jl
bit but it hangs at the readline
. Anyone know how to do this?
ctrl_d_ask = Dict{Any,Any}(
"^D" =>
function (s,o...)
if Base.LineEdit.buffer(s).size > 0
Base.LineEdit.edit_delete(s)
else
println("Exit? [Y/n]")
answer = readline(STDIN)
if answer=="" || lowercase(answer)=="y"
println(Base.LineEdit.terminal(s))
return :abort
else
return nothing
end
end
end
)
function customize_keys(repl)
repl.interface = Base.REPL.setup_interface(repl; extra_repl_keymap = ctrl_d_ask)
end
atreplinit(customize_keys)
I really like the idea of this package, even though it currently only works for the first few file changes. I’m not really sure what is going on, need to test it some more.
EDIT: It seems to be working now. Yay.
Anyway, I’m kind of curious why you have to do:
@schedule begin
sleep(0.1)
@eval using Revise
end
in .juliarc.jl
?
Do you mean, “as opposed to simply using Revise
in .juliarc.jl
”? The @schedule
is needed because .juliarc.jl
gets executed before the REPL code is fully initialized. Revise’s __init__
function alters an important component of the REPL code (shutting down one “service” and starting a modified one), so you have to do something to wait until the REPL code is initialized.
Thanks for this trick!! I have a function to change the prompt (to include the current branh-name, to no be lost when I have a handful of open prompts to compare e.g. performances for a PR), but never could find a way to call this function from my “.juliarrc.jl”. This is really neat, you solve one of my longstanding problems (although I believe there should eventually be a cleaner to achieve the same).
If you know for certain that you’re using the REPL, something like wait(Task(() -> while !isdefined(Base, :active_repl_backend) end))
might be even better than sleep(0.1)
. In Requires I want to make sure I support Juno/IJulia too, so there may never be a REPL. So I chose the more braindead solution.
Looks neat, but after playing a bit with it, I can’t make it work (I will need to read more about tasks to understand); it’s looks like the task is never run.
Even with @schedule
I have to manually call revise()
.
That’s unexpected. Is there an error message? What happens if you increase the sleep time? Are you loading any other packages in your .juliarc.jl
? If so, they won’t get tracked unless you make sure you load Revise first.
No error message. Here’s my current rc:
@schedule begin
sleep(0.1)
@eval using Revise
end
atreplinit((_)->begin
Base.require(:TerminalExtensions)
Base.require(:MiscGraphUtils)
end)
Maybe TeminalExtensions
does its own messing with things, perhaps try commenting that one out.
It wasn’t TerminalExtensions
, it was MiscGraphUtils
which depended on LightGraphs
(which was what I was revising). This seems to indicate that atreplinit
happens BEFORE @schedule
, right?
Also: if you remove a function from the source, it persists even after a revise() (this is not terribly surprising, I guess):
julia> LightGraphs.foo(g)
33
# remove foo from source, save.
julia> revise()
julia> LightGraphs.foo(g)
33
This seems to indicate that atreplinit happens BEFORE @schedule, right?
Well, technically the @schedule
happens immediately, but then execution progresses. Meanwhile the Task’s first action is to sleep 0.1s; if that takes longer than REPL initialization, then Revise gets loaded after those other packages. If you never use IJulia/Juno, you could just add Revise
to the atreplinit
list.
if you remove a function from the source, it persists even after a revise
Yes, this is documented in the README.
If you never use IJulia/Juno, you could just add Revise to the atreplinit list.
I don’t, but it doesn’t work as I might expect:
atreplinit((_)->begin
@eval using Revise
Base.require(:TerminalExtensions)
Base.require(:MiscGraphUtils)
end)
requires me to use revise()
for LightGraphs (after a using LightGraphs
typed into the REPL), and
atreplinit((_)->begin
Base.require(:Revise)
Base.require(:TerminalExtensions)
Base.require(:MiscGraphUtils)
end)
doesn’t load Revise at all.
This is a lifesaver! How hard would it be to make it a part of standard Julia REPL?
I personally think it’s worth considering, but the scary thing would be that if it doesn’t work for everyone then it could handicap the REPL (which would be pretty catastrophic). If we want to make progress towards such a future, the most important thing is for anyone who experiences trouble with the package to please report bugs!
(Along these lines, OSX users please upgrade to the 0.0.4 release once the METADATA tag gets merged.)
Just found out about this… This will change my life ! Thank you @tim.holy for doing this.