Avoid consuming CPU when waiting for input. (#651)

When reading input, start by calling `event::read`, which efficiently blocks
until input arrives, rather than polling for input every 100
milliseconds.

This preserves the existing `POLL_WAIT` polling behavior by moving the
poll after the first `read` call returns.

Fixes #521.
This commit is contained in:
Dan Gohman 2023-11-01 16:37:22 -07:00 committed by GitHub
parent 973dbb5f5f
commit 2b6790c14b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -725,77 +725,74 @@ impl Reedline {
}
}
if event::poll(Duration::from_millis(100))? {
let mut latest_resize = None;
let mut latest_resize = None;
loop {
match event::read()? {
Event::Resize(x, y) => {
latest_resize = Some((x, y));
}
enter @ Event::Key(KeyEvent {
code: KeyCode::Enter,
modifiers: KeyModifiers::NONE,
..
}) => {
let enter = ReedlineRawEvent::convert_from(enter);
if let Some(enter) = enter {
crossterm_events.push(enter);
// Break early to check if the input is complete and
// can be send to the hosting application. If
// multiple complete entries are submitted, events
// are still in the crossterm queue for us to
// process.
paste_enter_state = crossterm_events.len() > EVENTS_THRESHOLD;
break;
}
}
x => {
let raw_event = ReedlineRawEvent::convert_from(x);
if let Some(evt) = raw_event {
crossterm_events.push(evt);
}
}
}
// There could be multiple events queued up!
// pasting text, resizes, blocking this thread (e.g. during debugging)
// We should be able to handle all of them as quickly as possible without causing unnecessary output steps.
while event::poll(Duration::from_millis(POLL_WAIT))? {
match event::read()? {
Event::Resize(x, y) => {
latest_resize = Some((x, y));
}
enter @ Event::Key(KeyEvent {
code: KeyCode::Enter,
modifiers: KeyModifiers::NONE,
..
}) => {
let enter = ReedlineRawEvent::convert_from(enter);
match enter {
Some(enter) => {
crossterm_events.push(enter);
// Break early to check if the input is complete and
// can be send to the hosting application. If
// multiple complete entries are submitted, events
// are still in the crossterm queue for us to
// process.
paste_enter_state = crossterm_events.len() > EVENTS_THRESHOLD;
break;
}
None => continue,
}
}
x => {
let raw_event = ReedlineRawEvent::convert_from(x);
match raw_event {
Some(evt) => crossterm_events.push(evt),
None => continue,
}
}
if !event::poll(Duration::from_millis(POLL_WAIT))? {
break;
}
}
if let Some((x, y)) = latest_resize {
reedline_events.push(ReedlineEvent::Resize(x, y));
}
// Accelerate pasted text by fusing `EditCommand`s
//
// (Text should only be `EditCommand::InsertChar`s)
let mut last_edit_commands = None;
for event in crossterm_events.drain(..) {
match (&mut last_edit_commands, self.edit_mode.parse_event(event)) {
(None, ReedlineEvent::Edit(ec)) => {
last_edit_commands = Some(ec);
}
(None, other_event) => {
reedline_events.push(other_event);
}
(Some(ref mut last_ecs), ReedlineEvent::Edit(ec)) => {
last_ecs.extend(ec);
}
(ref mut a @ Some(_), other_event) => {
reedline_events.push(ReedlineEvent::Edit(a.take().unwrap()));
reedline_events.push(other_event);
}
}
if let Some((x, y)) = latest_resize {
reedline_events.push(ReedlineEvent::Resize(x, y));
}
// Accelerate pasted text by fusing `EditCommand`s
//
// (Text should only be `EditCommand::InsertChar`s)
let mut last_edit_commands = None;
for event in crossterm_events.drain(..) {
match (&mut last_edit_commands, self.edit_mode.parse_event(event)) {
(None, ReedlineEvent::Edit(ec)) => {
last_edit_commands = Some(ec);
}
(None, other_event) => {
reedline_events.push(other_event);
}
(Some(ref mut last_ecs), ReedlineEvent::Edit(ec)) => {
last_ecs.extend(ec);
}
(ref mut a @ Some(_), other_event) => {
reedline_events.push(ReedlineEvent::Edit(a.take().unwrap()));
reedline_events.push(other_event);
}
}
}
if let Some(ec) = last_edit_commands {
reedline_events.push(ReedlineEvent::Edit(ec));
}
};
}
if let Some(ec) = last_edit_commands {
reedline_events.push(ReedlineEvent::Edit(ec));
}
for event in reedline_events.drain(..) {
match self.handle_event(prompt, event)? {