@@ -17,6 +17,7 @@ use helix_core::{
18use helix_view::{
18use helix_view::{
19 document::{Mode, SCRATCH_BUFFER_NAME},
19 document::{Mode, SCRATCH_BUFFER_NAME},
20+ editor::CursorShapeConfig,
20 graphics::{CursorKind, Modifier, Rect, Style},
21 graphics::{CursorKind, Modifier, Rect, Style},
21 info::Info,
22 info::Info,
22 input::KeyEvent,
23 input::KeyEvent,
@@ -79,7 +80,7 @@ impl EditorView {
79 let highlights: Box<dyn Iterator<Item = HighlightEvent>> = if is_focused {
80 let highlights: Box<dyn Iterator<Item = HighlightEvent>> = if is_focused {
80 Box::new(syntax::merge(
81 Box::new(syntax::merge(
81 highlights,
82 highlights,
82− Self::doc_selection_highlights(doc, view, theme),
83+ Self::doc_selection_highlights(doc, view, theme, &config.cursor_shape),
85 Box::new(highlights)
86 Box::new(highlights)
@@ -213,11 +214,16 @@ impl EditorView {
213 doc: &Document,
214 doc: &Document,
214 view: &View,
215 view: &View,
215 theme: &Theme,
216 theme: &Theme,
217+ cursor_shape_config: &CursorShapeConfig,
216 ) -> Vec<(usize, std::ops::Range<usize>)> {
218 ) -> Vec<(usize, std::ops::Range<usize>)> {
217 let text = doc.text().slice(..);
219 let text = doc.text().slice(..);
218 let selection = doc.selection(view.id);
220 let selection = doc.selection(view.id);
219 let primary_idx = selection.primary_index();
221 let primary_idx = selection.primary_index();
223+ let mode = doc.mode();
224+ let cursorkind = cursor_shape_config.from_mode(mode);
225+ let cursor_is_block = cursorkind == CursorKind::Block;
221 let selection_scope = theme
227 let selection_scope = theme
222 .find_scope_index("ui.selection")
228 .find_scope_index("ui.selection")
223 .expect("could not find `ui.selection` scope in the theme!");
229 .expect("could not find `ui.selection` scope in the theme!");
@@ -225,13 +231,16 @@ impl EditorView {
225 .find_scope_index("ui.cursor")
231 .find_scope_index("ui.cursor")
226 .unwrap_or(selection_scope);
232 .unwrap_or(selection_scope);
228− let cursor_scope = match doc.mode() {
234+ let cursor_scope = match mode {
229 Mode::Insert => theme.find_scope_index("ui.cursor.insert"),
235 Mode::Insert => theme.find_scope_index("ui.cursor.insert"),
230 Mode::Select => theme.find_scope_index("ui.cursor.select"),
236 Mode::Select => theme.find_scope_index("ui.cursor.select"),
231 Mode::Normal => Some(base_cursor_scope),
237 Mode::Normal => Some(base_cursor_scope),
233 .unwrap_or(base_cursor_scope);
239 .unwrap_or(base_cursor_scope);
241+ let primary_cursor_scope = theme
242+ .find_scope_index("ui.cursor.primary")
243+ .unwrap_or(cursor_scope);
235 let primary_selection_scope = theme
244 let primary_selection_scope = theme
236 .find_scope_index("ui.selection.primary")
245 .find_scope_index("ui.selection.primary")
237 .unwrap_or(selection_scope);
246 .unwrap_or(selection_scope);
@@ -239,16 +248,20 @@ impl EditorView {
239 let mut spans: Vec<(usize, std::ops::Range<usize>)> = Vec::new();
248 let mut spans: Vec<(usize, std::ops::Range<usize>)> = Vec::new();
240 for (i, range) in selection.iter().enumerate() {
249 for (i, range) in selection.iter().enumerate() {
241 let selection_is_primary = i == primary_idx;
250 let selection_is_primary = i == primary_idx;
242− let selection_scope = if selection_is_primary {
251+ let (cursor_scope, selection_scope) = if selection_is_primary {
243− primary_selection_scope
252+ (primary_cursor_scope, primary_selection_scope)
245− selection_scope
254+ (cursor_scope, selection_scope)
248 // Special-case: cursor at end of the rope.
257 // Special-case: cursor at end of the rope.
249 if range.head == range.anchor && range.head == text.len_chars() {
258 if range.head == range.anchor && range.head == text.len_chars() {
250− if !selection_is_primary {
259+ if !selection_is_primary || cursor_is_block {
251− // Terminal cursor acts as the primary cursor
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.
252 spans.push((cursor_scope, range.head..range.head + 1));
265 spans.push((cursor_scope, range.head..range.head + 1));
254 continue;
267 continue;
@@ -259,13 +272,13 @@ impl EditorView {
259 // Standard case.
272 // Standard case.
260 let cursor_start = prev_grapheme_boundary(text, range.head);
273 let cursor_start = prev_grapheme_boundary(text, range.head);
261 spans.push((selection_scope, range.anchor..cursor_start));
274 spans.push((selection_scope, range.anchor..cursor_start));
262− if !selection_is_primary {
275+ if !selection_is_primary || cursor_is_block {
263 spans.push((cursor_scope, cursor_start..range.head));
276 spans.push((cursor_scope, cursor_start..range.head));
266 // Reverse case.
279 // Reverse case.
267 let cursor_end = next_grapheme_boundary(text, range.head);
280 let cursor_end = next_grapheme_boundary(text, range.head);
268− if !selection_is_primary {
281+ if !selection_is_primary || cursor_is_block {
269 spans.push((cursor_scope, range.head..cursor_end));
282 spans.push((cursor_scope, range.head..cursor_end));
271 spans.push((selection_scope, cursor_end..range.anchor));
284 spans.push((selection_scope, cursor_end..range.anchor));
@@ -1140,11 +1153,11 @@ impl Component for EditorView {
1142 fn cursor(&self, _area: Rect, editor: &Editor) -> (Option<Position>, CursorKind) {
1155 fn cursor(&self, _area: Rect, editor: &Editor) -> (Option<Position>, CursorKind) {
1143− // match view.doc.mode() {
1156+ match editor.cursor() {
1144− // Mode::Insert => write!(stdout, "\x1B[6 q"),
1157+ // All block cursors are drawn manually
1145− // mode => write!(stdout, "\x1B[2 q"),
1158+ (pos, CursorKind::Block) => (pos, CursorKind::Hidden),