Detailed changes
@@ -228,7 +228,12 @@
// Whether to show code action button at start of buffer line.
"inline_code_actions": true,
// Whether to allow drag and drop text selection in buffer.
- "drag_and_drop_selection": true,
+ "drag_and_drop_selection": {
+ // When true, enables drag and drop text selection in buffer.
+ "enabled": true,
+ // The delay in milliseconds that must elapse before drag and drop is allowed. Otherwise, a new text selection is created.
+ "delay": 300
+ },
// What to do when go to definition yields no results.
//
// 1. Do nothing: `none`
@@ -1170,7 +1170,6 @@ pub struct Editor {
pub change_list: ChangeList,
inline_value_cache: InlineValueCache,
selection_drag_state: SelectionDragState,
- drag_and_drop_selection_enabled: bool,
next_color_inlay_id: usize,
colors: Option<LspColorData>,
folding_newlines: Task<()>,
@@ -2202,7 +2201,6 @@ impl Editor {
change_list: ChangeList::new(),
mode,
selection_drag_state: SelectionDragState::None,
- drag_and_drop_selection_enabled: EditorSettings::get_global(cx).drag_and_drop_selection,
folding_newlines: Task::ready(()),
};
if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
@@ -19899,7 +19897,6 @@ impl Editor {
self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
- self.drag_and_drop_selection_enabled = editor_settings.drag_and_drop_selection;
}
if old_cursor_shape != self.cursor_shape {
@@ -52,7 +52,7 @@ pub struct EditorSettings {
#[serde(default)]
pub diagnostics_max_severity: Option<DiagnosticSeverity>,
pub inline_code_actions: bool,
- pub drag_and_drop_selection: bool,
+ pub drag_and_drop_selection: DragAndDropSelection,
pub lsp_document_colors: DocumentColorsRenderMode,
}
@@ -275,6 +275,26 @@ pub struct ScrollbarAxes {
pub vertical: bool,
}
+/// Whether to allow drag and drop text selection in buffer.
+#[derive(Copy, Clone, Default, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
+pub struct DragAndDropSelection {
+ /// When true, enables drag and drop text selection in buffer.
+ ///
+ /// Default: true
+ #[serde(default = "default_true")]
+ pub enabled: bool,
+
+ /// The delay in milliseconds that must elapse before drag and drop is allowed. Otherwise, a new text selection is created.
+ ///
+ /// Default: 300
+ #[serde(default = "default_drag_and_drop_selection_delay_ms")]
+ pub delay: u64,
+}
+
+fn default_drag_and_drop_selection_delay_ms() -> u64 {
+ 300
+}
+
/// Which diagnostic indicators to show in the scrollbar.
///
/// Default: all
@@ -536,10 +556,8 @@ pub struct EditorSettingsContent {
/// Default: true
pub inline_code_actions: Option<bool>,
- /// Whether to allow drag and drop text selection in buffer.
- ///
- /// Default: true
- pub drag_and_drop_selection: Option<bool>,
+ /// Drag and drop related settings
+ pub drag_and_drop_selection: Option<DragAndDropSelection>,
/// How to render LSP `textDocument/documentColor` colors in the editor.
///
@@ -87,7 +87,6 @@ use util::{RangeExt, ResultExt, debug_panic};
use workspace::{CollaboratorId, Workspace, item::Item, notifications::NotifyTaskExt};
const INLINE_BLAME_PADDING_EM_WIDTHS: f32 = 7.;
-const SELECTION_DRAG_DELAY: Duration = Duration::from_millis(300);
/// Determines what kinds of highlights should be applied to a lines background.
#[derive(Clone, Copy, Default)]
@@ -644,7 +643,11 @@ impl EditorElement {
return;
}
- if editor.drag_and_drop_selection_enabled && click_count == 1 {
+ if EditorSettings::get_global(cx)
+ .drag_and_drop_selection
+ .enabled
+ && click_count == 1
+ {
let newest_anchor = editor.selections.newest_anchor();
let snapshot = editor.snapshot(window, cx);
let selection = newest_anchor.map(|anchor| anchor.to_display_point(&snapshot));
@@ -1022,7 +1025,10 @@ impl EditorElement {
ref click_position,
ref mouse_down_time,
} => {
- if mouse_down_time.elapsed() >= SELECTION_DRAG_DELAY {
+ let drag_and_drop_delay = Duration::from_millis(
+ EditorSettings::get_global(cx).drag_and_drop_selection.delay,
+ );
+ if mouse_down_time.elapsed() >= drag_and_drop_delay {
let drop_cursor = Selection {
id: post_inc(&mut editor.selections.next_selection_id),
start: drop_anchor,
@@ -5710,6 +5716,19 @@ impl EditorElement {
let editor = self.editor.read(cx);
if editor.mouse_cursor_hidden {
window.set_window_cursor_style(CursorStyle::None);
+ } else if let SelectionDragState::ReadyToDrag {
+ mouse_down_time, ..
+ } = &editor.selection_drag_state
+ {
+ let drag_and_drop_delay = Duration::from_millis(
+ EditorSettings::get_global(cx).drag_and_drop_selection.delay,
+ );
+ if mouse_down_time.elapsed() >= drag_and_drop_delay {
+ window.set_cursor_style(
+ CursorStyle::DragCopy,
+ &layout.position_map.text_hitbox,
+ );
+ }
} else if matches!(
editor.selection_drag_state,
SelectionDragState::Dragging { .. }
@@ -93,3 +93,9 @@ pub(crate) mod m_2025_06_27 {
pub(crate) use settings::SETTINGS_PATTERNS;
}
+
+pub(crate) mod m_2025_07_08 {
+ mod settings;
+
+ pub(crate) use settings::SETTINGS_PATTERNS;
+}
@@ -0,0 +1,37 @@
+use std::ops::Range;
+use tree_sitter::{Query, QueryMatch};
+
+use crate::MigrationPatterns;
+use crate::patterns::SETTINGS_ROOT_KEY_VALUE_PATTERN;
+
+pub const SETTINGS_PATTERNS: MigrationPatterns = &[(
+ SETTINGS_ROOT_KEY_VALUE_PATTERN,
+ migrate_drag_and_drop_selection,
+)];
+
+fn migrate_drag_and_drop_selection(
+ contents: &str,
+ mat: &QueryMatch,
+ query: &Query,
+) -> Option<(Range<usize>, String)> {
+ let name_ix = query.capture_index_for_name("name")?;
+ let name_range = mat.nodes_for_capture_index(name_ix).next()?.byte_range();
+ let name = contents.get(name_range)?;
+
+ if name != "drag_and_drop_selection" {
+ return None;
+ }
+
+ let value_ix = query.capture_index_for_name("value")?;
+ let value_node = mat.nodes_for_capture_index(value_ix).next()?;
+ let value_range = value_node.byte_range();
+ let value = contents.get(value_range.clone())?;
+
+ match value {
+ "true" | "false" => {
+ let replacement = format!("{{\n \"enabled\": {}\n }}", value);
+ Some((value_range, replacement))
+ }
+ _ => None,
+ }
+}
@@ -160,6 +160,10 @@ pub fn migrate_settings(text: &str) -> Result<Option<String>> {
migrations::m_2025_06_27::SETTINGS_PATTERNS,
&SETTINGS_QUERY_2025_06_27,
),
+ (
+ migrations::m_2025_07_08::SETTINGS_PATTERNS,
+ &SETTINGS_QUERY_2025_07_08,
+ ),
];
run_migrations(text, migrations)
}
@@ -270,6 +274,10 @@ define_query!(
SETTINGS_QUERY_2025_06_27,
migrations::m_2025_06_27::SETTINGS_PATTERNS
);
+define_query!(
+ SETTINGS_QUERY_2025_07_08,
+ migrations::m_2025_07_08::SETTINGS_PATTERNS
+);
// custom query
static EDIT_PREDICTION_SETTINGS_MIGRATION_QUERY: LazyLock<Query> = LazyLock::new(|| {
@@ -1218,13 +1218,16 @@ or
### Drag And Drop Selection
-- Description: Whether to allow drag and drop text selection in buffer.
+- Description: Whether to allow drag and drop text selection in buffer. `delay` is the milliseconds that must elapse before drag and drop is allowed. Otherwise, a new text selection is created.
- Setting: `drag_and_drop_selection`
-- Default: `true`
-
-**Options**
+- Default:
-`boolean` values
+```json
+"drag_and_drop_selection": {
+ "enabled": true,
+ "delay": 300
+}
+```
## Editor Toolbar