|
|
@ -17,6 +17,7 @@ use helix_core::{
|
|
|
|
};
|
|
|
|
};
|
|
|
|
use helix_view::{
|
|
|
|
use helix_view::{
|
|
|
|
document::{Mode, SCRATCH_BUFFER_NAME},
|
|
|
|
document::{Mode, SCRATCH_BUFFER_NAME},
|
|
|
|
|
|
|
|
editor::CursorShapeConfig,
|
|
|
|
graphics::{CursorKind, Modifier, Rect, Style},
|
|
|
|
graphics::{CursorKind, Modifier, Rect, Style},
|
|
|
|
info::Info,
|
|
|
|
info::Info,
|
|
|
|
input::KeyEvent,
|
|
|
|
input::KeyEvent,
|
|
|
@ -79,7 +80,7 @@ impl EditorView {
|
|
|
|
let highlights: Box<dyn Iterator<Item = HighlightEvent>> = if is_focused {
|
|
|
|
let highlights: Box<dyn Iterator<Item = HighlightEvent>> = if is_focused {
|
|
|
|
Box::new(syntax::merge(
|
|
|
|
Box::new(syntax::merge(
|
|
|
|
highlights,
|
|
|
|
highlights,
|
|
|
|
Self::doc_selection_highlights(doc, view, theme),
|
|
|
|
Self::doc_selection_highlights(doc, view, theme, &config.cursor_shape),
|
|
|
|
))
|
|
|
|
))
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
Box::new(highlights)
|
|
|
|
Box::new(highlights)
|
|
|
@ -213,11 +214,16 @@ impl EditorView {
|
|
|
|
doc: &Document,
|
|
|
|
doc: &Document,
|
|
|
|
view: &View,
|
|
|
|
view: &View,
|
|
|
|
theme: &Theme,
|
|
|
|
theme: &Theme,
|
|
|
|
|
|
|
|
cursor_shape_config: &CursorShapeConfig,
|
|
|
|
) -> Vec<(usize, std::ops::Range<usize>)> {
|
|
|
|
) -> Vec<(usize, std::ops::Range<usize>)> {
|
|
|
|
let text = doc.text().slice(..);
|
|
|
|
let text = doc.text().slice(..);
|
|
|
|
let selection = doc.selection(view.id);
|
|
|
|
let selection = doc.selection(view.id);
|
|
|
|
let primary_idx = selection.primary_index();
|
|
|
|
let primary_idx = selection.primary_index();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let mode = doc.mode();
|
|
|
|
|
|
|
|
let cursorkind = cursor_shape_config.from_mode(mode);
|
|
|
|
|
|
|
|
let cursor_is_block = cursorkind == CursorKind::Block;
|
|
|
|
|
|
|
|
|
|
|
|
let selection_scope = theme
|
|
|
|
let selection_scope = theme
|
|
|
|
.find_scope_index("ui.selection")
|
|
|
|
.find_scope_index("ui.selection")
|
|
|
|
.expect("could not find `ui.selection` scope in the theme!");
|
|
|
|
.expect("could not find `ui.selection` scope in the theme!");
|
|
|
@ -225,13 +231,16 @@ impl EditorView {
|
|
|
|
.find_scope_index("ui.cursor")
|
|
|
|
.find_scope_index("ui.cursor")
|
|
|
|
.unwrap_or(selection_scope);
|
|
|
|
.unwrap_or(selection_scope);
|
|
|
|
|
|
|
|
|
|
|
|
let cursor_scope = match doc.mode() {
|
|
|
|
let cursor_scope = match mode {
|
|
|
|
Mode::Insert => theme.find_scope_index("ui.cursor.insert"),
|
|
|
|
Mode::Insert => theme.find_scope_index("ui.cursor.insert"),
|
|
|
|
Mode::Select => theme.find_scope_index("ui.cursor.select"),
|
|
|
|
Mode::Select => theme.find_scope_index("ui.cursor.select"),
|
|
|
|
Mode::Normal => Some(base_cursor_scope),
|
|
|
|
Mode::Normal => Some(base_cursor_scope),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
.unwrap_or(base_cursor_scope);
|
|
|
|
.unwrap_or(base_cursor_scope);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let primary_cursor_scope = theme
|
|
|
|
|
|
|
|
.find_scope_index("ui.cursor.primary")
|
|
|
|
|
|
|
|
.unwrap_or(cursor_scope);
|
|
|
|
let primary_selection_scope = theme
|
|
|
|
let primary_selection_scope = theme
|
|
|
|
.find_scope_index("ui.selection.primary")
|
|
|
|
.find_scope_index("ui.selection.primary")
|
|
|
|
.unwrap_or(selection_scope);
|
|
|
|
.unwrap_or(selection_scope);
|
|
|
@ -239,16 +248,20 @@ impl EditorView {
|
|
|
|
let mut spans: Vec<(usize, std::ops::Range<usize>)> = Vec::new();
|
|
|
|
let mut spans: Vec<(usize, std::ops::Range<usize>)> = Vec::new();
|
|
|
|
for (i, range) in selection.iter().enumerate() {
|
|
|
|
for (i, range) in selection.iter().enumerate() {
|
|
|
|
let selection_is_primary = i == primary_idx;
|
|
|
|
let selection_is_primary = i == primary_idx;
|
|
|
|
let selection_scope = if selection_is_primary {
|
|
|
|
let (cursor_scope, selection_scope) = if selection_is_primary {
|
|
|
|
primary_selection_scope
|
|
|
|
(primary_cursor_scope, primary_selection_scope)
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
selection_scope
|
|
|
|
(cursor_scope, selection_scope)
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 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 {
|
|
|
|
if !selection_is_primary || cursor_is_block {
|
|
|
|
// Terminal cursor acts as the primary cursor
|
|
|
|
// Bar and underline cursors are drawn by the terminal
|
|
|
|
|
|
|
|
// BUG: If the editor area loses focus while having a bar or
|
|
|
|
|
|
|
|
// underline cursor (eg. when a regex prompt has focus) then
|
|
|
|
|
|
|
|
// the primary cursor will be invisible. This doesn't happen
|
|
|
|
|
|
|
|
// with block cursors since we manually draw *all* cursors.
|
|
|
|
spans.push((cursor_scope, range.head..range.head + 1));
|
|
|
|
spans.push((cursor_scope, range.head..range.head + 1));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
continue;
|
|
|
@ -259,13 +272,13 @@ impl EditorView {
|
|
|
|
// Standard case.
|
|
|
|
// Standard case.
|
|
|
|
let cursor_start = prev_grapheme_boundary(text, range.head);
|
|
|
|
let cursor_start = prev_grapheme_boundary(text, range.head);
|
|
|
|
spans.push((selection_scope, range.anchor..cursor_start));
|
|
|
|
spans.push((selection_scope, range.anchor..cursor_start));
|
|
|
|
if !selection_is_primary {
|
|
|
|
if !selection_is_primary || cursor_is_block {
|
|
|
|
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);
|
|
|
|
if !selection_is_primary {
|
|
|
|
if !selection_is_primary || cursor_is_block {
|
|
|
|
spans.push((cursor_scope, range.head..cursor_end));
|
|
|
|
spans.push((cursor_scope, range.head..cursor_end));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
spans.push((selection_scope, cursor_end..range.anchor));
|
|
|
|
spans.push((selection_scope, cursor_end..range.anchor));
|
|
|
@ -1140,11 +1153,11 @@ impl Component for EditorView {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fn cursor(&self, _area: Rect, editor: &Editor) -> (Option<Position>, CursorKind) {
|
|
|
|
fn cursor(&self, _area: Rect, editor: &Editor) -> (Option<Position>, CursorKind) {
|
|
|
|
// match view.doc.mode() {
|
|
|
|
match editor.cursor() {
|
|
|
|
// Mode::Insert => write!(stdout, "\x1B[6 q"),
|
|
|
|
// All block cursors are drawn manually
|
|
|
|
// mode => write!(stdout, "\x1B[2 q"),
|
|
|
|
(pos, CursorKind::Block) => (pos, CursorKind::Hidden),
|
|
|
|
// };
|
|
|
|
cursor => cursor,
|
|
|
|
editor.cursor()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|