Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

readline: persistent history + repl changes #596

Closed
wants to merge 1 commit into from

Conversation

a8m
Copy link

@a8m a8m commented Jan 24, 2015

As I commented in #343
I think the persistent history support should be part of the readline module.
After this changes, any cli that using readline would be able to support too.
e.g:

var rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout,
  history: 'path/to/history'
});

The "main" changes is in the readline module and it's tested too.

I also changed a bit the repl module, and add the history support by default.
Maybe it should become with flags(NODE_DISABLE_HISTORY, NODE_HISTORY_PATH) like @evanlucas suggested, but this is out of the scope of this PR.

Thanks.

@brendanashworth
Copy link
Contributor

Is there a benefit to loading the current history into memory rather than just appending to the as-is history file? From what I'm seeing, it would allow a programmer to access previous history - at the expense of a breaking change to what they might have previously relied on (i.e., first command ran = first index).

@a8m
Copy link
Author

a8m commented Jan 24, 2015

Sorry, I didn't get your point.
I try to explain the process:
first, if there's an history support, fetch from the file, and store in-memory.
so, the previous history is available at the start.
then, on each line, store the current history in the file.

@brendanashworth
Copy link
Contributor

@a8m its alright. I intended to ask: why load on startup and overwrite the entire file every time a new line is entered, rather than appending each time a new line is entered?

For a big file (lets say 10Mb), and someone enters twenty lines, that'd be ~210Mb of input / output rather than just a few bytes (~8Kb) by appending to the file using fs.appendFileSync(). This would also avoid using lots of RAM by loading the file into memory.

Edit: this would also allow for two readline's to be run at once with the same history file.

@a8m
Copy link
Author

a8m commented Jan 24, 2015

I agree with you @brendanashworth, it really more sense.
But, because the limit for lines-history(for some reason) it's 30 rows, it's really doesn't matter.
What we can do, it's making it configurable too(make the 30 the default), then append to a file and trim it when it exceeds a particular size.
e.g:

var rl = readline.createInterface({
  //...
  history: 'path/to/history'
});
rl.setHistorySize(100);

what are your thoughts?

@brendanashworth
Copy link
Contributor

@a8m I like that idea, 👍 from me on that topic.

On a side note, could you clean up your commit title and description to fit the guidelines?

@a8m
Copy link
Author

a8m commented Jan 25, 2015

Update:
I've change a bit the previous commit.
Currently, on each line, it's appending to the history file.
Then, when the close function is fired, test if the in-memory history is greater than or equal to _hisotrySize. if so, call writeFileSync and copy the in-memory history to ensure the file is not exceeding the _hisotrySize.(Can you think about more elegant/cheap way to trim the file?).

Also, I've updated the docs and the tests too.
Cheers.

@a8m a8m changed the title feat(readline): persistent history + repl changes readline: persistent history + repl changes Jan 25, 2015
@@ -31,6 +31,8 @@ const rl = require('readline');
const Console = require('console').Console;
const domain = require('domain');
const debug = util.debuglog('repl');
const HISTORY_PATH = path.join(process.env.HOME || process.env.USERPROFILE,
'.iojs_history');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change should not be made to the REPL module, it should be specific to iojs command line repl.

@a8m
Copy link
Author

a8m commented Jan 26, 2015

/cc @chrisdickinson

@vkurchatkin
Copy link
Contributor

I don't think readline should do any io. The user can just pass history array and retrieve it later

@rvagg
Copy link
Member

rvagg commented Jan 27, 2015

+1 to @vkurchatkin's comment above

@a8m
Copy link
Author

a8m commented Jan 27, 2015

@vkurchatkin writing to the terminal is also io, but I get your point.
so, if the load and the save operations will move to the user land, it will look something like that:

readline.createInterface({
  //...
  history: loadSync('history')
})
.on('line',  // append to a file)
.on('close', // or save on closing)

If this is acceptable to you guys, I'll make this changes.
Thx.

@vkurchatkin
Copy link
Contributor

@a8m it is, but readline doesn't write directly, you provide a stream. This way you can use it with any kind of stream. The same principle applies to history, so that user can store history in memory or database.

@a8m a8m force-pushed the feature/readline-history branch 4 times, most recently from 86fb5d8 to 3755b30 Compare January 28, 2015 06:55
@piscisaureus
Copy link
Contributor

What @vkurchatkin said.

@a8m
Copy link
Author

a8m commented Jan 29, 2015

@piscisaureus this PR was updated after @vkurchatkin comments.
Thx

@@ -13,7 +13,8 @@ program to gracefully exit:

var rl = readline.createInterface({
input: process.stdin,
output: process.stdout
output: process.stdout,
history: loadHistorySync()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's not clear from the example what is the result of loadHistorySync(). It's better to use array literal

@@ -24,7 +21,7 @@ exports.createInterface = function(input, output, completer, terminal) {
};


function Interface(input, output, completer, terminal) {
function Interface(input, output, completer, terminal, history) {
if (!(this instanceof Interface)) {
return new Interface(input, output, completer, terminal);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

history should be passed here as well

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right! (I'm usually using it with option object)
changed!

@brendanashworth brendanashworth added the semver-minor PRs that contain new features and should be released in the next minor version. label Feb 3, 2015
@mscdex mscdex added the readline Issues and PRs related to the built-in readline module. label Mar 22, 2015
(user ? (process.getuid() === 0 ? '/root' : '/home/' + user) : null);
}
return home || null;
})()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: missing semicolon here

@brendanashworth
Copy link
Contributor

Is there an update on this? It hasn't been touched in a while.

@a8m
Copy link
Author

a8m commented Apr 14, 2015

It's up to you guys.

@silverwind
Copy link
Contributor

With 0450ce7 landed, I think this may be obsolete now.

@Fishrock123
Copy link
Contributor

Yep, seems like it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
readline Issues and PRs related to the built-in readline module. semver-minor PRs that contain new features and should be released in the next minor version.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

10 participants