mirror of
https://github.com/helix-editor/helix.git
synced 2025-01-19 13:37:06 +04:00
Change cursor shape on mode change
Fixes #323. Due to terminal limitations we can only change the shape of the primary cursor.
This commit is contained in:
parent
21143e8d22
commit
7961355ba1
@ -5,9 +5,26 @@ # Configuration
|
|||||||
* Linux and Mac: `~/.config/helix/config.toml`
|
* Linux and Mac: `~/.config/helix/config.toml`
|
||||||
* Windows: `%AppData%\helix\config.toml`
|
* Windows: `%AppData%\helix\config.toml`
|
||||||
|
|
||||||
|
Example config:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
theme = "onedark"
|
||||||
|
|
||||||
|
[editor]
|
||||||
|
line-number = "relative"
|
||||||
|
mouse = false
|
||||||
|
|
||||||
|
[editor.cursor-shape]
|
||||||
|
normal = "underline"
|
||||||
|
insert = "block"
|
||||||
|
|
||||||
|
[editor.file-picker]
|
||||||
|
hidden = false
|
||||||
|
```
|
||||||
|
|
||||||
## Editor
|
## Editor
|
||||||
|
|
||||||
`[editor]` section of the config.
|
### `[editor]` Section
|
||||||
|
|
||||||
| Key | Description | Default |
|
| Key | Description | Default |
|
||||||
|--|--|---------|
|
|--|--|---------|
|
||||||
@ -24,7 +41,28 @@ ## Editor
|
|||||||
| `completion-trigger-len` | The min-length of word under cursor to trigger autocompletion | `2` |
|
| `completion-trigger-len` | The min-length of word under cursor to trigger autocompletion | `2` |
|
||||||
| `auto-info` | Whether to display infoboxes | `true` |
|
| `auto-info` | Whether to display infoboxes | `true` |
|
||||||
|
|
||||||
`[editor.filepicker]` section of the config. Sets options for file picker and global search. All but the last key listed in the default file-picker configuration below are IgnoreOptions: whether hidden files and files listed within ignore files are ignored by (not visible in) the helix file picker and global search. There is also one other key, `max-depth` available, which is not defined by default.
|
### `[editor.cursor-shape]` Section
|
||||||
|
|
||||||
|
Defines the shape of cursor in each mode. Note that due to limitations
|
||||||
|
of the terminal environment, only the primary cursor can change shape.
|
||||||
|
|
||||||
|
| Key | Description | Default |
|
||||||
|
| --- | ----------- | -------- |
|
||||||
|
| `normal` | Cursor shape in [normal mode][normal mode] | `block` |
|
||||||
|
| `insert` | Cursor shape in [insert mode][insert mode] | `bar` |
|
||||||
|
| `select` | Cursor shape in [select mode][select mode] | `underline` |
|
||||||
|
|
||||||
|
[normal mode]: ./keymap.md#normal-mode
|
||||||
|
[insert mode]: ./keymap.md#insert-mode
|
||||||
|
[select mode]: ./keymap.md#select--extend-mode
|
||||||
|
|
||||||
|
### `[editor.filepicker]` Section
|
||||||
|
|
||||||
|
Sets options for file picker and global search. All but the last key listed in
|
||||||
|
the default file-picker configuration below are IgnoreOptions: whether hidden
|
||||||
|
files and files listed within ignore files are ignored by (not visible in) the
|
||||||
|
helix file picker and global search. There is also one other key, `max-depth`
|
||||||
|
available, which is not defined by default.
|
||||||
|
|
||||||
| Key | Description | Default |
|
| Key | Description | Default |
|
||||||
|--|--|---------|
|
|--|--|---------|
|
||||||
|
@ -250,7 +250,9 @@ pub fn doc_selection_highlights(
|
|||||||
|
|
||||||
// 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() {
|
||||||
spans.push((cursor_scope, range.head..range.head + 1));
|
if i != primary_idx {
|
||||||
|
spans.push((cursor_scope, range.head..range.head + 1));
|
||||||
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -259,11 +261,15 @@ pub fn doc_selection_highlights(
|
|||||||
// 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));
|
||||||
spans.push((cursor_scope, cursor_start..range.head));
|
if i != primary_idx {
|
||||||
|
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);
|
||||||
spans.push((cursor_scope, range.head..cursor_end));
|
if i != primary_idx {
|
||||||
|
spans.push((cursor_scope, range.head..cursor_end));
|
||||||
|
}
|
||||||
spans.push((selection_scope, cursor_end..range.anchor));
|
spans.push((selection_scope, cursor_end..range.anchor));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
clipboard::{get_clipboard_provider, ClipboardProvider},
|
clipboard::{get_clipboard_provider, ClipboardProvider},
|
||||||
document::SCRATCH_BUFFER_NAME,
|
document::{Mode, SCRATCH_BUFFER_NAME},
|
||||||
graphics::{CursorKind, Rect},
|
graphics::{CursorKind, Rect},
|
||||||
theme::{self, Theme},
|
theme::{self, Theme},
|
||||||
tree::{self, Tree},
|
tree::{self, Tree},
|
||||||
@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
use futures_util::future;
|
use futures_util::future;
|
||||||
use std::{
|
use std::{
|
||||||
collections::BTreeMap,
|
collections::{BTreeMap, HashMap},
|
||||||
io::stdin,
|
io::stdin,
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
pin::Pin,
|
pin::Pin,
|
||||||
@ -22,7 +22,7 @@
|
|||||||
|
|
||||||
pub use helix_core::diagnostic::Severity;
|
pub use helix_core::diagnostic::Severity;
|
||||||
pub use helix_core::register::Registers;
|
pub use helix_core::register::Registers;
|
||||||
use helix_core::syntax;
|
use helix_core::{hashmap, syntax};
|
||||||
use helix_core::{Position, Selection};
|
use helix_core::{Position, Selection};
|
||||||
|
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
@ -103,6 +103,30 @@ pub struct Config {
|
|||||||
/// Whether to display infoboxes. Defaults to true.
|
/// Whether to display infoboxes. Defaults to true.
|
||||||
pub auto_info: bool,
|
pub auto_info: bool,
|
||||||
pub file_picker: FilePickerConfig,
|
pub file_picker: FilePickerConfig,
|
||||||
|
/// Shape for cursor in each mode
|
||||||
|
pub cursor_shape: CursorShapeConfig,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Deserialize)]
|
||||||
|
#[serde(transparent)]
|
||||||
|
pub struct CursorShapeConfig(HashMap<Mode, CursorKind>);
|
||||||
|
|
||||||
|
impl std::ops::Deref for CursorShapeConfig {
|
||||||
|
type Target = HashMap<Mode, CursorKind>;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for CursorShapeConfig {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self(hashmap!(
|
||||||
|
Mode::Insert => CursorKind::Bar,
|
||||||
|
Mode::Normal => CursorKind::Block,
|
||||||
|
Mode::Select => CursorKind::Underline,
|
||||||
|
))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
|
||||||
@ -110,7 +134,6 @@ pub struct Config {
|
|||||||
pub enum LineNumber {
|
pub enum LineNumber {
|
||||||
/// Show absolute line number
|
/// Show absolute line number
|
||||||
Absolute,
|
Absolute,
|
||||||
|
|
||||||
/// Show relative line number to the primary cursor
|
/// Show relative line number to the primary cursor
|
||||||
Relative,
|
Relative,
|
||||||
}
|
}
|
||||||
@ -135,6 +158,7 @@ fn default() -> Self {
|
|||||||
completion_trigger_len: 2,
|
completion_trigger_len: 2,
|
||||||
auto_info: true,
|
auto_info: true,
|
||||||
file_picker: FilePickerConfig::default(),
|
file_picker: FilePickerConfig::default(),
|
||||||
|
cursor_shape: CursorShapeConfig::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -594,9 +618,15 @@ pub fn cursor(&self) -> (Option<Position>, CursorKind) {
|
|||||||
let inner = view.inner_area();
|
let inner = view.inner_area();
|
||||||
pos.col += inner.x as usize;
|
pos.col += inner.x as usize;
|
||||||
pos.row += inner.y as usize;
|
pos.row += inner.y as usize;
|
||||||
(Some(pos), CursorKind::Hidden)
|
let cursorkind = self
|
||||||
|
.config
|
||||||
|
.cursor_shape
|
||||||
|
.get(&doc.mode())
|
||||||
|
.copied()
|
||||||
|
.unwrap_or_default();
|
||||||
|
(Some(pos), cursorkind)
|
||||||
} else {
|
} else {
|
||||||
(None, CursorKind::Hidden)
|
(None, CursorKind::default())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
|
use anyhow::{anyhow, Error};
|
||||||
use bitflags::bitflags;
|
use bitflags::bitflags;
|
||||||
|
use serde::de::{self, Deserialize, Deserializer};
|
||||||
use std::{
|
use std::{
|
||||||
cmp::{max, min},
|
cmp::{max, min},
|
||||||
str::FromStr,
|
str::FromStr,
|
||||||
@ -17,6 +19,36 @@ pub enum CursorKind {
|
|||||||
Hidden,
|
Hidden,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Default for CursorKind {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::Block
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for CursorKind {
|
||||||
|
type Err = Error;
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
match s {
|
||||||
|
"bar" => Ok(Self::Bar),
|
||||||
|
"block" => Ok(Self::Block),
|
||||||
|
"underline" => Ok(Self::Underline),
|
||||||
|
_ => Err(anyhow!("Invalid cursor '{}'", s)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// toml deserializer doesn't seem to recognize string as enum
|
||||||
|
impl<'de> Deserialize<'de> for CursorKind {
|
||||||
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
let s = String::deserialize(deserializer)?;
|
||||||
|
s.parse().map_err(de::Error::custom)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
pub struct Margin {
|
pub struct Margin {
|
||||||
pub vertical: u16,
|
pub vertical: u16,
|
||||||
|
Loading…
Reference in New Issue
Block a user