diff --git a/src/edit/editor.rs b/src/edit/editor.rs index 1231002cec..b2c4026871 100644 --- a/src/edit/editor.rs +++ b/src/edit/editor.rs @@ -25,6 +25,11 @@ pub struct Editor<'buffer> { cursor_moved: bool, auto_indent: bool, change: Option, + // A preedit was specified with non-empty text but with empty cursor, + // indicating that the cursor should be hidden + has_preedit_without_cursor: bool, + // Set with `set_cursor_hidden` + cursor_hidden_by_setting: bool, } fn cursor_glyph_opt(cursor: &Cursor, run: &LayoutRun) -> Option<(usize, f32)> { @@ -104,6 +109,8 @@ impl<'buffer> Editor<'buffer> { cursor_moved: false, auto_indent: false, change: None, + has_preedit_without_cursor: false, + cursor_hidden_by_setting: false, } } @@ -191,8 +198,14 @@ impl<'buffer> Editor<'buffer> { } // Draw cursor - if let Some((x, y)) = cursor_position(&self.cursor, &run) { - f(x, y, 1, line_height as u32, cursor_color); + let cursor_hidden = self.cursor_hidden_by_setting + || self.has_preedit_without_cursor + || self.has_selection(); + + if !cursor_hidden { + if let Some((x, y)) = cursor_position(&self.cursor, &run) { + f(x, y, 1, line_height as u32, cursor_color); + } } for glyph in run.glyphs.iter() { @@ -255,6 +268,11 @@ impl<'buffer> Edit<'buffer> for Editor<'buffer> { } } + fn set_cursor_hidden(&mut self, hidden: bool) { + self.cursor_hidden_by_setting = hidden; + self.set_redraw(true); + } + fn selection(&self) -> Selection { self.selection } diff --git a/src/edit/mod.rs b/src/edit/mod.rs index d9d4fd11db..5385022773 100644 --- a/src/edit/mod.rs +++ b/src/edit/mod.rs @@ -203,9 +203,33 @@ pub trait Edit<'buffer> { /// Get the current cursor fn cursor(&self) -> Cursor; + /// Hide or show the cursor + /// + /// This should be used to hide the cursor, for example, + /// when the editor is unfocused, when the text is not editable, + /// or to implement cursor blinking. + /// + /// Note that even after `set_cursor_hidden(false)`, the editor may + /// choose to hide the cursor based on internal state, for example, + /// when there is a selection or when there is a preedit without a cursor. + fn set_cursor_hidden(&mut self, hidden: bool); + /// Set the current cursor fn set_cursor(&mut self, cursor: Cursor); + /// Returns true if some text is selected + fn has_selection(&self) -> bool { + match self.selection() { + Selection::None => false, + Selection::Normal(selection) => { + let cursor = self.cursor(); + selection.line != cursor.line || selection.index != cursor.index + } + Selection::Line(selection) => selection.line != self.cursor().line, + Selection::Word(_) => true, + } + } + /// Get the current selection position fn selection(&self) -> Selection; diff --git a/src/edit/syntect.rs b/src/edit/syntect.rs index d6ef2d8871..75b1e23dd3 100644 --- a/src/edit/syntect.rs +++ b/src/edit/syntect.rs @@ -256,6 +256,10 @@ impl<'syntax_system, 'buffer> Edit<'buffer> for SyntaxEditor<'syntax_system, 'bu self.editor.selection() } + fn set_cursor_hidden(&mut self, hidden: bool) { + self.editor.set_cursor_hidden(hidden); + } + fn set_selection(&mut self, selection: Selection) { self.editor.set_selection(selection); } diff --git a/src/edit/vi.rs b/src/edit/vi.rs index 08dfd480fb..e697f4f6ec 100644 --- a/src/edit/vi.rs +++ b/src/edit/vi.rs @@ -1165,6 +1165,10 @@ impl<'syntax_system, 'buffer> Edit<'buffer> for ViEditor<'syntax_system, 'buffer fn cursor_position(&self) -> Option<(i32, i32)> { self.editor.cursor_position() } + + fn set_cursor_hidden(&mut self, hidden: bool) { + self.editor.set_cursor_hidden(hidden); + } } impl<'font_system, 'syntax_system, 'buffer>