Skip to content

Commit 23bb4ae

Browse files
committed
Change cursor visibility
1 parent 77f1d53 commit 23bb4ae

File tree

7 files changed

+79
-18
lines changed

7 files changed

+79
-18
lines changed

Cargo.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,6 @@ termios = { version = "0.3.3", optional = true }
5050

5151
[target.'cfg(windows)'.dependencies]
5252
winapi = { version = "0.3", features = ["consoleapi", "handleapi", "synchapi", "minwindef", "processenv", "std", "winbase", "wincon", "winerror", "winuser"] }
53-
scopeguard = "1.1"
5453
clipboard-win = "5.0"
5554

5655
[dev-dependencies]

examples/read_password.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,13 @@ impl Highlighter for MaskingHighlighter {
1414
fn highlight<'l>(&self, line: &'l str, _pos: usize) -> Cow<'l, str> {
1515
use unicode_width::UnicodeWidthStr;
1616
if self.masking {
17-
Owned("*".repeat(line.width()))
17+
Owned(" ".repeat(line.width()))
1818
} else {
1919
Borrowed(line)
2020
}
2121
}
2222

23-
fn highlight_char(&self, line: &str, pos: usize, forced: bool) -> bool {
23+
fn highlight_char(&self, _line: &str, _pos: usize, _forced: bool) -> bool {
2424
self.masking
2525
}
2626
}
@@ -37,7 +37,9 @@ fn main() -> Result<()> {
3737
rl.helper_mut().expect("No helper").masking = true;
3838
rl.set_color_mode(ColorMode::Forced); // force masking
3939
rl.set_auto_add_history(false); // make sure password is not added to history
40+
let mut guard = rl.set_cursor_visibility(false)?;
4041
let passwd = rl.readline("Password:")?;
42+
guard.take();
4143
println!("Secret: {passwd}");
4244
Ok(())
4345
}

src/lib.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -917,6 +917,14 @@ impl<H: Helper, I: History> Editor<H, I> {
917917
pub fn create_external_printer(&mut self) -> Result<<Terminal as Term>::ExternalPrinter> {
918918
self.term.create_external_printer()
919919
}
920+
921+
/// Change cursor visibility
922+
pub fn set_cursor_visibility(
923+
&mut self,
924+
visible: bool,
925+
) -> Result<Option<<Terminal as Term>::CursorGuard>> {
926+
self.term.set_cursor_visibility(visible)
927+
}
920928
}
921929

922930
impl<H: Helper, I: History> config::Configurer for Editor<H, I> {

src/tty/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,7 @@ pub trait Term {
220220
type Writer: Renderer<Reader = Self::Reader>; // rl_outstream
221221
type Mode: RawMode;
222222
type ExternalPrinter: ExternalPrinter;
223+
type CursorGuard;
223224

224225
fn new(
225226
color_mode: ColorMode,
@@ -246,6 +247,8 @@ pub trait Term {
246247
fn writeln(&self) -> Result<()>;
247248
/// Create an external printer
248249
fn create_external_printer(&mut self) -> Result<Self::ExternalPrinter>;
250+
/// Change cursor visibility
251+
fn set_cursor_visibility(&mut self, visible: bool) -> Result<Option<Self::CursorGuard>>;
249252
}
250253

251254
// If on Windows platform import Windows TTY module

src/tty/test.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,7 @@ pub struct DummyTerminal {
160160
}
161161

162162
impl Term for DummyTerminal {
163+
type CursorGuard = ();
163164
type ExternalPrinter = DummyExternalPrinter;
164165
type KeyMap = KeyMap;
165166
type Mode = Mode;
@@ -219,6 +220,10 @@ impl Term for DummyTerminal {
219220
Ok(DummyExternalPrinter {})
220221
}
221222

223+
fn set_cursor_visibility(&mut self, _: bool) -> Result<Option<()>> {
224+
Ok(None)
225+
}
226+
222227
fn writeln(&self) -> Result<()> {
223228
Ok(())
224229
}

src/tty/unix.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1139,6 +1139,23 @@ fn write_all(fd: RawFd, buf: &str) -> nix::Result<()> {
11391139
Ok(())
11401140
}
11411141

1142+
pub struct PosixCursorGuard(RawFd);
1143+
1144+
impl Drop for PosixCursorGuard {
1145+
fn drop(&mut self) {
1146+
let _ = set_cursor_visibility(self.0, true);
1147+
}
1148+
}
1149+
1150+
fn set_cursor_visibility(fd: RawFd, visible: bool) -> Result<Option<PosixCursorGuard>> {
1151+
write_all(fd, if visible { "\x1b[?25h" } else { "\x1b[?25l" })?;
1152+
Ok(if visible {
1153+
None
1154+
} else {
1155+
Some(PosixCursorGuard(fd))
1156+
})
1157+
}
1158+
11421159
#[cfg(not(feature = "signal-hook"))]
11431160
static mut SIGWINCH_PIPE: RawFd = -1;
11441161
#[cfg(not(feature = "signal-hook"))]
@@ -1236,6 +1253,7 @@ impl PosixTerminal {
12361253
}
12371254

12381255
impl Term for PosixTerminal {
1256+
type CursorGuard = PosixCursorGuard;
12391257
type ExternalPrinter = ExternalPrinter;
12401258
type KeyMap = PosixKeyMap;
12411259
type Mode = PosixMode;
@@ -1405,6 +1423,14 @@ impl Term for PosixTerminal {
14051423
tty_out: self.tty_out,
14061424
})
14071425
}
1426+
1427+
fn set_cursor_visibility(&mut self, visible: bool) -> Result<Option<PosixCursorGuard>> {
1428+
if self.is_out_a_tty {
1429+
set_cursor_visibility(self.tty_out, visible)
1430+
} else {
1431+
Ok(None)
1432+
}
1433+
}
14081434
}
14091435

14101436
#[allow(unused_must_use)]

src/tty/windows.rs

Lines changed: 33 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -330,8 +330,8 @@ impl ConsoleRenderer {
330330
})?)
331331
}
332332

333-
fn set_cursor_visible(&mut self, visible: BOOL) -> Result<()> {
334-
set_cursor_visible(self.conout, visible)
333+
fn set_cursor_visibility(&mut self, visible: bool) -> Result<Option<ConsoleCursorGuard>> {
334+
set_cursor_visibility(self.conout, visible)
335335
}
336336

337337
// You can't have both ENABLE_WRAP_AT_EOL_OUTPUT and
@@ -374,16 +374,28 @@ impl ConsoleRenderer {
374374
}
375375
}
376376

377-
fn set_cursor_visible(handle: HANDLE, visible: BOOL) -> Result<()> {
377+
pub struct ConsoleCursorGuard(HANDLE);
378+
379+
impl Drop for ConsoleCursorGuard {
380+
fn drop(&mut self) {
381+
let _ = set_cursor_visibility(self.0, true);
382+
}
383+
}
384+
385+
fn set_cursor_visibility(handle: HANDLE, visible: bool) -> Result<Option<ConsoleCursorGuard>> {
378386
let mut info = unsafe { mem::zeroed() };
379387
check(unsafe { wincon::GetConsoleCursorInfo(handle, &mut info) })?;
380-
if info.bVisible == visible {
381-
return Ok(());
388+
let b = if visible { TRUE } else { FALSE };
389+
if info.bVisible == b {
390+
return Ok(None);
382391
}
383-
info.bVisible = visible;
384-
Ok(check(unsafe {
385-
wincon::SetConsoleCursorInfo(handle, &info)
386-
})?)
392+
info.bVisible = b;
393+
check(unsafe { wincon::SetConsoleCursorInfo(handle, &info) })?;
394+
Ok(if visible {
395+
None
396+
} else {
397+
Some(ConsoleCursorGuard(handle))
398+
})
387399
}
388400

389401
impl Renderer for ConsoleRenderer {
@@ -449,11 +461,8 @@ impl Renderer for ConsoleRenderer {
449461
}
450462
}
451463
let info = self.get_console_screen_buffer_info()?;
452-
self.set_cursor_visible(FALSE)?; // just to avoid flickering
453-
let handle = self.conout;
454-
scopeguard::defer! {
455-
let _ = set_cursor_visible(handle, TRUE);
456-
}
464+
// just to avoid flickering
465+
let mut guard = self.set_cursor_visibility(false)?;
457466
// position at the start of the prompt, clear to end of previous input
458467
self.clear_old_rows(&info, old_layout)?;
459468
// display prompt, input line and hint
@@ -465,7 +474,7 @@ impl Renderer for ConsoleRenderer {
465474
coord.X = cursor.col as i16;
466475
coord.Y -= (end_pos.row - cursor.row) as i16;
467476
self.set_console_cursor_position(coord, info.dwSize)?;
468-
477+
guard.take();
469478
Ok(())
470479
}
471480

@@ -628,6 +637,7 @@ impl Console {
628637
}
629638

630639
impl Term for Console {
640+
type CursorGuard = ConsoleCursorGuard;
631641
type ExternalPrinter = ExternalPrinter;
632642
type KeyMap = ConsoleKeyMap;
633643
type Mode = ConsoleMode;
@@ -831,6 +841,14 @@ impl Term for Console {
831841
conout: self.conout,
832842
})
833843
}
844+
845+
fn set_cursor_visibility(&mut self, visible: bool) -> Result<Option<ConsoleCursorGuard>> {
846+
if self.conout_isatty {
847+
set_cursor_visibility(self.conout, visible)
848+
} else {
849+
Ok(None)
850+
}
851+
}
834852
}
835853

836854
impl Drop for Console {

0 commit comments

Comments
 (0)