Detailed changes
@@ -648,11 +648,19 @@
// Show git status colors in the editor tabs.
"git_status": false,
// Position of the close button on the editor tabs.
+ // One of: ["right", "left", "hidden"]
"close_position": "right",
// Whether to show the file icon for a tab.
"file_icons": false,
- // Whether to always show the close button on tabs.
- "always_show_close_button": false,
+ // Controls the appearance behavior of the tab's close button.
+ //
+ // 1. Show it just upon hovering the tab. (default)
+ // "hover"
+ // 2. Show it persistently.
+ // "always"
+ // 3. Never show it, even if hovering it.
+ // "hidden"
+ "show_close_button": "hover",
// What to do after closing the current tab.
//
// 1. Activate the tab that was open previously (default)
@@ -72,7 +72,7 @@ pub fn migrate_edit_prediction_provider_settings(text: &str) -> Result<Option<St
migrate(
&text,
&[(
- SETTINGS_REPLACE_NESTED_KEY,
+ SETTINGS_NESTED_KEY_VALUE_PATTERN,
replace_edit_prediction_provider_setting,
)],
&EDIT_PREDICTION_SETTINGS_MIGRATION_QUERY,
@@ -571,9 +571,17 @@ pub static ACTION_ARGUMENT_SNAKE_CASE_REPLACE: LazyLock<HashMap<&str, &str>> =
const SETTINGS_MIGRATION_PATTERNS: MigrationPatterns = &[
(SETTINGS_STRING_REPLACE_QUERY, replace_setting_name),
(
- SETTINGS_REPLACE_NESTED_KEY,
+ SETTINGS_NESTED_KEY_VALUE_PATTERN,
replace_edit_prediction_provider_setting,
),
+ (
+ SETTINGS_NESTED_KEY_VALUE_PATTERN,
+ replace_tab_close_button_setting_key,
+ ),
+ (
+ SETTINGS_NESTED_KEY_VALUE_PATTERN,
+ replace_tab_close_button_setting_value,
+ ),
(
SETTINGS_REPLACE_IN_LANGUAGES_QUERY,
replace_setting_in_languages,
@@ -594,7 +602,7 @@ static SETTINGS_MIGRATION_QUERY: LazyLock<Query> = LazyLock::new(|| {
static EDIT_PREDICTION_SETTINGS_MIGRATION_QUERY: LazyLock<Query> = LazyLock::new(|| {
Query::new(
&tree_sitter_json::LANGUAGE.into(),
- SETTINGS_REPLACE_NESTED_KEY,
+ SETTINGS_NESTED_KEY_VALUE_PATTERN,
)
.unwrap()
});
@@ -639,14 +647,14 @@ pub static SETTINGS_STRING_REPLACE: LazyLock<HashMap<&'static str, &'static str>
])
});
-const SETTINGS_REPLACE_NESTED_KEY: &str = r#"
+const SETTINGS_NESTED_KEY_VALUE_PATTERN: &str = r#"
(object
(pair
key: (string (string_content) @parent_key)
value: (object
(pair
key: (string (string_content) @setting_name)
- value: (_) @value
+ value: (_) @setting_value
)
)
)
@@ -679,6 +687,73 @@ fn replace_edit_prediction_provider_setting(
None
}
+fn replace_tab_close_button_setting_key(
+ contents: &str,
+ mat: &QueryMatch,
+ query: &Query,
+) -> Option<(Range<usize>, String)> {
+ let parent_object_capture_ix = query.capture_index_for_name("parent_key")?;
+ let parent_object_range = mat
+ .nodes_for_capture_index(parent_object_capture_ix)
+ .next()?
+ .byte_range();
+ let parent_object_name = contents.get(parent_object_range.clone())?;
+
+ let setting_name_ix = query.capture_index_for_name("setting_name")?;
+ let setting_range = mat
+ .nodes_for_capture_index(setting_name_ix)
+ .next()?
+ .byte_range();
+ let setting_name = contents.get(setting_range.clone())?;
+
+ if parent_object_name == "tabs" && setting_name == "always_show_close_button" {
+ return Some((setting_range, "show_close_button".into()));
+ }
+
+ None
+}
+
+fn replace_tab_close_button_setting_value(
+ contents: &str,
+ mat: &QueryMatch,
+ query: &Query,
+) -> Option<(Range<usize>, String)> {
+ let parent_object_capture_ix = query.capture_index_for_name("parent_key")?;
+ let parent_object_range = mat
+ .nodes_for_capture_index(parent_object_capture_ix)
+ .next()?
+ .byte_range();
+ let parent_object_name = contents.get(parent_object_range.clone())?;
+
+ let setting_name_ix = query.capture_index_for_name("setting_name")?;
+ let setting_name_range = mat
+ .nodes_for_capture_index(setting_name_ix)
+ .next()?
+ .byte_range();
+ let setting_name = contents.get(setting_name_range.clone())?;
+
+ let setting_value_ix = query.capture_index_for_name("setting_value")?;
+ let setting_value_range = mat
+ .nodes_for_capture_index(setting_value_ix)
+ .next()?
+ .byte_range();
+ let setting_value = contents.get(setting_value_range.clone())?;
+
+ if parent_object_name == "tabs" && setting_name == "always_show_close_button" {
+ match setting_value {
+ "true" => {
+ return Some((setting_value_range, "\"always\"".to_string()));
+ }
+ "false" => {
+ return Some((setting_value_range, "\"hover\"".to_string()));
+ }
+ _ => {}
+ }
+ }
+
+ None
+}
+
const SETTINGS_REPLACE_IN_LANGUAGES_QUERY: &str = r#"
(object
(pair
@@ -42,7 +42,7 @@ pub struct ItemSettings {
pub activate_on_close: ActivateOnClose,
pub file_icons: bool,
pub show_diagnostics: ShowDiagnostics,
- pub always_show_close_button: bool,
+ pub show_close_button: ShowCloseButton,
}
#[derive(Deserialize)]
@@ -60,6 +60,15 @@ pub enum ClosePosition {
Right,
}
+#[derive(Clone, Default, Serialize, Deserialize, JsonSchema)]
+#[serde(rename_all = "lowercase")]
+pub enum ShowCloseButton {
+ Always,
+ #[default]
+ Hover,
+ Hidden,
+}
+
#[derive(Copy, Clone, Debug, Default, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum ShowDiagnostics {
@@ -104,7 +113,7 @@ pub struct ItemSettingsContent {
/// Whether to always show the close button on tabs.
///
/// Default: false
- always_show_close_button: Option<bool>,
+ show_close_button: Option<ShowCloseButton>,
}
#[derive(Clone, Default, Serialize, Deserialize, JsonSchema)]
@@ -1,7 +1,7 @@
use crate::{
item::{
ActivateOnClose, ClosePosition, Item, ItemHandle, ItemSettings, PreviewTabsSettings,
- ShowDiagnostics, TabContentParams, TabTooltipContent, WeakItemHandle,
+ ShowCloseButton, ShowDiagnostics, TabContentParams, TabTooltipContent, WeakItemHandle,
},
move_item,
notifications::NotifyResultExt,
@@ -2269,7 +2269,7 @@ impl Pane {
let settings = ItemSettings::get_global(cx);
let close_side = &settings.close_position;
- let always_show_close_button = settings.always_show_close_button;
+ let show_close_button = &settings.show_close_button;
let indicator = render_item_indicator(item.boxed_clone(), cx);
let item_id = item.item_id();
let is_first_item = ix == 0;
@@ -2373,18 +2373,21 @@ impl Pane {
close_pinned: false,
};
end_slot_tooltip_text = "Close Tab";
- IconButton::new("close tab", IconName::Close)
- .when(!always_show_close_button, |button| {
- button.visible_on_hover("")
- })
- .shape(IconButtonShape::Square)
- .icon_color(Color::Muted)
- .size(ButtonSize::None)
- .icon_size(IconSize::XSmall)
- .on_click(cx.listener(move |pane, _, window, cx| {
- pane.close_item_by_id(item_id, SaveIntent::Close, window, cx)
- .detach_and_log_err(cx);
- }))
+ match show_close_button {
+ ShowCloseButton::Always => IconButton::new("close tab", IconName::Close),
+ ShowCloseButton::Hover => {
+ IconButton::new("close tab", IconName::Close).visible_on_hover("")
+ }
+ ShowCloseButton::Hidden => return this,
+ }
+ .shape(IconButtonShape::Square)
+ .icon_color(Color::Muted)
+ .size(ButtonSize::None)
+ .icon_size(IconSize::XSmall)
+ .on_click(cx.listener(move |pane, _, window, cx| {
+ pane.close_item_by_id(item_id, SaveIntent::Close, window, cx)
+ .detach_and_log_err(cx);
+ }))
}
.map(|this| {
if is_active {
@@ -784,7 +784,7 @@ List of `string` values
"file_icons": false,
"git_status": false,
"activate_on_close": "history",
- "always_show_close_button": false
+ "show_close_button": "hover"
},
```
@@ -856,11 +856,37 @@ List of `string` values
}
```
-### Always show the close button
+### Show close button
-- Description: Whether to always show the close button on tabs.
-- Setting: `always_show_close_button`
-- Default: `false`
+- Description: Controls the appearance behavior of the tab's close button.
+- Setting: `show_close_button`
+- Default: `hover`
+
+**Options**
+
+1. Show it just upon hovering the tab:
+
+```json
+{
+ "show_close_button": "hover"
+}
+```
+
+2. Show it persistently:
+
+```json
+{
+ "show_close_button": "always"
+}
+```
+
+3. Never show it, even if hovering it:
+
+```json
+{
+ "show_close_button": "hidden"
+}
+```
## Editor Toolbar