Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Change cursor shape on mode change #1154

Merged
merged 8 commits into from
Jan 23, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 40 additions & 2 deletions book/src/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,26 @@ To override global configuration parameters, create a `config.toml` file located
* Linux and Mac: `~/.config/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]` section of the config.
### `[editor]` Section

| Key | Description | Default |
|--|--|---------|
Expand All @@ -24,7 +41,28 @@ To override global configuration parameters, create a `config.toml` file located
| `completion-trigger-len` | The min-length of word under cursor to trigger autocompletion | `2` |
| `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 |
|--|--|---------|
Expand Down
12 changes: 9 additions & 3 deletions helix-term/src/ui/editor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,9 @@ impl EditorView {

// Special-case: cursor at end of the rope.
if range.head == range.anchor && range.head == text.len_chars() {
spans.push((cursor_scope, range.head..range.head + 1));
if i != primary_idx {
sudormrfbin marked this conversation as resolved.
Show resolved Hide resolved
spans.push((cursor_scope, range.head..range.head + 1));
}
continue;
}

Expand All @@ -259,11 +261,15 @@ impl EditorView {
// Standard case.
let cursor_start = prev_grapheme_boundary(text, range.head);
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));
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Previously the terminal cursor was hidden and we drew our own primary cursor. Now we use the terminal cursor as the primary cursor and hence ui.cursor.primary is no longer used to style it. Is there any way to use it to style the cursor ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you please add a comment for these?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was looking for a way to style the terminal cursor so that we can still use ui.cursor.primary; it's possible to do so and vim allows it: #323 (comment).

} else {
// Reverse case.
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));
}
}
Expand Down
42 changes: 36 additions & 6 deletions helix-view/src/editor.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::{
clipboard::{get_clipboard_provider, ClipboardProvider},
document::SCRATCH_BUFFER_NAME,
document::{Mode, SCRATCH_BUFFER_NAME},
graphics::{CursorKind, Rect},
theme::{self, Theme},
tree::{self, Tree},
Expand All @@ -9,7 +9,7 @@ use crate::{

use futures_util::future;
use std::{
collections::BTreeMap,
collections::{BTreeMap, HashMap},
io::stdin,
path::{Path, PathBuf},
pin::Pin,
Expand All @@ -22,7 +22,7 @@ use anyhow::Error;

pub use helix_core::diagnostic::Severity;
pub use helix_core::register::Registers;
use helix_core::syntax;
use helix_core::{hashmap, syntax};
use helix_core::{Position, Selection};

use serde::Deserialize;
Expand Down Expand Up @@ -103,14 +103,37 @@ pub struct Config {
/// Whether to display infoboxes. Defaults to true.
pub auto_info: bool,
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)]
#[serde(rename_all = "kebab-case")]
pub enum LineNumber {
/// Show absolute line number
Absolute,

/// Show relative line number to the primary cursor
Relative,
}
Expand All @@ -135,6 +158,7 @@ impl Default for Config {
completion_trigger_len: 2,
auto_info: true,
file_picker: FilePickerConfig::default(),
cursor_shape: CursorShapeConfig::default(),
}
}
}
Expand Down Expand Up @@ -594,9 +618,15 @@ impl Editor {
let inner = view.inner_area();
pos.col += inner.x 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 {
(None, CursorKind::Hidden)
(None, CursorKind::default())
}
}

Expand Down
32 changes: 32 additions & 0 deletions helix-view/src/graphics.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
use anyhow::{anyhow, Error};
use bitflags::bitflags;
use serde::de::{self, Deserialize, Deserializer};
use std::{
cmp::{max, min},
str::FromStr,
Expand All @@ -17,6 +19,36 @@ pub enum CursorKind {
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)
}
}
sudormrfbin marked this conversation as resolved.
Show resolved Hide resolved

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Margin {
pub vertical: u16,
Expand Down