mirror of https://github.com/helix-editor/helix
fix: show primary cursor when command prompt is active
When the command prompt (:) is active, the terminal cursor moves to the prompt line, leaving the primary cursor position in the editor invisible. This change detects when a prompt component is active and forces the primary cursor to be drawn manually in the editor while the prompt is shown. - Add prompt_active field to EditorView to track prompt state - Update compositor to detect and communicate prompt state to EditorView - Modify cursor highlighting logic to force primary cursor drawing when prompt is active - Maintain real terminal cursor for prompt while showing fake cursor in editorpull/13821/head
parent
5af123a4d9
commit
7d17fd7ba3
|
@ -177,7 +177,14 @@ impl Compositor {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn render(&mut self, area: Rect, surface: &mut Surface, cx: &mut Context) {
|
pub fn render(&mut self, area: Rect, surface: &mut Surface, cx: &mut Context) {
|
||||||
|
// Check if there are prompt layers active and update EditorView
|
||||||
|
let has_prompt = self.has_component("helix_term::ui::prompt::Prompt");
|
||||||
|
|
||||||
for layer in &mut self.layers {
|
for layer in &mut self.layers {
|
||||||
|
// Update prompt state for EditorView
|
||||||
|
if let Some(editor_view) = layer.as_any_mut().downcast_mut::<crate::ui::EditorView>() {
|
||||||
|
editor_view.prompt_active = has_prompt;
|
||||||
|
}
|
||||||
layer.render(area, surface, cx);
|
layer.render(area, surface, cx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,6 +44,8 @@ pub struct EditorView {
|
||||||
spinners: ProgressSpinners,
|
spinners: ProgressSpinners,
|
||||||
/// Tracks if the terminal window is focused by reaction to terminal focus events
|
/// Tracks if the terminal window is focused by reaction to terminal focus events
|
||||||
terminal_focused: bool,
|
terminal_focused: bool,
|
||||||
|
/// Tracks if there are prompt layers active (updated by compositor)
|
||||||
|
pub prompt_active: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
@ -67,6 +69,7 @@ impl EditorView {
|
||||||
completion: None,
|
completion: None,
|
||||||
spinners: ProgressSpinners::default(),
|
spinners: ProgressSpinners::default(),
|
||||||
terminal_focused: true,
|
terminal_focused: true,
|
||||||
|
prompt_active: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -133,7 +136,7 @@ impl EditorView {
|
||||||
if let Some(tabstops) = Self::tabstop_highlights(doc, theme) {
|
if let Some(tabstops) = Self::tabstop_highlights(doc, theme) {
|
||||||
overlays.push(tabstops);
|
overlays.push(tabstops);
|
||||||
}
|
}
|
||||||
overlays.push(Self::doc_selection_highlights(
|
overlays.push(self.doc_selection_highlights(
|
||||||
editor.mode(),
|
editor.mode(),
|
||||||
doc,
|
doc,
|
||||||
view,
|
view,
|
||||||
|
@ -427,7 +430,8 @@ impl EditorView {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get highlight spans for selections in a document view.
|
/// Get highlight spans for selections in a document view.
|
||||||
pub fn doc_selection_highlights(
|
fn doc_selection_highlights(
|
||||||
|
&self,
|
||||||
mode: Mode,
|
mode: Mode,
|
||||||
doc: &Document,
|
doc: &Document,
|
||||||
view: &View,
|
view: &View,
|
||||||
|
@ -481,9 +485,9 @@ impl EditorView {
|
||||||
|
|
||||||
// Special-case: cursor at end of the rope.
|
// Special-case: cursor at end of the rope.
|
||||||
if range.head == range.anchor && range.head == text.len_chars() {
|
if range.head == range.anchor && range.head == text.len_chars() {
|
||||||
if !selection_is_primary || !is_terminal_focused {
|
if !selection_is_primary || !is_terminal_focused || self.prompt_active {
|
||||||
// Primary cursor is drawn by the terminal when focused
|
// Primary cursor is drawn by the terminal when focused and no prompt is active
|
||||||
// Secondary cursors and unfocused primary cursor are drawn manually
|
// Secondary cursors, unfocused primary cursor, and editor cursor when prompt is active are drawn manually
|
||||||
spans.push((cursor_scope, range.head..range.head + 1));
|
spans.push((cursor_scope, range.head..range.head + 1));
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
|
@ -502,16 +506,16 @@ impl EditorView {
|
||||||
};
|
};
|
||||||
spans.push((selection_scope, range.anchor..selection_end));
|
spans.push((selection_scope, range.anchor..selection_end));
|
||||||
// add cursors
|
// add cursors
|
||||||
// skip primary cursor if terminal is focused - terminal cursor is used in that case
|
// skip primary cursor if terminal is focused and no prompt is active - terminal cursor is used in that case
|
||||||
if !selection_is_primary || !is_terminal_focused {
|
if !selection_is_primary || !is_terminal_focused || self.prompt_active {
|
||||||
spans.push((cursor_scope, cursor_start..range.head));
|
spans.push((cursor_scope, cursor_start..range.head));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Reverse case.
|
// Reverse case.
|
||||||
let cursor_end = next_grapheme_boundary(text, range.head);
|
let cursor_end = next_grapheme_boundary(text, range.head);
|
||||||
// add cursors
|
// add cursors
|
||||||
// skip primary cursor if terminal is focused - terminal cursor is used in that case
|
// skip primary cursor if terminal is focused and no prompt is active - terminal cursor is used in that case
|
||||||
if !selection_is_primary || !is_terminal_focused {
|
if !selection_is_primary || !is_terminal_focused || self.prompt_active {
|
||||||
spans.push((cursor_scope, range.head..cursor_end));
|
spans.push((cursor_scope, range.head..cursor_end));
|
||||||
}
|
}
|
||||||
// non block cursors look like they exclude the cursor
|
// non block cursors look like they exclude the cursor
|
||||||
|
|
Loading…
Reference in New Issue