So I took a stab at implementing this with rustyline's builtin history dump feature, but it was pointed out that we should probably spend some time talking about the design first. https://github.com/rtfeldman/roc/issues/2510
Also might be a good time to talk about the repl command parser architecture a bit, since this is the first command that takes an argument!
very cool idea!
so one thought that comes immediately to mind: what if we just saved it automatically, instead of having a command?
like you bring up the repl again and press up, and it just remembers what was there the last time you used the repl?
A persistent history would also be great yeah. It might be convenient to keep a 'dump session' feature on top of that so people don't have to slice and dice their whole repl scrollback and that file can stay someplace relatively out-of-the-way
hm, so what would the use case for that be? :thinking:
I've never used a feature like that in a repl! :big_smile:
I use repls as a drafting table pretty often, but I think it's fair that that's not a feature most people expect from a repl, although it's unclear if they don't expect it because it's not well-implemented or because it's not a part of their workflow (or maybe it's a chicken-and-egg thing.)
interesting! I'm curious what your workflow looks like
is it a per-project thing?
I move around from project to project a lot so I'm often working on code I don't own, robust repls and debuggers make my life much easier
Actually my hackathon and CTF workflow benefits a lot from that too. Tough to beat notebooks for that kind of draft-test-iterate workflow but repls can be pretty close
cool, so let's say you have like 5 different projects in 5 different folders on your machine
and let's say you're working on one of those projects right now
and let's also say that (somehow) when you brought up the repl in that project, it just automatically remembered your command history from the last time you brought it up in this project
at that point, would you still use a dump/restore session feature, within the bounds of that project alone?
I think I would; but I feel like the real question is, if I draft something complicated in the repl and I'm happy with it, how can I easily get it into my project?
ahh gotcha! so in that use case, it's not so much about the command history as the code?
Yes exactly
ok I understand
so what if we separated the two features?
does that seem like a reasonable design direction?
for the way you use repls
Yeah absolutely
ok cool! so for exporting the code, there's a bit of groundwork we need in the repl first
because right now, it doesn't really "remember" anything :sweat_smile:
like if you enter an expression, it evaluates it, prints the result, and then forgets all about it
(this is not the long-term design, it's just that we've never taught it to do anything else!)
(For context, this use case is the reason I filed the issue initially. I have the same workflow and I think it works best in notebooks, but those are heavy weight and don’t work for every language, so it’s nice if a repl supports it.)
so because of the way Roc expressions work, you can do this in the repl:
x = 5
x + 1
because that's one expression in Roc
but once I've entered that one expression, the repl has forgotten all about x
so I need to redefine it from scratch again in a fresh expression if I want to use it again
similarly, we also don't have a way to refer to previous repl executions
Right. It saves your input, but not any of the state from prior commands being executed
yeah
which it totally should! It just doesn't yet.
I've used other repls that also generate some automatic name for expressions you enter
I filed a related issue around that topic too, in case it is of any use: https://github.com/rtfeldman/roc/issues/2509
like if I just put in 5 + 5 it might generate the name repl1 for that (and print it out along with the answer)
so I can refer to it later without having to enter it again
I think that would also be a nice feature, and generating names that are conducive to export seems like a good thing to keep in mind for it
e.g. I know some languages will name previous values things with special repl-only characters (like automatically generating the name $1 instead of repl1)
that avoids potential namespace collisions, but it makes it harder to export them to a file, because if I enter $1 + 5 and then export that to a file later, that won't make sense in a normal .roc file
(as opposed to like repl1 + 5
)
:thinking: one way to avoid the namespace issue might be to put the auto-generated names in an auto-generated module like Repl
so maybe you write Repl.v1 for the first value the repl printed out
and then when you export it, it puts all those declarations into a file
That would be really nice with some refactoring/renaming features
I think being a little imperfect is okay, what is written in a repl is usually drafty/prototypey and would likely require manual cleanup anyway
Yeah that's part of why I felt confident to just charge ahead with the rustyline builtin hahah
yeah, although I think rustyline only knows about inputs and not declarations :big_smile:
so we need something like https://github.com/rtfeldman/roc/issues/2509 to get the actual export
but!
rustyline can totally be used to preserve input history
for that, I was thinking now might be the time to start storing local per-project caches, which we'll want later for incremental compilation anyway
Yes. It's literally just dumping what you typed into a file, whether it was parsed successfully or not.
specifically I was thinking of introducing a .roc-cache folder
the folder structure would be:
.roc-cache/version-number-or-git-commit-sha-of-compiler/datafile-goes-here
so if you're building from source on commit 1aec997843764c44f6774a8a39d34be775f7ab2f, and you start using the repl, every time you enter an expression, it would write to .roc-cache/1aec997843764c44f6774a8a39d34be775f7ab2f/repl-history.dat
and then whenever you bring up a new repl, it would look for that file
actually I could also see an argument for the repl history existing outside the compiler version :thinking:
like the compiler versioning makes sense because otherwise it might have stale compilation artifacts that aren't compatible between versions (and might even cause bugs)
but maybe for the repl it's just best to keep all the raw inputs even if you're (for example) upgrading compiler versions
because most of them will probably still make sense, and be useful, after the upgrade
thoughts?
Agree; I wouldn't want my history wiped on an update in normal circumstances
ok cool! so then .roc-cache/repl-history.dat
as a subdirectory of the current working directory where you opened the repl
does that seem like a good design?
Sounds good to me!
awesome! let's give others some time to weigh in (like 24 hours let's say) so we get some more perspectives before proceeding, but I'm really liking this direction! :smiley:
I like the per-project repl history!
Two suggestions:
Could we also persist the history in a global history file? So if I'm in "directory A", the history of the repl for my current session will be saved to a file in .roc-cache there, but also be written through to a global repl history file. The reason for this is so that I can have a global view of all repl history, without having to necessarily remember what directory I came from.
The second is could we still have a method to save the current session state to a file? I think there is still value to this, in at least that
roc-cache, since that may be larger than what I worked on in a single session of the replroc-cache. For example we may want to save things in a more compact manner or remember type/evaluation information in that history file at a latter point, to avoid duplicating work if need be. If this is done then the history file would not be a file containing only Roc code anymore, and would make it more challenging for users to parse out what they need (namely Roc code)I think that's kind of another question; should the repl be contextual or should it be like a shell, where your command history is global? Like if I just fire up a shell to test something while I'm in a meeting or something, I might still expect to see those commands when I start a repl elsewhere
But I definitely still think a dump-session-history-to-file command is a good idea
We could prioritize contextual and fallback on the global history, that way you don't have to go hunting if you forget what directory you were in, but if you do remember, you can "continue where you left off"
I also definitely think a user should never need to know what/where that history file is in order to accomplish what they want
Got a new draft of this feature I feel okay about; it's interacting a little weirdly with the unit tests so I'm wondering about a no-history command line flag or something like that https://github.com/rtfeldman/roc/pull/2598
Last updated: Jun 16 2026 at 16:19 UTC