Skip to content

Commit cf79718

Browse files
authored
Merge pull request #882 from gwenn/min
Support minimal repaint
2 parents abf171d + b81f45c commit cf79718

File tree

6 files changed

+55
-36
lines changed

6 files changed

+55
-36
lines changed

src/edit.rs

Lines changed: 42 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ use crate::tty::{Renderer, Term, Terminal};
1717
use crate::undo::Changeset;
1818
use crate::validate::{ValidationContext, ValidationResult};
1919
use crate::KillRing;
20+
use RefreshKind::All;
2021

2122
/// Represent the state during line editing.
2223
/// Implement rendering.
@@ -41,6 +42,15 @@ enum Info<'m> {
4142
Msg(Option<&'m str>),
4243
}
4344

45+
/// Refresh kind
46+
#[derive(PartialEq)]
47+
pub enum RefreshKind {
48+
// Do not clear old rows and keep current layout
49+
Min,
50+
// Clear old rows + layout
51+
All,
52+
}
53+
4454
impl<'out, 'prompt, H: Helper> State<'out, 'prompt, H> {
4555
pub fn new(
4656
out: &'out mut <Terminal as Term>::Writer,
@@ -136,8 +146,7 @@ impl<'out, 'prompt, H: Helper> State<'out, 'prompt, H> {
136146
return Ok(());
137147
}
138148
if self.highlight_char(kind) {
139-
let prompt_size = self.prompt_size;
140-
self.refresh(self.prompt, prompt_size, true, Info::NoHint)?;
149+
self.refresh(self.prompt, self.prompt_size, true, All, Info::NoHint)?;
141150
} else {
142151
self.out.move_cursor(self.layout.cursor, cursor)?;
143152
self.layout.prompt_size = self.prompt_size;
@@ -161,11 +170,16 @@ impl<'out, 'prompt, H: Helper> State<'out, 'prompt, H> {
161170
self.out.move_cursor_at_leftmost(rdr)
162171
}
163172

173+
pub fn repaint(&mut self, kind: RefreshKind) -> Result<()> {
174+
self.refresh(self.prompt, self.prompt_size, true, kind, Info::Hint)
175+
}
176+
164177
fn refresh(
165178
&mut self,
166179
prompt: &str,
167180
prompt_size: Position,
168181
default_prompt: bool,
182+
kind: RefreshKind,
169183
info: Info<'_>,
170184
) -> Result<()> {
171185
let info = match info {
@@ -179,21 +193,26 @@ impl<'out, 'prompt, H: Helper> State<'out, 'prompt, H> {
179193
None
180194
};
181195

182-
let new_layout = self
183-
.out
184-
.compute_layout(prompt_size, default_prompt, &self.line, info);
196+
if kind == RefreshKind::Min {
197+
self.out
198+
.refresh_line(prompt, &self.line, info, None, &self.layout, highlighter)?;
199+
} else {
200+
let new_layout = self
201+
.out
202+
.compute_layout(prompt_size, default_prompt, &self.line, info);
185203

186-
debug!(target: "rustyline", "old layout: {:?}", self.layout);
187-
debug!(target: "rustyline", "new layout: {new_layout:?}");
188-
self.out.refresh_line(
189-
prompt,
190-
&self.line,
191-
info,
192-
&self.layout,
193-
&new_layout,
194-
highlighter,
195-
)?;
196-
self.layout = new_layout;
204+
debug!(target: "rustyline", "old layout: {:?}", self.layout);
205+
debug!(target: "rustyline", "new layout: {new_layout:?}");
206+
self.out.refresh_line(
207+
prompt,
208+
&self.line,
209+
info,
210+
Some(&self.layout),
211+
&new_layout,
212+
highlighter,
213+
)?;
214+
self.layout = new_layout;
215+
}
197216

198217
Ok(())
199218
}
@@ -270,20 +289,20 @@ impl<H: Helper> Refresher for State<'_, '_, H> {
270289
fn refresh_line(&mut self) -> Result<()> {
271290
self.hint();
272291
self.highlight_char(CmdKind::Other);
273-
self.refresh(self.prompt, self.prompt_size, true, Info::Hint)
292+
self.repaint(All)
274293
}
275294

276295
fn refresh_line_with_msg(&mut self, msg: Option<&str>, kind: CmdKind) -> Result<()> {
277296
self.hint = None;
278297
self.highlight_char(kind);
279-
self.refresh(self.prompt, self.prompt_size, true, Info::Msg(msg))
298+
self.refresh(self.prompt, self.prompt_size, true, All, Info::Msg(msg))
280299
}
281300

282301
fn refresh_prompt_and_line(&mut self, prompt: &str) -> Result<()> {
283302
let prompt_size = self.out.calculate_position(prompt, Position::default());
284303
self.hint();
285304
self.highlight_char(CmdKind::Other);
286-
self.refresh(prompt, prompt_size, false, Info::Hint)
305+
self.refresh(prompt, prompt_size, false, All, Info::Hint)
287306
}
288307

289308
fn doing_insert(&mut self) {
@@ -321,13 +340,11 @@ impl<H: Helper> Refresher for State<'_, '_, H> {
321340
fn external_print(&mut self, msg: String) -> Result<()> {
322341
self.out.begin_synchronized_update()?;
323342
self.out.clear_rows(&self.layout)?;
324-
self.layout.end.row = 0;
325-
self.layout.cursor.row = 0;
326343
self.out.write_and_flush(msg.as_str())?;
327344
if !msg.ends_with('\n') {
328345
self.out.write_and_flush("\n")?;
329346
}
330-
self.refresh_line()?;
347+
self.repaint(RefreshKind::Min)?;
331348
self.out.end_synchronized_update()
332349
}
333350
}
@@ -374,7 +391,7 @@ impl<H: Helper> State<'_, '_, H> {
374391
let bits = ch.encode_utf8(&mut self.byte_buffer);
375392
self.out.write_and_flush(bits)
376393
} else {
377-
self.refresh(self.prompt, self.prompt_size, true, Info::Hint)
394+
self.repaint(All)
378395
}
379396
} else {
380397
self.refresh_line()
@@ -584,7 +601,7 @@ impl<H: Helper> State<'_, '_, H> {
584601
debug_assert_eq!(self.layout.cursor, self.layout.end);
585602
self.out.clear_to_eol()
586603
} else {
587-
self.refresh(self.prompt, self.prompt_size, true, Info::Hint)
604+
self.repaint(All)
588605
}
589606
} else {
590607
Ok(())
@@ -638,7 +655,7 @@ impl<H: Helper> State<'_, '_, H> {
638655
}
639656
}
640657

641-
/// Moves the cursor to the same column in the line above
658+
/// Moves the cursor to the same column in the line below
642659
pub fn edit_move_line_down(&mut self, n: RepeatCount) -> Result<bool> {
643660
if self.line.move_to_line_down(n, &self.layout) {
644661
self.move_cursor(CmdKind::MoveCursor)?;

src/lib.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ use crate::tty::{Buffer, RawMode, RawReader, Renderer, Term, Terminal};
5555
pub use crate::binding::{ConditionalEventHandler, Event, EventContext, EventHandler};
5656
use crate::completion::{longest_common_prefix, Candidate, Completer};
5757
pub use crate::config::{Behavior, ColorMode, CompletionType, Config, EditMode, HistoryDuplicates};
58-
use crate::edit::State;
58+
use crate::edit::{RefreshKind, State};
5959
use crate::error::ReadlineError;
6060
use crate::highlight::{CmdKind, Highlighter};
6161
use crate::hint::Hinter;
@@ -356,9 +356,7 @@ fn page_completions<C: Candidate, H: Helper>(
356356
s.out.write_and_flush(ab.as_str())?;
357357
}
358358
s.out.write_and_flush("\n")?;
359-
s.layout.end.row = 0; // dirty way to make clear_old_rows do nothing
360-
s.layout.cursor.row = 0;
361-
s.refresh_line()?;
359+
s.repaint(RefreshKind::Min)?;
362360
Ok(None)
363361
}
364362

src/tty/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ pub trait Renderer {
5454
prompt: &str,
5555
line: &LineBuffer,
5656
hint: Option<&str>,
57-
old_layout: &Layout,
57+
old_layout: Option<&Layout>, // used to clear old rows
5858
new_layout: &Layout,
5959
highlighter: Option<&dyn Highlighter>,
6060
) -> Result<()>;

src/tty/test.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ impl Renderer for Sink {
105105
_prompt: &str,
106106
_line: &LineBuffer,
107107
_hint: Option<&str>,
108-
_old_layout: &Layout,
108+
_old_layout: Option<&Layout>,
109109
_new_layout: &Layout,
110110
_highlighter: Option<&dyn Highlighter>,
111111
) -> Result<()> {

src/tty/unix.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1026,7 +1026,7 @@ impl Renderer for PosixRenderer {
10261026
prompt: &str,
10271027
line: &LineBuffer,
10281028
hint: Option<&str>,
1029-
old_layout: &Layout,
1029+
old_layout: Option<&Layout>,
10301030
new_layout: &Layout,
10311031
highlighter: Option<&dyn Highlighter>,
10321032
) -> Result<()> {
@@ -1038,7 +1038,9 @@ impl Renderer for PosixRenderer {
10381038
let cursor = new_layout.cursor;
10391039
let end_pos = new_layout.end;
10401040

1041-
self.clear_old_rows(old_layout);
1041+
if let Some(old_layout) = old_layout {
1042+
self.clear_old_rows(old_layout);
1043+
}
10421044

10431045
if let Some(highlighter) = highlighter {
10441046
// display the prompt
@@ -1752,7 +1754,7 @@ mod test {
17521754
let new_layout = out.compute_layout(prompt_size, default_prompt, &line, None);
17531755
assert_eq!(Position { col: 1, row: 1 }, new_layout.cursor);
17541756
assert_eq!(new_layout.cursor, new_layout.end);
1755-
out.refresh_line(prompt, &line, None, &old_layout, &new_layout, None)
1757+
out.refresh_line(prompt, &line, None, Some(&old_layout), &new_layout, None)
17561758
.unwrap();
17571759
#[rustfmt::skip]
17581760
assert_eq!(

src/tty/windows.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -440,7 +440,7 @@ impl Renderer for ConsoleRenderer {
440440
prompt: &str,
441441
line: &LineBuffer,
442442
hint: Option<&str>,
443-
old_layout: &Layout,
443+
old_layout: Option<&Layout>,
444444
new_layout: &Layout,
445445
highlighter: Option<&dyn Highlighter>,
446446
) -> Result<()> {
@@ -481,7 +481,9 @@ impl Renderer for ConsoleRenderer {
481481
// just to avoid flickering
482482
let mut guard = self.set_cursor_visibility(false)?;
483483
// position at the start of the prompt, clear to end of previous input
484-
self.clear_old_rows(&info, old_layout)?;
484+
if let Some(old_layout) = old_layout {
485+
self.clear_old_rows(&info, old_layout)?;
486+
}
485487
// display prompt, input line and hint
486488
write_to_console(self.conout, self.buffer.as_str(), &mut self.utf16)?;
487489

0 commit comments

Comments
 (0)