on master help sign in
Manually draw all block cursors
commitc0bbadcaaf42698d102fa03f6f9267021f3efec0 authorGokul Soumya <gokulps15@gmail.com> dateThu 23 Dec 2021, 11:56 (5 years ago) parentd4fb1d0
4 files changed+36−21
book/src/themes.md+1 helix-syntax/languages/tree-sitter-scala+1−1 helix-term/src/ui/editor.rs+27−14 helix-view/src/editor.rs+7−6
book/src/themes.md+1
@@ -188,6 +188,7 @@ These scopes are used for theming the editor interface.
188188| `ui.cursor.insert` | |
189189| `ui.cursor.select` | |
190190| `ui.cursor.match` | Matching bracket etc. |
191+| `ui.cursor.primary` | Cursor with primary selection |
191192| `ui.linenr` | |
192193| `ui.linenr.selected` | |
193194| `ui.statusline` | Statusline |
helix-syntax/languages/tree-sitter-scala+1−1

Submodule changed.

helix-term/src/ui/editor.rs+27−14
@@ -17,6 +17,7 @@ use helix_core::{
1717};
1818use helix_view::{
1919 document::{Mode, SCRATCH_BUFFER_NAME},
20+ editor::CursorShapeConfig,
2021 graphics::{CursorKind, Modifier, Rect, Style},
2122 info::Info,
2223 input::KeyEvent,
@@ -79,7 +80,7 @@ impl EditorView {
7980 let highlights: Box<dyn Iterator<Item = HighlightEvent>> = if is_focused {
8081 Box::new(syntax::merge(
8182 highlights,
82− Self::doc_selection_highlights(doc, view, theme),
83+ Self::doc_selection_highlights(doc, view, theme, &config.cursor_shape),
8384 ))
8485 } else {
8586 Box::new(highlights)
@@ -213,11 +214,16 @@ impl EditorView {
213214 doc: &Document,
214215 view: &View,
215216 theme: &Theme,
217+ cursor_shape_config: &CursorShapeConfig,
216218 ) -> Vec<(usize, std::ops::Range<usize>)> {
217219 let text = doc.text().slice(..);
218220 let selection = doc.selection(view.id);
219221 let primary_idx = selection.primary_index();
220222
223+ let mode = doc.mode();
224+ let cursorkind = cursor_shape_config.from_mode(mode);
225+ let cursor_is_block = cursorkind == CursorKind::Block;
226+
221227 let selection_scope = theme
222228 .find_scope_index("ui.selection")
223229 .expect("could not find `ui.selection` scope in the theme!");
@@ -225,13 +231,16 @@ impl EditorView {
225231 .find_scope_index("ui.cursor")
226232 .unwrap_or(selection_scope);
227233
228− let cursor_scope = match doc.mode() {
234+ let cursor_scope = match mode {
229235 Mode::Insert => theme.find_scope_index("ui.cursor.insert"),
230236 Mode::Select => theme.find_scope_index("ui.cursor.select"),
231237 Mode::Normal => Some(base_cursor_scope),
232238 }
233239 .unwrap_or(base_cursor_scope);
234240
241+ let primary_cursor_scope = theme
242+ .find_scope_index("ui.cursor.primary")
243+ .unwrap_or(cursor_scope);
235244 let primary_selection_scope = theme
236245 .find_scope_index("ui.selection.primary")
237246 .unwrap_or(selection_scope);
@@ -239,16 +248,20 @@ impl EditorView {
239248 let mut spans: Vec<(usize, std::ops::Range<usize>)> = Vec::new();
240249 for (i, range) in selection.iter().enumerate() {
241250 let selection_is_primary = i == primary_idx;
242− let selection_scope = if selection_is_primary {
243− primary_selection_scope
251+ let (cursor_scope, selection_scope) = if selection_is_primary {
252+ (primary_cursor_scope, primary_selection_scope)
244253 } else {
245− selection_scope
254+ (cursor_scope, selection_scope)
246255 };
247256
248257 // Special-case: cursor at end of the rope.
249258 if range.head == range.anchor && range.head == text.len_chars() {
250− if !selection_is_primary {
251− // Terminal cursor acts as the primary cursor
259+ if !selection_is_primary || cursor_is_block {
260+ // Bar and underline cursors are drawn by the terminal
261+ // BUG: If the editor area loses focus while having a bar or
262+ // underline cursor (eg. when a regex prompt has focus) then
263+ // the primary cursor will be invisible. This doesn't happen
264+ // with block cursors since we manually draw *all* cursors.
252265 spans.push((cursor_scope, range.head..range.head + 1));
253266 }
254267 continue;
@@ -259,13 +272,13 @@ impl EditorView {
259272 // Standard case.
260273 let cursor_start = prev_grapheme_boundary(text, range.head);
261274 spans.push((selection_scope, range.anchor..cursor_start));
262− if !selection_is_primary {
275+ if !selection_is_primary || cursor_is_block {
263276 spans.push((cursor_scope, cursor_start..range.head));
264277 }
265278 } else {
266279 // Reverse case.
267280 let cursor_end = next_grapheme_boundary(text, range.head);
268− if !selection_is_primary {
281+ if !selection_is_primary || cursor_is_block {
269282 spans.push((cursor_scope, range.head..cursor_end));
270283 }
271284 spans.push((selection_scope, cursor_end..range.anchor));
@@ -1140,11 +1153,11 @@ impl Component for EditorView {
11401153 }
11411154
11421155 fn cursor(&self, _area: Rect, editor: &Editor) -> (Option<Position>, CursorKind) {
1143− // match view.doc.mode() {
1144− // Mode::Insert => write!(stdout, "\x1B[6 q"),
1145− // mode => write!(stdout, "\x1B[2 q"),
1146− // };
1147− editor.cursor()
1156+ match editor.cursor() {
1157+ // All block cursors are drawn manually
1158+ (pos, CursorKind::Block) => (pos, CursorKind::Hidden),
1159+ cursor => cursor,
1160+ }
11481161 }
11491162}
11501163
helix-view/src/editor.rs+7−6
@@ -116,6 +116,12 @@ pub struct Config {
116116#[derive(Debug, Clone, PartialEq)]
117117pub struct CursorShapeConfig([CursorKind; 3]);
118118
119+impl CursorShapeConfig {
120+ pub fn from_mode(&self, mode: Mode) -> CursorKind {
121+ self.get(mode as usize).copied().unwrap_or_default()
122+ }
123+}
124+
119125impl<'de> Deserialize<'de> for CursorShapeConfig {
120126 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
121127 where
@@ -647,12 +653,7 @@ impl Editor {
647653 let inner = view.inner_area();
648654 pos.col += inner.x as usize;
649655 pos.row += inner.y as usize;
650− let cursorkind = self
651− .config
652− .cursor_shape
653− .get(doc.mode() as usize)
654− .copied()
655− .unwrap_or_default();
656+ let cursorkind = self.config.cursor_shape.from_mode(doc.mode());
656657 (Some(pos), cursorkind)
657658 } else {
658659 (None, CursorKind::default())