@@ -19,6 +19,7 @@ use helix_core::{
20use helix_view::{
20use helix_view::{
21 document::{Mode, SCRATCH_BUFFER_NAME},
21 document::{Mode, SCRATCH_BUFFER_NAME},
22+ editor::CursorShapeConfig,
22 graphics::{CursorKind, Modifier, Rect, Style},
23 graphics::{CursorKind, Modifier, Rect, Style},
23 info::Info,
24 info::Info,
24 input::KeyEvent,
25 input::KeyEvent,
@@ -80,7 +81,7 @@ impl EditorView {
80 let highlights: Box<dyn Iterator<Item = HighlightEvent>> = if is_focused {
81 let highlights: Box<dyn Iterator<Item = HighlightEvent>> = if is_focused {
81 Box::new(syntax::merge(
82 Box::new(syntax::merge(
82 highlights,
83 highlights,
83− Self::doc_selection_highlights(doc, view, theme),
84+ Self::doc_selection_highlights(doc, view, theme, &config.cursor_shape),
86 Box::new(highlights)
87 Box::new(highlights)
@@ -195,11 +196,16 @@ impl EditorView {
195 doc: &Document,
196 doc: &Document,
196 view: &View,
197 view: &View,
197 theme: &Theme,
198 theme: &Theme,
199+ cursor_shape_config: &CursorShapeConfig,
198 ) -> Vec<(usize, std::ops::Range<usize>)> {
200 ) -> Vec<(usize, std::ops::Range<usize>)> {
199 let text = doc.text().slice(..);
201 let text = doc.text().slice(..);
200 let selection = doc.selection(view.id);
202 let selection = doc.selection(view.id);
201 let primary_idx = selection.primary_index();
203 let primary_idx = selection.primary_index();
205+ let mode = doc.mode();
206+ let cursorkind = cursor_shape_config.from_mode(mode);
207+ let cursor_is_block = cursorkind == CursorKind::Block;
203 let selection_scope = theme
209 let selection_scope = theme
204 .find_scope_index("ui.selection")
210 .find_scope_index("ui.selection")
205 .expect("could not find `ui.selection` scope in the theme!");
211 .expect("could not find `ui.selection` scope in the theme!");
@@ -207,7 +213,7 @@ impl EditorView {
207 .find_scope_index("ui.cursor")
213 .find_scope_index("ui.cursor")
208 .unwrap_or(selection_scope);
214 .unwrap_or(selection_scope);
210− let cursor_scope = match doc.mode() {
216+ let cursor_scope = match mode {
211 Mode::Insert => theme.find_scope_index("ui.cursor.insert"),
217 Mode::Insert => theme.find_scope_index("ui.cursor.insert"),
212 Mode::Select => theme.find_scope_index("ui.cursor.select"),
218 Mode::Select => theme.find_scope_index("ui.cursor.select"),
213 Mode::Normal => Some(base_cursor_scope),
219 Mode::Normal => Some(base_cursor_scope),
@@ -223,7 +229,8 @@ impl EditorView {
224 let mut spans: Vec<(usize, std::ops::Range<usize>)> = Vec::new();
230 let mut spans: Vec<(usize, std::ops::Range<usize>)> = Vec::new();
225 for (i, range) in selection.iter().enumerate() {
231 for (i, range) in selection.iter().enumerate() {
232+ let selection_is_primary = i == primary_idx;
226− let (cursor_scope, selection_scope) = if i == primary_idx {
233+ let (cursor_scope, selection_scope) = if selection_is_primary {
227 (primary_cursor_scope, primary_selection_scope)
234 (primary_cursor_scope, primary_selection_scope)
229 (cursor_scope, selection_scope)
236 (cursor_scope, selection_scope)
@@ -231,7 +238,14 @@ impl EditorView {
232 // Special-case: cursor at end of the rope.
239 // Special-case: cursor at end of the rope.
233 if range.head == range.anchor && range.head == text.len_chars() {
240 if range.head == range.anchor && range.head == text.len_chars() {
241+ if !selection_is_primary || cursor_is_block {
242+ // Bar and underline cursors are drawn by the terminal
243+ // BUG: If the editor area loses focus while having a bar or
244+ // underline cursor (eg. when a regex prompt has focus) then
245+ // the primary cursor will be invisible. This doesn't happen
246+ // with block cursors since we manually draw *all* cursors.
234− spans.push((cursor_scope, range.head..range.head + 1));
247+ spans.push((cursor_scope, range.head..range.head + 1));
235 continue;
249 continue;
@@ -240,11 +254,15 @@ impl EditorView {
240 // Standard case.
254 // Standard case.
241 let cursor_start = prev_grapheme_boundary(text, range.head);
255 let cursor_start = prev_grapheme_boundary(text, range.head);
242 spans.push((selection_scope, range.anchor..cursor_start));
256 spans.push((selection_scope, range.anchor..cursor_start));
257+ if !selection_is_primary || cursor_is_block {
243− spans.push((cursor_scope, cursor_start..range.head));
258+ spans.push((cursor_scope, cursor_start..range.head));
245 // Reverse case.
261 // Reverse case.
246 let cursor_end = next_grapheme_boundary(text, range.head);
262 let cursor_end = next_grapheme_boundary(text, range.head);
263+ if !selection_is_primary || cursor_is_block {
247− spans.push((cursor_scope, range.head..cursor_end));
264+ spans.push((cursor_scope, range.head..cursor_end));
248 spans.push((selection_scope, cursor_end..range.anchor));
266 spans.push((selection_scope, cursor_end..range.anchor));
@@ -1141,11 +1159,11 @@ impl Component for EditorView {
1143 fn cursor(&self, _area: Rect, editor: &Editor) -> (Option<Position>, CursorKind) {
1161 fn cursor(&self, _area: Rect, editor: &Editor) -> (Option<Position>, CursorKind) {
1144− // match view.doc.mode() {
1162+ match editor.cursor() {
1145− // Mode::Insert => write!(stdout, "\x1B[6 q"),
1163+ // All block cursors are drawn manually
1146− // mode => write!(stdout, "\x1B[2 q"),
1164+ (pos, CursorKind::Block) => (pos, CursorKind::Hidden),