Add `cursor_shape` setting for the default editor (#17572)

thataboy created

Closes https://github.com/zed-industries/zed/issues/16451,
https://github.com/zed-industries/zed/issues/14447,
https://github.com/zed-industries/zed/issues/7203

Addresses but does not closes
https://github.com/zed-industries/zed/issues/5179

Expose cursor shape selection to users. Possibly controversial, since
block cursor seems preserved for vim and terminal. But the heart wants
what it wants?

Release Notes:

- Added a setting for `cursor_shape`. Can be `bar`, `block`,
`underline`, or `hollow`. Default is `bar`.

Change summary

assets/settings/default.json         | 12 +++++++++++
crates/editor/src/editor.rs          |  3 +
crates/editor/src/editor_settings.rs |  7 ++++++
crates/language/src/buffer.rs        |  5 +++
docs/src/configuring-zed.md          | 32 ++++++++++++++++++++++++++++++
5 files changed, 57 insertions(+), 2 deletions(-)

Detailed changes

assets/settings/default.json 🔗

@@ -111,6 +111,18 @@
   "use_system_path_prompts": true,
   // Whether the cursor blinks in the editor.
   "cursor_blink": true,
+  // Cursor shape for the default editor.
+  //  1. A vertical bar
+  //     "bar"
+  //  2. A block that surrounds the following character
+  //     "block"
+  //  3. An underline that runs along the following character
+  //     "underscore"
+  //  4. A box drawn around the following character
+  //     "hollow"
+  //
+  // Default: bar
+  "cursor_shape": "bar",
   // How to highlight the current line in the editor.
   //
   // 1. Don't highlight the current line:

crates/editor/src/editor.rs 🔗

@@ -1904,7 +1904,7 @@ impl Editor {
             linked_editing_range_task: Default::default(),
             pending_rename: Default::default(),
             searchable: true,
-            cursor_shape: Default::default(),
+            cursor_shape: EditorSettings::get_global(cx).cursor_shape,
             current_line_highlight: None,
             autoindent_mode: Some(AutoindentMode::EachLine),
             collapse_matches: false,
@@ -11820,6 +11820,7 @@ impl Editor {
             cx,
         );
         let editor_settings = EditorSettings::get_global(cx);
+        self.cursor_shape = editor_settings.cursor_shape;
         self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
         self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
 

crates/editor/src/editor_settings.rs 🔗

@@ -1,4 +1,5 @@
 use gpui::AppContext;
+use language::CursorShape;
 use schemars::JsonSchema;
 use serde::{Deserialize, Serialize};
 use settings::{Settings, SettingsSources};
@@ -6,6 +7,7 @@ use settings::{Settings, SettingsSources};
 #[derive(Deserialize, Clone)]
 pub struct EditorSettings {
     pub cursor_blink: bool,
+    pub cursor_shape: CursorShape,
     pub current_line_highlight: CurrentLineHighlight,
     pub hover_popover_enabled: bool,
     pub show_completions_on_input: bool,
@@ -177,6 +179,11 @@ pub struct EditorSettingsContent {
     ///
     /// Default: true
     pub cursor_blink: Option<bool>,
+    /// Cursor shape for the default editor.
+    /// Can be "bar", "block", "underscore", or "hollow".
+    ///
+    /// Default: bar
+    pub cursor_shape: Option<CursorShape>,
     /// How to highlight the current line in the editor.
     ///
     /// Default: all

crates/language/src/buffer.rs 🔗

@@ -26,6 +26,8 @@ use gpui::{
 };
 use lsp::LanguageServerId;
 use parking_lot::Mutex;
+use schemars::JsonSchema;
+use serde::{Deserialize, Serialize};
 use serde_json::Value;
 use settings::WorktreeId;
 use similar::{ChangeTag, TextDiff};
@@ -161,7 +163,8 @@ pub enum IndentKind {
 }
 
 /// The shape of a selection cursor.
-#[derive(Copy, Clone, PartialEq, Eq, Debug, Default)]
+#[derive(Copy, Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
+#[serde(rename_all = "snake_case")]
 pub enum CursorShape {
     /// A vertical bar
     #[default]

docs/src/configuring-zed.md 🔗

@@ -293,6 +293,38 @@ List of `string` values
 
 `boolean` values
 
+## Cursor Shape
+
+- Description: Cursor shape for the default editor.
+- Setting: `cursor_shape`
+- Default: `bar`
+
+**Options**
+
+1. A vertical bar:
+
+```json
+"cursor_shape": "bar"
+```
+
+2. A block that surrounds the following character:
+
+```json
+"cursor_shape": "block"
+```
+
+3. An underline that runs along the following character:
+
+```json
+"cursor_shape": "underline"
+```
+
+4. An box drawn around the following character:
+
+```json
+"cursor_shape": "hollow"
+```
+
 ## Default Dock Anchor
 
 - Description: The default anchor for new docks.