aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--book/src/themes.md1
m---------helix-syntax/languages/tree-sitter-scala0
-rw-r--r--helix-term/src/ui/editor.rs41
-rw-r--r--helix-view/src/editor.rs13
4 files changed, 35 insertions, 20 deletions
diff --git a/book/src/themes.md b/book/src/themes.md
index 40c14781..b6de7002 100644
--- a/book/src/themes.md
+++ b/book/src/themes.md
@@ -188,6 +188,7 @@ These scopes are used for theming the editor interface.
| `ui.cursor.insert` | |
| `ui.cursor.select` | |
| `ui.cursor.match` | Matching bracket etc. |
+| `ui.cursor.primary` | Cursor with primary selection |
| `ui.linenr` | |
| `ui.linenr.selected` | |
| `ui.statusline` | Statusline |
diff --git a/helix-syntax/languages/tree-sitter-scala b/helix-syntax/languages/tree-sitter-scala
-Subproject fb23ed9a99da012d86b7a5059b9d8928607cce2
+Subproject 0a3dd53a7fc4b352a538397d054380aaa28be54
diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs
index 7d57e581..6b015171 100644
--- a/helix-term/src/ui/editor.rs
+++ b/helix-term/src/ui/editor.rs
@@ -17,6 +17,7 @@ use helix_core::{
};
use helix_view::{
document::{Mode, SCRATCH_BUFFER_NAME},
+ editor::CursorShapeConfig,
graphics::{CursorKind, Modifier, Rect, Style},
info::Info,
input::KeyEvent,
@@ -79,7 +80,7 @@ impl EditorView {
let highlights: Box<dyn Iterator<Item = HighlightEvent>> = if is_focused {
Box::new(syntax::merge(
highlights,
- Self::doc_selection_highlights(doc, view, theme),
+ Self::doc_selection_highlights(doc, view, theme, &config.cursor_shape),
))
} else {
Box::new(highlights)
@@ -213,11 +214,16 @@ impl EditorView {
doc: &Document,
view: &View,
theme: &Theme,
+ cursor_shape_config: &CursorShapeConfig,
) -> Vec<(usize, std::ops::Range<usize>)> {
let text = doc.text().slice(..);
let selection = doc.selection(view.id);
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
.find_scope_index("ui.selection")
.expect("could not find `ui.selection` scope in the theme!");
@@ -225,13 +231,16 @@ impl EditorView {
.find_scope_index("ui.cursor")
.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::Select => theme.find_scope_index("ui.cursor.select"),
Mode::Normal => Some(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
.find_scope_index("ui.selection.primary")
.unwrap_or(selection_scope);
@@ -239,16 +248,20 @@ impl EditorView {
let mut spans: Vec<(usize, std::ops::Range<usize>)> = Vec::new();
for (i, range) in selection.iter().enumerate() {
let selection_is_primary = i == primary_idx;
- let selection_scope = if selection_is_primary {
- primary_selection_scope
+ let (cursor_scope, selection_scope) = if selection_is_primary {
+ (primary_cursor_scope, primary_selection_scope)
} else {
- selection_scope
+ (cursor_scope, selection_scope)
};
// Special-case: cursor at end of the rope.
if range.head == range.anchor && range.head == text.len_chars() {
- if !selection_is_primary {
- // Terminal cursor acts as the primary cursor
+ if !selection_is_primary || cursor_is_block {
+ // 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));
}
continue;
@@ -259,13 +272,13 @@ impl EditorView {
// Standard case.
let cursor_start = prev_grapheme_boundary(text, range.head);
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));
}
} else {
// Reverse case.
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((selection_scope, cursor_end..range.anchor));
@@ -1140,11 +1153,11 @@ impl Component for EditorView {
}
fn cursor(&self, _area: Rect, editor: &Editor) -> (Option<Position>, CursorKind) {
- // match view.doc.mode() {
- // Mode::Insert => write!(stdout, "\x1B[6 q"),
- // mode => write!(stdout, "\x1B[2 q"),
- // };
- editor.cursor()
+ match editor.cursor() {
+ // All block cursors are drawn manually
+ (pos, CursorKind::Block) => (pos, CursorKind::Hidden),
+ cursor => cursor,
+ }
}
}
diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs
index fff4792d..d65c1fb2 100644
--- a/helix-view/src/editor.rs
+++ b/helix-view/src/editor.rs
@@ -116,6 +116,12 @@ pub struct Config {
#[derive(Debug, Clone, PartialEq)]
pub struct CursorShapeConfig([CursorKind; 3]);
+impl CursorShapeConfig {
+ pub fn from_mode(&self, mode: Mode) -> CursorKind {
+ self.get(mode as usize).copied().unwrap_or_default()
+ }
+}
+
impl<'de> Deserialize<'de> for CursorShapeConfig {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
@@ -647,12 +653,7 @@ impl Editor {
let inner = view.inner_area();
pos.col += inner.x as usize;
pos.row += inner.y as usize;
- let cursorkind = self
- .config
- .cursor_shape
- .get(doc.mode() as usize)
- .copied()
- .unwrap_or_default();
+ let cursorkind = self.config.cursor_shape.from_mode(doc.mode());
(Some(pos), cursorkind)
} else {
(None, CursorKind::default())