From d17c6b392ec3b89cbaffdf83a890587c99e6b32d Mon Sep 17 00:00:00 2001 From: Marshall Bowers Date: Wed, 19 Feb 2025 11:37:39 -0500 Subject: [PATCH] Add `allow_rewrap` setting to control `editor::Rewrap` behavior for a given language (#25173) This PR adds a new `allow_rewrap` setting to control how `editor::Rewrap` behaves for a given language. This is a language setting, so it can either be configured globally or within the context of an individual language. For example: ```json { "allow_rewrap": "in_selections", "languages": { "Typst": { "allow_rewrap": "anywhere" } } } ``` There are three different values: - `in_comment`: Only perform rewrapping within comments. - `in_selections`: Only perform rewrapping within the current selection(s). - `anywhere`: Allow rewrapping anywhere. The global default is `in_comment`, as it is the most conservative option and allows rewrapping comments without risking breaking other syntax. The `Markdown` and `Plain Text` languages default to `anywhere`, which mirrors the previous behavior for those language that was hard-coded into the rewrap implementation. This setting does not have any effect in Vim mode, as Vim mode already allowed rewrapping anywhere. Closes https://github.com/zed-industries/zed/issues/24242. Release Notes: - Added an `allow_rewrap` setting to control the `editor::Rewrap` behavior for a given language. --- assets/settings/default.json | 21 ++++++++++++++++++ crates/editor/src/editor.rs | 26 +++++++++++------------ crates/editor/src/editor_tests.rs | 19 ++++++++++++++++- crates/language/src/language_settings.rs | 27 ++++++++++++++++++++++++ 4 files changed, 79 insertions(+), 14 deletions(-) diff --git a/assets/settings/default.json b/assets/settings/default.json index a3a592a59b..d87ddf49e0 100644 --- a/assets/settings/default.json +++ b/assets/settings/default.json @@ -204,6 +204,23 @@ // Otherwise(when `true`), the closing characters are always skipped over and auto-removed // no matter how they were inserted. "always_treat_brackets_as_autoclosed": false, + // Controls where the `editor::Rewrap` action is allowed in the current language scope. + // + // This setting can take three values: + // + // 1. Only allow rewrapping in comments: + // "in_comments" + // 2. Only allow rewrapping in the current selection(s): + // "in_selections" + // 3. Allow rewrapping anywhere: + // "anywhere" + // + // When using values other than `in_comments`, it is possible for the rewrapping to produce code + // that is syntactically invalid. Keep this in mind when selecting which behavior you would like + // to use. + // + // Note: This setting has no effect in Vim mode, as rewrap is already allowed everywhere. + "allow_rewrap": "in_comments", // Controls whether edit predictions are shown immediately (true) // or manually by triggering `editor::ShowEditPrediction` (false). "show_edit_predictions": true, @@ -1103,6 +1120,7 @@ "Markdown": { "format_on_save": "off", "use_on_type_format": false, + "allow_rewrap": "anywhere", "prettier": { "allowed": true } @@ -1115,6 +1133,9 @@ "parser": "php" } }, + "Plain Text": { + "allow_rewrap": "anywhere" + }, "Ruby": { "language_servers": ["solargraph", "!ruby-lsp", "!rubocop", "..."] }, diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index aaa49a1390..424aefb5bb 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -97,7 +97,9 @@ use inline_completion::{EditPredictionProvider, InlineCompletionProviderHandle}; pub use items::MAX_TAB_TITLE_LEN; use itertools::Itertools; use language::{ - language_settings::{self, all_language_settings, language_settings, InlayHintSettings}, + language_settings::{ + self, all_language_settings, language_settings, InlayHintSettings, RewrapBehavior, + }, point_from_lsp, AutoindentMode, BracketPair, Buffer, Capability, CharKind, CodeLabel, CursorShape, Diagnostic, DiskState, EditPredictionsMode, EditPreview, HighlightedText, IndentKind, IndentSize, Language, OffsetRangeExt, Point, Selection, SelectionGoal, TextObject, @@ -7744,17 +7746,6 @@ impl Editor { continue; } - let mut should_rewrap = is_vim_mode == IsVimMode::Yes; - - if let Some(language_scope) = buffer.language_scope_at(selection.head()) { - match language_scope.language_name().as_ref() { - "Markdown" | "Plain Text" => { - should_rewrap = true; - } - _ => {} - } - } - let tab_size = buffer.settings_at(selection.head(), cx).tab_size; // Since not all lines in the selection may be at the same indent @@ -7785,6 +7776,7 @@ impl Editor { let mut line_prefix = indent_size.chars().collect::(); + let mut inside_comment = false; if let Some(comment_prefix) = buffer .language_scope_at(selection.head()) @@ -7797,9 +7789,17 @@ impl Editor { }) { line_prefix.push_str(&comment_prefix); - should_rewrap = true; + inside_comment = true; } + let language_settings = buffer.settings_at(selection.head(), cx); + let allow_rewrap_based_on_language = match language_settings.allow_rewrap { + RewrapBehavior::InComments => inside_comment, + RewrapBehavior::InSelections => !selection.is_empty(), + RewrapBehavior::Anywhere => true, + }; + + let should_rewrap = is_vim_mode == IsVimMode::Yes || allow_rewrap_based_on_language; if !should_rewrap { continue; } diff --git a/crates/editor/src/editor_tests.rs b/crates/editor/src/editor_tests.rs index 0f85e81a70..90897e0c0a 100644 --- a/crates/editor/src/editor_tests.rs +++ b/crates/editor/src/editor_tests.rs @@ -4321,7 +4321,24 @@ fn test_transpose(cx: &mut TestAppContext) { #[gpui::test] async fn test_rewrap(cx: &mut TestAppContext) { - init_test(cx, |_| {}); + init_test(cx, |settings| { + settings.languages.extend([ + ( + "Markdown".into(), + LanguageSettingsContent { + allow_rewrap: Some(language_settings::RewrapBehavior::Anywhere), + ..Default::default() + }, + ), + ( + "Plain Text".into(), + LanguageSettingsContent { + allow_rewrap: Some(language_settings::RewrapBehavior::Anywhere), + ..Default::default() + }, + ), + ]) + }); let mut cx = EditorTestContext::new(cx).await; diff --git a/crates/language/src/language_settings.rs b/crates/language/src/language_settings.rs index ac6f04f4b6..c038458977 100644 --- a/crates/language/src/language_settings.rs +++ b/crates/language/src/language_settings.rs @@ -109,6 +109,11 @@ pub struct LanguageSettings { /// - `"!"` - A language server ID prefixed with a `!` will be disabled. /// - `"..."` - A placeholder to refer to the **rest** of the registered language servers for this language. pub language_servers: Vec, + /// Controls where the `editor::Rewrap` action is allowed for this language. + /// + /// Note: This setting has no effect in Vim mode, as rewrap is already + /// allowed everywhere. + pub allow_rewrap: RewrapBehavior, /// Controls whether edit predictions are shown immediately (true) /// or manually by triggering `editor::ShowEditPrediction` (false). pub show_edit_predictions: bool, @@ -349,6 +354,14 @@ pub struct LanguageSettingsContent { /// Default: ["..."] #[serde(default)] pub language_servers: Option>, + /// Controls where the `editor::Rewrap` action is allowed for this language. + /// + /// Note: This setting has no effect in Vim mode, as rewrap is already + /// allowed everywhere. + /// + /// Default: "in_comments" + #[serde(default)] + pub allow_rewrap: Option, /// Controls whether edit predictions are shown immediately (true) /// or manually by triggering `editor::ShowEditPrediction` (false). /// @@ -427,6 +440,19 @@ pub struct LanguageSettingsContent { pub show_completion_documentation: Option, } +/// The behavior of `editor::Rewrap`. +#[derive(Debug, PartialEq, Clone, Copy, Default, Serialize, Deserialize, JsonSchema)] +#[serde(rename_all = "snake_case")] +pub enum RewrapBehavior { + /// Only rewrap within comments. + #[default] + InComments, + /// Only rewrap within the current selection(s). + InSelections, + /// Allow rewrapping anywhere. + Anywhere, +} + /// The contents of the edit prediction settings. #[derive(Clone, Debug, Default, Serialize, Deserialize, JsonSchema, PartialEq)] pub struct EditPredictionSettingsContent { @@ -1224,6 +1250,7 @@ fn merge_settings(settings: &mut LanguageSettings, src: &LanguageSettingsContent src.enable_language_server, ); merge(&mut settings.language_servers, src.language_servers.clone()); + merge(&mut settings.allow_rewrap, src.allow_rewrap); merge( &mut settings.show_edit_predictions, src.show_edit_predictions,