I'm trying to create a REPL via the programmatic library provided by the built-in repl package (https://nodejs.org/api/repl.html).
I'm doing something like this[1]:
var repl = require('repl')
repl.start(' > ')
And I'm expecting the commands I enter to be preserved if I open the repl once again later. Not finding that this is the case, I have been trying to setting both NODE_REPL_HISTORY
and NODE_REPL_HISTORY
by doing something like this process.env.NODE_REPL_HISTORY = 'somepath'
. I've tried setting something
to relative path, absolute path, a folder, a file, a non-existing file and a already existing file. But in all cases, the history is not persisted.
I'm not sure if I found a bug or if I'm doing something wrong but would appreciate any I can get.
[1] In reality I'm doing something bigger, https://github.com/victorbjelkholm/trymodule, but figured a small test-case is better for troubleshooting.
FWIW I would expect programmatic REPLs to have to opt-in as far as saving history goes.
@mscdex That makes sense for me as well, I just would like to be able to enable it somehow, setting the environment variable would be one way, accepting it being set in opts
PS. I can also reproduce this in a docker image (mhart/alpine-node
) I frequently use for testing things.
@VictorBjelkholm what if you pass terminal: true
in the REPL options? Looking at the code, it looks like that causes the history to be setup.
@cjihrig Yeah, tried that as well but to no avail :-1:
Extended example:
var repl = require('repl')
repl.start({
terminal: true,
prompt: '> '
})
Ah, yea that is only for the internal REPL, sorry.
@cjihrig saving history in general for programmatic repl or that specific snippet of code? (https://github.com/nodejs/node/blob/master/lib/internal/repl.js#L58-L61)
Seems like one option would be to use the relatively small library repl.history
(https://github.com/tmpvar/repl.history) but I would much rather have it in node vanilla.
I meant that specific snippet of code that you linked to. It's exported at the top of that file as createInternalRepl()
. It looks like it might not be supported for the programmatic REPL at this time.
Oh, I see.
I'll leave this issue open as a feature request to enable history persistence in the programmatic repl and continue my day with using repl.history
instead.
Thanks for the help @cjihrig :+1:
Imo this is kind of up to the implementor. Maybe we can have it as an option? But it would be a very significant change the programatic API.
How big of a change is it really? The createInternalRepl()
function just uses a boolean (an odd one, if you ask me[1]) to determine whether or not to call setupHistory()
. It seems to me that this function could easily be moved to the public facing repl.js
, and triggered on a similar, but probably more aptly named option. E.g. option.history = '/path/to/file.txt'
.
It's minor, but there is already a little bleed over from internal to external. I don't see a disadvantage to moving history management into the public API and simply make the createInternalRepl
function much simpler - setting up command line defaults and such.
Edit: This is a long way of saying, I'd be willing to submit a PR for this change if there's any chance of it being accepted.
[1] The fact that writing history is a side effect of setting opts.terminal = true
seems strange, but I suspect it's a vestige of the fact that this createInternalRepl
is secret and only ever used by node.js
at startup.
Given that we ultimately decided not to merge the PR for this, I'm going to close it. Feel free to reopen if there is demonstrated need.
Just chiming in after some research but late to the party, I would definitely use this if it were available in the stdlib ^^ :)
For others who find this issue:
repl.start
is a no-go because it misses historynode -r ./noderc.js
is a no-go because repl.repl
is unavailablerequire('repl').repl
is undefined under -r
, even for interactive sessionsMy work-around is to have tmux start node and send it arbitrary initialization code:
$ cat bin/repl
#!/bin/sh
file="$HOME/path/to/my/noderc.js"
stty -echo
tmux send-keys 'node; stty echo' C-m ".load $file" C-m
UPDATE:
New hack: Use a command-line flag to require a module that configures the global object, and sets a callback to configure the repl once it's been initialized.
~ $ grep repl .bashrc
alias repl='node --use-strict -r ~/home/git/env/etc/noderc.js'
~ $ cat ~/home/git/env/etc/noderc.js
setTimeout(() => global.repl.repl.ignoreUndefined = true, 1000);
global.jenny = [8, 6, 7, 5, 3, 0, 9];
This has the advantage of not adding the rc file contents to .node_repl_history every time you start a REPL.
Any examples of how to implement loading command history into the repl that is os- and terminal-independent? I looked at repl.history but don't see how to load that history back into the repl once it loads.
nevermind: https://medium.com/@tjwebb/a-custom-node-repl-with-history-is-not-as-hard-as-it-looks-3eb2ca7ec0bd
I'd very much like to see this reopened. It's strange that the built-in REPL has this functionality but programmatic REPLs have no access to it and instead depend on hacky workarounds.
Also, the workaround linked above requires extra effort in order to reimplement max history size, so it's at least a little harder than that.
Most helpful comment
For others who find this issue:
repl.start
is a no-go because it misses historynode -r ./noderc.js
is a no-go becauserepl.repl
is unavailablerequire('repl').repl
is undefined under-r
, even for interactive sessionsMy work-around is to have tmux start node and send it arbitrary initialization code:
UPDATE:
New hack: Use a command-line flag to require a module that configures the global object, and sets a callback to configure the repl once it's been initialized.
This has the advantage of not adding the rc file contents to .node_repl_history every time you start a REPL.