From dfc7c815000b3dfd0cf6b25254ab9f87009abb6c Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Thu, 2 Nov 2023 21:03:29 -0600 Subject: [PATCH] WIP --- Cargo.lock | 2 +- crates/editor2/src/display_map.rs | 5 +- crates/editor2/src/display_map/wrap_map.rs | 2 +- crates/editor2/src/editor.rs | 14686 ++++++++-------- crates/editor2/src/items.rs | 227 +- crates/editor2/src/movement.rs | 880 +- crates/editor2/src/scroll.rs | 28 +- crates/editor2/src/scroll/autoscroll.rs | 17 +- .../src/test/editor_lsp_test_context.rs | 526 +- .../editor2/src/test/editor_test_context.rs | 24 +- crates/gpui2/src/geometry.rs | 4 + crates/workspace2/src/item.rs | 2 +- 12 files changed, 8192 insertions(+), 8211 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ffd69fb1df..bd4fca5fa5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2648,7 +2648,7 @@ dependencies = [ "lazy_static", "log", "lsp2", - "multi_buffer", + "multi_buffer2", "ordered-float 2.10.0", "parking_lot 0.11.2", "postage", diff --git a/crates/editor2/src/display_map.rs b/crates/editor2/src/display_map.rs index ab137df74f..94391f7cb5 100644 --- a/crates/editor2/src/display_map.rs +++ b/crates/editor2/src/display_map.rs @@ -6,17 +6,16 @@ mod wrap_map; use crate::{ link_go_to_definition::InlayHighlight, movement::TextLayoutDetails, Anchor, AnchorRangeExt, - EditorStyle, InlayId, MultiBuffer, MultiBufferSnapshot, ToOffset, ToPoint, + InlayId, MultiBuffer, MultiBufferSnapshot, ToOffset, ToPoint, }; pub use block_map::{BlockMap, BlockPoint}; use collections::{BTreeMap, HashMap, HashSet}; use fold_map::FoldMap; -use gpui::{FontId, HighlightStyle, Hsla, Line, Model, ModelContext, UnderlineStyle}; +use gpui::{FontId, HighlightStyle, Hsla, Line, Model, ModelContext}; use inlay_map::InlayMap; use language::{ language_settings::language_settings, OffsetUtf16, Point, Subscription as BufferSubscription, }; -use lsp::DiagnosticSeverity; use std::{any::TypeId, borrow::Cow, fmt::Debug, num::NonZeroU32, ops::Range, sync::Arc}; use sum_tree::{Bias, TreeMap}; use tab_map::TabMap; diff --git a/crates/editor2/src/display_map/wrap_map.rs b/crates/editor2/src/display_map/wrap_map.rs index d6f321f616..06f06fb5c3 100644 --- a/crates/editor2/src/display_map/wrap_map.rs +++ b/crates/editor2/src/display_map/wrap_map.rs @@ -73,7 +73,7 @@ impl WrapMap { wrap_width: Option, cx: &mut AppContext, ) -> (Model, WrapSnapshot) { - let handle = cx.add_model(|cx| { + let handle = cx.build_model(|cx| { let mut this = Self { font: (font_id, font_size), wrap_width: None, diff --git a/crates/editor2/src/editor.rs b/crates/editor2/src/editor.rs index 0ae03661e8..ee552d3dbd 100644 --- a/crates/editor2/src/editor.rs +++ b/crates/editor2/src/editor.rs @@ -19,15 +19,11 @@ pub mod selections_collection; mod editor_tests; #[cfg(any(test, feature = "test-support"))] pub mod test; -use ::git::diff::DiffHunk; use aho_corasick::AhoCorasick; -use anyhow::{anyhow, Context, Result}; use blink_manager::BlinkManager; -use client::{ClickhouseEvent, Client, Collaborator, ParticipantIndex, TelemetrySettings}; -use clock::{Global, ReplicaId}; -use collections::{BTreeMap, Bound, HashMap, HashSet, VecDeque}; -use convert_case::{Case, Casing}; -use copilot::Copilot; +use client::{Collaborator, ParticipantIndex}; +use clock::ReplicaId; +use collections::{HashMap, HashSet, VecDeque}; pub use display_map::DisplayPoint; use display_map::*; pub use editor_settings::EditorSettings; @@ -37,43 +33,26 @@ pub use element::{ use futures::FutureExt; use fuzzy::{StringMatch, StringMatchCandidate}; use gpui::{ - serde_json, AnyElement, AppContext, AsyncAppContext, ClipboardItem, Element, Entity, - EventEmitter, FontWeight, HighlightStyle, Hsla, Model, Pixels, Quad, Render, Subscription, - Task, Text, View, ViewContext, WeakView, WindowContext, + AnyElement, AppContext, Element, EventEmitter, Model, Pixels, Render, Subscription, Task, View, + ViewContext, WeakView, }; -use highlight_matching_bracket::refresh_matching_bracket_highlights; -use hover_popover::{hide_hover, HoverState}; -use inlay_hint_cache::{InlayHintCache, InlaySplice, InvalidationStrategy}; +use hover_popover::HoverState; pub use items::MAX_TAB_TITLE_LEN; -use itertools::Itertools; pub use language::{char_kind, CharKind}; use language::{ language_settings::{self, all_language_settings, InlayHintSettings}, - point_from_lsp, AutoindentMode, BracketPair, Buffer, CodeAction, CodeLabel, Completion, - CursorShape, Diagnostic, DiagnosticSeverity, File, IndentKind, IndentSize, Language, - LanguageRegistry, LanguageServerName, OffsetRangeExt, OffsetUtf16, Point, Selection, - SelectionGoal, TransactionId, + AutoindentMode, BracketPair, Buffer, CodeAction, Completion, CursorShape, Diagnostic, Language, + OffsetRangeExt, Point, Selection, SelectionGoal, TransactionId, }; -use link_go_to_definition::{ - hide_link_definition, show_link_definition, GoToDefinitionLink, InlayHighlight, - LinkGoToDefinitionState, -}; -use log::error; -use lsp::LanguageServerId; -use movement::TextLayoutDetails; -use multi_buffer::ToOffsetUtf16; +use link_go_to_definition::LinkGoToDefinitionState; pub use multi_buffer::{ Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, ToOffset, ToPoint, }; -use ordered_float::OrderedFloat; use parking_lot::RwLock; -use project::{FormatTrigger, Location, Project, ProjectPath, ProjectTransaction}; -use rand::{seq::SliceRandom, thread_rng}; -use rpc::proto::{self, PeerId}; -use scroll::{ - autoscroll::Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager, ScrollbarAutoHide, -}; +use project::Project; +use rpc::proto::*; +use scroll::{autoscroll::Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager}; use selections_collection::SelectionsCollection; use serde::{Deserialize, Serialize}; use settings::Settings; @@ -1763,7350 +1742,7350 @@ impl InlayHintRefreshReason { } } -// impl Editor { -// pub fn single_line( -// field_editor_style: Option>, -// cx: &mut ViewContext, -// ) -> Self { -// let buffer = cx.add_model(|cx| Buffer::new(0, cx.model_id() as u64, String::new())); -// let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx)); -// Self::new(EditorMode::SingleLine, buffer, None, field_editor_style, cx) -// } +impl Editor { + // pub fn single_line( + // field_editor_style: Option>, + // cx: &mut ViewContext, + // ) -> Self { + // let buffer = cx.add_model(|cx| Buffer::new(0, cx.model_id() as u64, String::new())); + // let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx)); + // Self::new(EditorMode::SingleLine, buffer, None, field_editor_style, cx) + // } -// pub fn multi_line( -// field_editor_style: Option>, -// cx: &mut ViewContext, -// ) -> Self { -// let buffer = cx.add_model(|cx| Buffer::new(0, cx.model_id() as u64, String::new())); -// let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx)); -// Self::new(EditorMode::Full, buffer, None, field_editor_style, cx) -// } + // pub fn multi_line( + // field_editor_style: Option>, + // cx: &mut ViewContext, + // ) -> Self { + // let buffer = cx.add_model(|cx| Buffer::new(0, cx.model_id() as u64, String::new())); + // let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx)); + // Self::new(EditorMode::Full, buffer, None, field_editor_style, cx) + // } -// pub fn auto_height( -// max_lines: usize, -// field_editor_style: Option>, -// cx: &mut ViewContext, -// ) -> Self { -// let buffer = cx.add_model(|cx| Buffer::new(0, cx.model_id() as u64, String::new())); -// let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx)); -// Self::new( -// EditorMode::AutoHeight { max_lines }, -// buffer, -// None, -// field_editor_style, -// cx, -// ) -// } + // pub fn auto_height( + // max_lines: usize, + // field_editor_style: Option>, + // cx: &mut ViewContext, + // ) -> Self { + // let buffer = cx.add_model(|cx| Buffer::new(0, cx.model_id() as u64, String::new())); + // let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx)); + // Self::new( + // EditorMode::AutoHeight { max_lines }, + // buffer, + // None, + // field_editor_style, + // cx, + // ) + // } -// pub fn for_buffer( -// buffer: Model, -// project: Option>, -// cx: &mut ViewContext, -// ) -> Self { -// let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx)); -// Self::new(EditorMode::Full, buffer, project, None, cx) -// } + // pub fn for_buffer( + // buffer: Model, + // project: Option>, + // cx: &mut ViewContext, + // ) -> Self { + // let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx)); + // Self::new(EditorMode::Full, buffer, project, None, cx) + // } -// pub fn for_multibuffer( -// buffer: Model, -// project: Option>, -// cx: &mut ViewContext, -// ) -> Self { -// Self::new(EditorMode::Full, buffer, project, None, cx) -// } + // pub fn for_multibuffer( + // buffer: Model, + // project: Option>, + // cx: &mut ViewContext, + // ) -> Self { + // Self::new(EditorMode::Full, buffer, project, None, cx) + // } -// pub fn clone(&self, cx: &mut ViewContext) -> Self { -// let mut clone = Self::new( -// self.mode, -// self.buffer.clone(), -// self.project.clone(), -// self.get_field_editor_theme.clone(), -// cx, -// ); -// self.display_map.update(cx, |display_map, cx| { -// let snapshot = display_map.snapshot(cx); -// clone.display_map.update(cx, |display_map, cx| { -// display_map.set_state(&snapshot, cx); -// }); -// }); -// clone.selections.clone_state(&self.selections); -// clone.scroll_manager.clone_state(&self.scroll_manager); -// clone.searchable = self.searchable; -// clone -// } + // pub fn clone(&self, cx: &mut ViewContext) -> Self { + // let mut clone = Self::new( + // self.mode, + // self.buffer.clone(), + // self.project.clone(), + // self.get_field_editor_theme.clone(), + // cx, + // ); + // self.display_map.update(cx, |display_map, cx| { + // let snapshot = display_map.snapshot(cx); + // clone.display_map.update(cx, |display_map, cx| { + // display_map.set_state(&snapshot, cx); + // }); + // }); + // clone.selections.clone_state(&self.selections); + // clone.scroll_manager.clone_state(&self.scroll_manager); + // clone.searchable = self.searchable; + // clone + // } -// fn new( -// mode: EditorMode, -// buffer: Model, -// project: Option>, -// get_field_editor_theme: Option>, -// cx: &mut ViewContext, -// ) -> Self { -// let editor_view_id = cx.view_id(); -// let display_map = cx.add_model(|cx| { -// let settings = settings::get::(cx); -// let style = build_style(settings, get_field_editor_theme.as_deref(), None, cx); -// DisplayMap::new( -// buffer.clone(), -// style.text.font_id, -// style.text.font_size, -// None, -// 2, -// 1, -// cx, -// ) -// }); + // fn new( + // mode: EditorMode, + // buffer: Model, + // project: Option>, + // get_field_editor_theme: Option>, + // cx: &mut ViewContext, + // ) -> Self { + // let editor_view_id = cx.view_id(); + // let display_map = cx.add_model(|cx| { + // let settings = settings::get::(cx); + // let style = build_style(settings, get_field_editor_theme.as_deref(), None, cx); + // DisplayMap::new( + // buffer.clone(), + // style.text.font_id, + // style.text.font_size, + // None, + // 2, + // 1, + // cx, + // ) + // }); -// let selections = SelectionsCollection::new(display_map.clone(), buffer.clone()); + // let selections = SelectionsCollection::new(display_map.clone(), buffer.clone()); -// let blink_manager = cx.add_model(|cx| BlinkManager::new(CURSOR_BLINK_INTERVAL, cx)); + // let blink_manager = cx.add_model(|cx| BlinkManager::new(CURSOR_BLINK_INTERVAL, cx)); -// let soft_wrap_mode_override = -// (mode == EditorMode::SingleLine).then(|| language_settings::SoftWrap::None); + // let soft_wrap_mode_override = + // (mode == EditorMode::SingleLine).then(|| language_settings::SoftWrap::None); -// let mut project_subscriptions = Vec::new(); -// if mode == EditorMode::Full { -// if let Some(project) = project.as_ref() { -// if buffer.read(cx).is_singleton() { -// project_subscriptions.push(cx.observe(project, |_, _, cx| { -// cx.emit(Event::TitleChanged); -// })); -// } -// project_subscriptions.push(cx.subscribe(project, |editor, _, event, cx| { -// if let project::Event::RefreshInlayHints = event { -// editor.refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx); -// }; -// })); -// } -// } + // let mut project_subscriptions = Vec::new(); + // if mode == EditorMode::Full { + // if let Some(project) = project.as_ref() { + // if buffer.read(cx).is_singleton() { + // project_subscriptions.push(cx.observe(project, |_, _, cx| { + // cx.emit(Event::TitleChanged); + // })); + // } + // project_subscriptions.push(cx.subscribe(project, |editor, _, event, cx| { + // if let project::Event::RefreshInlayHints = event { + // editor.refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx); + // }; + // })); + // } + // } -// let inlay_hint_settings = inlay_hint_settings( -// selections.newest_anchor().head(), -// &buffer.read(cx).snapshot(cx), -// cx, -// ); + // let inlay_hint_settings = inlay_hint_settings( + // selections.newest_anchor().head(), + // &buffer.read(cx).snapshot(cx), + // cx, + // ); -// let mut this = Self { -// handle: cx.weak_handle(), -// buffer: buffer.clone(), -// display_map: display_map.clone(), -// selections, -// scroll_manager: ScrollManager::new(), -// columnar_selection_tail: None, -// add_selections_state: None, -// select_next_state: None, -// select_prev_state: None, -// selection_history: Default::default(), -// autoclose_regions: Default::default(), -// snippet_stack: Default::default(), -// select_larger_syntax_node_stack: Vec::new(), -// ime_transaction: Default::default(), -// active_diagnostics: None, -// soft_wrap_mode_override, -// get_field_editor_theme, -// collaboration_hub: project.clone().map(|project| Box::new(project) as _), -// project, -// focused: false, -// blink_manager: blink_manager.clone(), -// show_local_selections: true, -// mode, -// show_gutter: mode == EditorMode::Full, -// show_wrap_guides: None, -// placeholder_text: None, -// highlighted_rows: None, -// background_highlights: Default::default(), -// inlay_background_highlights: Default::default(), -// nav_history: None, -// context_menu: RwLock::new(None), -// mouse_context_menu: cx -// .add_view(|cx| context_menu::ContextMenu::new(editor_view_id, cx)), -// completion_tasks: Default::default(), -// next_completion_id: 0, -// next_inlay_id: 0, -// available_code_actions: Default::default(), -// code_actions_task: Default::default(), -// document_highlights_task: Default::default(), -// pending_rename: Default::default(), -// searchable: true, -// override_text_style: None, -// cursor_shape: Default::default(), -// autoindent_mode: Some(AutoindentMode::EachLine), -// collapse_matches: false, -// workspace: None, -// keymap_context_layers: Default::default(), -// input_enabled: true, -// read_only: false, -// leader_peer_id: None, -// remote_id: None, -// hover_state: Default::default(), -// link_go_to_definition_state: Default::default(), -// copilot_state: Default::default(), -// // inlay_hint_cache: InlayHintCache::new(inlay_hint_settings), -// gutter_hovered: false, -// pixel_position_of_newest_cursor: None, -// _subscriptions: vec![ -// cx.observe(&buffer, Self::on_buffer_changed), -// cx.subscribe(&buffer, Self::on_buffer_event), -// cx.observe(&display_map, Self::on_display_map_changed), -// cx.observe(&blink_manager, |_, _, cx| cx.notify()), -// cx.observe_global::(Self::settings_changed), -// cx.observe_window_activation(|editor, active, cx| { -// editor.blink_manager.update(cx, |blink_manager, cx| { -// if active { -// blink_manager.enable(cx); -// } else { -// blink_manager.show_cursor(cx); -// blink_manager.disable(cx); -// } -// }); -// }), -// ], -// }; + // let mut this = Self { + // handle: cx.weak_handle(), + // buffer: buffer.clone(), + // display_map: display_map.clone(), + // selections, + // scroll_manager: ScrollManager::new(), + // columnar_selection_tail: None, + // add_selections_state: None, + // select_next_state: None, + // select_prev_state: None, + // selection_history: Default::default(), + // autoclose_regions: Default::default(), + // snippet_stack: Default::default(), + // select_larger_syntax_node_stack: Vec::new(), + // ime_transaction: Default::default(), + // active_diagnostics: None, + // soft_wrap_mode_override, + // get_field_editor_theme, + // collaboration_hub: project.clone().map(|project| Box::new(project) as _), + // project, + // focused: false, + // blink_manager: blink_manager.clone(), + // show_local_selections: true, + // mode, + // show_gutter: mode == EditorMode::Full, + // show_wrap_guides: None, + // placeholder_text: None, + // highlighted_rows: None, + // background_highlights: Default::default(), + // inlay_background_highlights: Default::default(), + // nav_history: None, + // context_menu: RwLock::new(None), + // mouse_context_menu: cx + // .add_view(|cx| context_menu::ContextMenu::new(editor_view_id, cx)), + // completion_tasks: Default::default(), + // next_completion_id: 0, + // next_inlay_id: 0, + // available_code_actions: Default::default(), + // code_actions_task: Default::default(), + // document_highlights_task: Default::default(), + // pending_rename: Default::default(), + // searchable: true, + // override_text_style: None, + // cursor_shape: Default::default(), + // autoindent_mode: Some(AutoindentMode::EachLine), + // collapse_matches: false, + // workspace: None, + // keymap_context_layers: Default::default(), + // input_enabled: true, + // read_only: false, + // leader_peer_id: None, + // remote_id: None, + // hover_state: Default::default(), + // link_go_to_definition_state: Default::default(), + // copilot_state: Default::default(), + // // inlay_hint_cache: InlayHintCache::new(inlay_hint_settings), + // gutter_hovered: false, + // pixel_position_of_newest_cursor: None, + // _subscriptions: vec![ + // cx.observe(&buffer, Self::on_buffer_changed), + // cx.subscribe(&buffer, Self::on_buffer_event), + // cx.observe(&display_map, Self::on_display_map_changed), + // cx.observe(&blink_manager, |_, _, cx| cx.notify()), + // cx.observe_global::(Self::settings_changed), + // cx.observe_window_activation(|editor, active, cx| { + // editor.blink_manager.update(cx, |blink_manager, cx| { + // if active { + // blink_manager.enable(cx); + // } else { + // blink_manager.show_cursor(cx); + // blink_manager.disable(cx); + // } + // }); + // }), + // ], + // }; -// this._subscriptions.extend(project_subscriptions); + // this._subscriptions.extend(project_subscriptions); -// this.end_selection(cx); -// this.scroll_manager.show_scrollbar(cx); + // this.end_selection(cx); + // this.scroll_manager.show_scrollbar(cx); -// let editor_created_event = EditorCreated(cx.handle()); -// cx.emit_global(editor_created_event); + // let editor_created_event = EditorCreated(cx.handle()); + // cx.emit_global(editor_created_event); -// if mode == EditorMode::Full { -// let should_auto_hide_scrollbars = cx.platform().should_auto_hide_scrollbars(); -// cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars)); -// } + // if mode == EditorMode::Full { + // let should_auto_hide_scrollbars = cx.platform().should_auto_hide_scrollbars(); + // cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars)); + // } -// this.report_editor_event("open", None, cx); -// this -// } + // this.report_editor_event("open", None, cx); + // this + // } -// pub fn new_file( -// workspace: &mut Workspace, -// _: &workspace::NewFile, -// cx: &mut ViewContext, -// ) { -// let project = workspace.project().clone(); -// if project.read(cx).is_remote() { -// cx.propagate_action(); -// } else if let Some(buffer) = project -// .update(cx, |project, cx| project.create_buffer("", None, cx)) -// .log_err() -// { -// workspace.add_item( -// Box::new(cx.add_view(|cx| Editor::for_buffer(buffer, Some(project.clone()), cx))), -// cx, -// ); -// } -// } + // pub fn new_file( + // workspace: &mut Workspace, + // _: &workspace::NewFile, + // cx: &mut ViewContext, + // ) { + // let project = workspace.project().clone(); + // if project.read(cx).is_remote() { + // cx.propagate_action(); + // } else if let Some(buffer) = project + // .update(cx, |project, cx| project.create_buffer("", None, cx)) + // .log_err() + // { + // workspace.add_item( + // Box::new(cx.add_view(|cx| Editor::for_buffer(buffer, Some(project.clone()), cx))), + // cx, + // ); + // } + // } -// pub fn new_file_in_direction( -// workspace: &mut Workspace, -// action: &workspace::NewFileInDirection, -// cx: &mut ViewContext, -// ) { -// let project = workspace.project().clone(); -// if project.read(cx).is_remote() { -// cx.propagate_action(); -// } else if let Some(buffer) = project -// .update(cx, |project, cx| project.create_buffer("", None, cx)) -// .log_err() -// { -// workspace.split_item( -// action.0, -// Box::new(cx.add_view(|cx| Editor::for_buffer(buffer, Some(project.clone()), cx))), -// cx, -// ); -// } -// } + // pub fn new_file_in_direction( + // workspace: &mut Workspace, + // action: &workspace::NewFileInDirection, + // cx: &mut ViewContext, + // ) { + // let project = workspace.project().clone(); + // if project.read(cx).is_remote() { + // cx.propagate_action(); + // } else if let Some(buffer) = project + // .update(cx, |project, cx| project.create_buffer("", None, cx)) + // .log_err() + // { + // workspace.split_item( + // action.0, + // Box::new(cx.add_view(|cx| Editor::for_buffer(buffer, Some(project.clone()), cx))), + // cx, + // ); + // } + // } -// pub fn replica_id(&self, cx: &AppContext) -> ReplicaId { -// self.buffer.read(cx).replica_id() -// } + // pub fn replica_id(&self, cx: &AppContext) -> ReplicaId { + // self.buffer.read(cx).replica_id() + // } -// pub fn leader_peer_id(&self) -> Option { -// self.leader_peer_id -// } + // pub fn leader_peer_id(&self) -> Option { + // self.leader_peer_id + // } -pub fn buffer(&self) -> &Model { - &self.buffer + pub fn buffer(&self) -> &Model { + &self.buffer + } + + // fn workspace(&self, cx: &AppContext) -> Option> { + // self.workspace.as_ref()?.0.upgrade(cx) + // } + + // pub fn title<'a>(&self, cx: &'a AppContext) -> Cow<'a, str> { + // self.buffer().read(cx).title(cx) + // } + + // pub fn snapshot(&mut self, cx: &mut WindowContext) -> EditorSnapshot { + // EditorSnapshot { + // mode: self.mode, + // show_gutter: self.show_gutter, + // display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)), + // scroll_anchor: self.scroll_manager.anchor(), + // ongoing_scroll: self.scroll_manager.ongoing_scroll(), + // placeholder_text: self.placeholder_text.clone(), + // is_focused: self + // .handle + // .upgrade(cx) + // .map_or(false, |handle| handle.is_focused(cx)), + // } + // } + + // pub fn language_at<'a, T: ToOffset>( + // &self, + // point: T, + // cx: &'a AppContext, + // ) -> Option> { + // self.buffer.read(cx).language_at(point, cx) + // } + + // pub fn file_at<'a, T: ToOffset>(&self, point: T, cx: &'a AppContext) -> Option> { + // self.buffer.read(cx).read(cx).file_at(point).cloned() + // } + + // pub fn active_excerpt( + // &self, + // cx: &AppContext, + // ) -> Option<(ExcerptId, Model, Range)> { + // self.buffer + // .read(cx) + // .excerpt_containing(self.selections.newest_anchor().head(), cx) + // } + + // pub fn style(&self, cx: &AppContext) -> EditorStyle { + // build_style( + // settings::get::(cx), + // self.get_field_editor_theme.as_deref(), + // self.override_text_style.as_deref(), + // cx, + // ) + // } + + // pub fn mode(&self) -> EditorMode { + // self.mode + // } + + // pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> { + // self.collaboration_hub.as_deref() + // } + + // pub fn set_collaboration_hub(&mut self, hub: Box) { + // self.collaboration_hub = Some(hub); + // } + + // pub fn set_placeholder_text( + // &mut self, + // placeholder_text: impl Into>, + // cx: &mut ViewContext, + // ) { + // self.placeholder_text = Some(placeholder_text.into()); + // cx.notify(); + // } + + // pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut ViewContext) { + // self.cursor_shape = cursor_shape; + // cx.notify(); + // } + + // pub fn set_collapse_matches(&mut self, collapse_matches: bool) { + // self.collapse_matches = collapse_matches; + // } + + // pub fn range_for_match(&self, range: &Range) -> Range { + // if self.collapse_matches { + // return range.start..range.start; + // } + // range.clone() + // } + + // pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut ViewContext) { + // if self.display_map.read(cx).clip_at_line_ends != clip { + // self.display_map + // .update(cx, |map, _| map.clip_at_line_ends = clip); + // } + // } + + // pub fn set_keymap_context_layer( + // &mut self, + // context: KeymapContext, + // cx: &mut ViewContext, + // ) { + // self.keymap_context_layers + // .insert(TypeId::of::(), context); + // cx.notify(); + // } + + // pub fn remove_keymap_context_layer(&mut self, cx: &mut ViewContext) { + // self.keymap_context_layers.remove(&TypeId::of::()); + // cx.notify(); + // } + + // pub fn set_input_enabled(&mut self, input_enabled: bool) { + // self.input_enabled = input_enabled; + // } + + // pub fn set_autoindent(&mut self, autoindent: bool) { + // if autoindent { + // self.autoindent_mode = Some(AutoindentMode::EachLine); + // } else { + // self.autoindent_mode = None; + // } + // } + + // pub fn read_only(&self) -> bool { + // self.read_only + // } + + // pub fn set_read_only(&mut self, read_only: bool) { + // self.read_only = read_only; + // } + + // pub fn set_field_editor_style( + // &mut self, + // style: Option>, + // cx: &mut ViewContext, + // ) { + // self.get_field_editor_theme = style; + // cx.notify(); + // } + + // fn selections_did_change( + // &mut self, + // local: bool, + // old_cursor_position: &Anchor, + // cx: &mut ViewContext, + // ) { + // if self.focused && self.leader_peer_id.is_none() { + // self.buffer.update(cx, |buffer, cx| { + // buffer.set_active_selections( + // &self.selections.disjoint_anchors(), + // self.selections.line_mode, + // self.cursor_shape, + // cx, + // ) + // }); + // } + + // let display_map = self + // .display_map + // .update(cx, |display_map, cx| display_map.snapshot(cx)); + // let buffer = &display_map.buffer_snapshot; + // self.add_selections_state = None; + // self.select_next_state = None; + // self.select_prev_state = None; + // self.select_larger_syntax_node_stack.clear(); + // self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), buffer); + // self.snippet_stack + // .invalidate(&self.selections.disjoint_anchors(), buffer); + // self.take_rename(false, cx); + + // let new_cursor_position = self.selections.newest_anchor().head(); + + // self.push_to_nav_history( + // old_cursor_position.clone(), + // Some(new_cursor_position.to_point(buffer)), + // cx, + // ); + + // if local { + // let new_cursor_position = self.selections.newest_anchor().head(); + // let mut context_menu = self.context_menu.write(); + // let completion_menu = match context_menu.as_ref() { + // Some(ContextMenu::Completions(menu)) => Some(menu), + + // _ => { + // *context_menu = None; + // None + // } + // }; + + // if let Some(completion_menu) = completion_menu { + // let cursor_position = new_cursor_position.to_offset(buffer); + // let (word_range, kind) = + // buffer.surrounding_word(completion_menu.initial_position.clone()); + // if kind == Some(CharKind::Word) + // && word_range.to_inclusive().contains(&cursor_position) + // { + // let mut completion_menu = completion_menu.clone(); + // drop(context_menu); + + // let query = Self::completion_query(buffer, cursor_position); + // cx.spawn(move |this, mut cx| async move { + // completion_menu + // .filter(query.as_deref(), cx.background().clone()) + // .await; + + // this.update(&mut cx, |this, cx| { + // let mut context_menu = this.context_menu.write(); + // let Some(ContextMenu::Completions(menu)) = context_menu.as_ref() else { + // return; + // }; + + // if menu.id > completion_menu.id { + // return; + // } + + // *context_menu = Some(ContextMenu::Completions(completion_menu)); + // drop(context_menu); + // cx.notify(); + // }) + // }) + // .detach(); + + // self.show_completions(&ShowCompletions, cx); + // } else { + // drop(context_menu); + // self.hide_context_menu(cx); + // } + // } else { + // drop(context_menu); + // } + + // hide_hover(self, cx); + + // if old_cursor_position.to_display_point(&display_map).row() + // != new_cursor_position.to_display_point(&display_map).row() + // { + // self.available_code_actions.take(); + // } + // self.refresh_code_actions(cx); + // self.refresh_document_highlights(cx); + // refresh_matching_bracket_highlights(self, cx); + // self.discard_copilot_suggestion(cx); + // } + + // self.blink_manager.update(cx, BlinkManager::pause_blinking); + // cx.emit(Event::SelectionsChanged { local }); + // cx.notify(); + // } + + // pub fn change_selections( + // &mut self, + // autoscroll: Option, + // cx: &mut ViewContext, + // change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R, + // ) -> R { + // let old_cursor_position = self.selections.newest_anchor().head(); + // self.push_to_selection_history(); + + // let (changed, result) = self.selections.change_with(cx, change); + + // if changed { + // if let Some(autoscroll) = autoscroll { + // self.request_autoscroll(autoscroll, cx); + // } + // self.selections_did_change(true, &old_cursor_position, cx); + // } + + // result + // } + + // pub fn edit(&mut self, edits: I, cx: &mut ViewContext) + // where + // I: IntoIterator, T)>, + // S: ToOffset, + // T: Into>, + // { + // if self.read_only { + // return; + // } + + // self.buffer + // .update(cx, |buffer, cx| buffer.edit(edits, None, cx)); + // } + + // pub fn edit_with_autoindent(&mut self, edits: I, cx: &mut ViewContext) + // where + // I: IntoIterator, T)>, + // S: ToOffset, + // T: Into>, + // { + // if self.read_only { + // return; + // } + + // self.buffer.update(cx, |buffer, cx| { + // buffer.edit(edits, self.autoindent_mode.clone(), cx) + // }); + // } + + // pub fn edit_with_block_indent( + // &mut self, + // edits: I, + // original_indent_columns: Vec, + // cx: &mut ViewContext, + // ) where + // I: IntoIterator, T)>, + // S: ToOffset, + // T: Into>, + // { + // if self.read_only { + // return; + // } + + // self.buffer.update(cx, |buffer, cx| { + // buffer.edit( + // edits, + // Some(AutoindentMode::Block { + // original_indent_columns, + // }), + // cx, + // ) + // }); + // } + + // fn select(&mut self, phase: SelectPhase, cx: &mut ViewContext) { + // self.hide_context_menu(cx); + + // match phase { + // SelectPhase::Begin { + // position, + // add, + // click_count, + // } => self.begin_selection(position, add, click_count, cx), + // SelectPhase::BeginColumnar { + // position, + // goal_column, + // } => self.begin_columnar_selection(position, goal_column, cx), + // SelectPhase::Extend { + // position, + // click_count, + // } => self.extend_selection(position, click_count, cx), + // SelectPhase::Update { + // position, + // goal_column, + // scroll_position, + // } => self.update_selection(position, goal_column, scroll_position, cx), + // SelectPhase::End => self.end_selection(cx), + // } + // } + + // fn extend_selection( + // &mut self, + // position: DisplayPoint, + // click_count: usize, + // cx: &mut ViewContext, + // ) { + // let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); + // let tail = self.selections.newest::(cx).tail(); + // self.begin_selection(position, false, click_count, cx); + + // let position = position.to_offset(&display_map, Bias::Left); + // let tail_anchor = display_map.buffer_snapshot.anchor_before(tail); + + // let mut pending_selection = self + // .selections + // .pending_anchor() + // .expect("extend_selection not called with pending selection"); + // if position >= tail { + // pending_selection.start = tail_anchor; + // } else { + // pending_selection.end = tail_anchor; + // pending_selection.reversed = true; + // } + + // let mut pending_mode = self.selections.pending_mode().unwrap(); + // match &mut pending_mode { + // SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor, + // _ => {} + // } + + // self.change_selections(Some(Autoscroll::fit()), cx, |s| { + // s.set_pending(pending_selection, pending_mode) + // }); + // } + + // fn begin_selection( + // &mut self, + // position: DisplayPoint, + // add: bool, + // click_count: usize, + // cx: &mut ViewContext, + // ) { + // if !self.focused { + // cx.focus_self(); + // } + + // let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); + // let buffer = &display_map.buffer_snapshot; + // let newest_selection = self.selections.newest_anchor().clone(); + // let position = display_map.clip_point(position, Bias::Left); + + // let start; + // let end; + // let mode; + // let auto_scroll; + // match click_count { + // 1 => { + // start = buffer.anchor_before(position.to_point(&display_map)); + // end = start.clone(); + // mode = SelectMode::Character; + // auto_scroll = true; + // } + // 2 => { + // let range = movement::surrounding_word(&display_map, position); + // start = buffer.anchor_before(range.start.to_point(&display_map)); + // end = buffer.anchor_before(range.end.to_point(&display_map)); + // mode = SelectMode::Word(start.clone()..end.clone()); + // auto_scroll = true; + // } + // 3 => { + // let position = display_map + // .clip_point(position, Bias::Left) + // .to_point(&display_map); + // let line_start = display_map.prev_line_boundary(position).0; + // let next_line_start = buffer.clip_point( + // display_map.next_line_boundary(position).0 + Point::new(1, 0), + // Bias::Left, + // ); + // start = buffer.anchor_before(line_start); + // end = buffer.anchor_before(next_line_start); + // mode = SelectMode::Line(start.clone()..end.clone()); + // auto_scroll = true; + // } + // _ => { + // start = buffer.anchor_before(0); + // end = buffer.anchor_before(buffer.len()); + // mode = SelectMode::All; + // auto_scroll = false; + // } + // } + + // self.change_selections(auto_scroll.then(|| Autoscroll::newest()), cx, |s| { + // if !add { + // s.clear_disjoint(); + // } else if click_count > 1 { + // s.delete(newest_selection.id) + // } + + // s.set_pending_anchor_range(start..end, mode); + // }); + // } + + // fn begin_columnar_selection( + // &mut self, + // position: DisplayPoint, + // goal_column: u32, + // cx: &mut ViewContext, + // ) { + // if !self.focused { + // cx.focus_self(); + // } + + // let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); + // let tail = self.selections.newest::(cx).tail(); + // self.columnar_selection_tail = Some(display_map.buffer_snapshot.anchor_before(tail)); + + // self.select_columns( + // tail.to_display_point(&display_map), + // position, + // goal_column, + // &display_map, + // cx, + // ); + // } + + // fn update_selection( + // &mut self, + // position: DisplayPoint, + // goal_column: u32, + // scroll_position: Vector2F, + // cx: &mut ViewContext, + // ) { + // let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); + + // if let Some(tail) = self.columnar_selection_tail.as_ref() { + // let tail = tail.to_display_point(&display_map); + // self.select_columns(tail, position, goal_column, &display_map, cx); + // } else if let Some(mut pending) = self.selections.pending_anchor() { + // let buffer = self.buffer.read(cx).snapshot(cx); + // let head; + // let tail; + // let mode = self.selections.pending_mode().unwrap(); + // match &mode { + // SelectMode::Character => { + // head = position.to_point(&display_map); + // tail = pending.tail().to_point(&buffer); + // } + // SelectMode::Word(original_range) => { + // let original_display_range = original_range.start.to_display_point(&display_map) + // ..original_range.end.to_display_point(&display_map); + // let original_buffer_range = original_display_range.start.to_point(&display_map) + // ..original_display_range.end.to_point(&display_map); + // if movement::is_inside_word(&display_map, position) + // || original_display_range.contains(&position) + // { + // let word_range = movement::surrounding_word(&display_map, position); + // if word_range.start < original_display_range.start { + // head = word_range.start.to_point(&display_map); + // } else { + // head = word_range.end.to_point(&display_map); + // } + // } else { + // head = position.to_point(&display_map); + // } + + // if head <= original_buffer_range.start { + // tail = original_buffer_range.end; + // } else { + // tail = original_buffer_range.start; + // } + // } + // SelectMode::Line(original_range) => { + // let original_range = original_range.to_point(&display_map.buffer_snapshot); + + // let position = display_map + // .clip_point(position, Bias::Left) + // .to_point(&display_map); + // let line_start = display_map.prev_line_boundary(position).0; + // let next_line_start = buffer.clip_point( + // display_map.next_line_boundary(position).0 + Point::new(1, 0), + // Bias::Left, + // ); + + // if line_start < original_range.start { + // head = line_start + // } else { + // head = next_line_start + // } + + // if head <= original_range.start { + // tail = original_range.end; + // } else { + // tail = original_range.start; + // } + // } + // SelectMode::All => { + // return; + // } + // }; + + // if head < tail { + // pending.start = buffer.anchor_before(head); + // pending.end = buffer.anchor_before(tail); + // pending.reversed = true; + // } else { + // pending.start = buffer.anchor_before(tail); + // pending.end = buffer.anchor_before(head); + // pending.reversed = false; + // } + + // self.change_selections(None, cx, |s| { + // s.set_pending(pending, mode); + // }); + // } else { + // error!("update_selection dispatched with no pending selection"); + // return; + // } + + // self.set_scroll_position(scroll_position, cx); + // cx.notify(); + // } + + // fn end_selection(&mut self, cx: &mut ViewContext) { + // self.columnar_selection_tail.take(); + // if self.selections.pending_anchor().is_some() { + // let selections = self.selections.all::(cx); + // self.change_selections(None, cx, |s| { + // s.select(selections); + // s.clear_pending(); + // }); + // } + // } + + // fn select_columns( + // &mut self, + // tail: DisplayPoint, + // head: DisplayPoint, + // goal_column: u32, + // display_map: &DisplaySnapshot, + // cx: &mut ViewContext, + // ) { + // let start_row = cmp::min(tail.row(), head.row()); + // let end_row = cmp::max(tail.row(), head.row()); + // let start_column = cmp::min(tail.column(), goal_column); + // let end_column = cmp::max(tail.column(), goal_column); + // let reversed = start_column < tail.column(); + + // let selection_ranges = (start_row..=end_row) + // .filter_map(|row| { + // if start_column <= display_map.line_len(row) && !display_map.is_block_line(row) { + // let start = display_map + // .clip_point(DisplayPoint::new(row, start_column), Bias::Left) + // .to_point(display_map); + // let end = display_map + // .clip_point(DisplayPoint::new(row, end_column), Bias::Right) + // .to_point(display_map); + // if reversed { + // Some(end..start) + // } else { + // Some(start..end) + // } + // } else { + // None + // } + // }) + // .collect::>(); + + // self.change_selections(None, cx, |s| { + // s.select_ranges(selection_ranges); + // }); + // cx.notify(); + // } + + // pub fn has_pending_nonempty_selection(&self) -> bool { + // let pending_nonempty_selection = match self.selections.pending_anchor() { + // Some(Selection { start, end, .. }) => start != end, + // None => false, + // }; + // pending_nonempty_selection || self.columnar_selection_tail.is_some() + // } + + // pub fn has_pending_selection(&self) -> bool { + // self.selections.pending_anchor().is_some() || self.columnar_selection_tail.is_some() + // } + + // pub fn cancel(&mut self, _: &Cancel, cx: &mut ViewContext) { + // if self.take_rename(false, cx).is_some() { + // return; + // } + + // if hide_hover(self, cx) { + // return; + // } + + // if self.hide_context_menu(cx).is_some() { + // return; + // } + + // if self.discard_copilot_suggestion(cx) { + // return; + // } + + // if self.snippet_stack.pop().is_some() { + // return; + // } + + // if self.mode == EditorMode::Full { + // if self.active_diagnostics.is_some() { + // self.dismiss_diagnostics(cx); + // return; + // } + + // if self.change_selections(Some(Autoscroll::fit()), cx, |s| s.try_cancel()) { + // return; + // } + // } + + // cx.propagate_action(); + // } + + // pub fn handle_input(&mut self, text: &str, cx: &mut ViewContext) { + // let text: Arc = text.into(); + + // if self.read_only { + // return; + // } + + // let selections = self.selections.all_adjusted(cx); + // let mut brace_inserted = false; + // let mut edits = Vec::new(); + // let mut new_selections = Vec::with_capacity(selections.len()); + // let mut new_autoclose_regions = Vec::new(); + // let snapshot = self.buffer.read(cx).read(cx); + + // for (selection, autoclose_region) in + // self.selections_with_autoclose_regions(selections, &snapshot) + // { + // if let Some(scope) = snapshot.language_scope_at(selection.head()) { + // // Determine if the inserted text matches the opening or closing + // // bracket of any of this language's bracket pairs. + // let mut bracket_pair = None; + // let mut is_bracket_pair_start = false; + // if !text.is_empty() { + // // `text` can be empty when an user is using IME (e.g. Chinese Wubi Simplified) + // // and they are removing the character that triggered IME popup. + // for (pair, enabled) in scope.brackets() { + // if enabled && pair.close && pair.start.ends_with(text.as_ref()) { + // bracket_pair = Some(pair.clone()); + // is_bracket_pair_start = true; + // break; + // } else if pair.end.as_str() == text.as_ref() { + // bracket_pair = Some(pair.clone()); + // break; + // } + // } + // } + + // if let Some(bracket_pair) = bracket_pair { + // if selection.is_empty() { + // if is_bracket_pair_start { + // let prefix_len = bracket_pair.start.len() - text.len(); + + // // If the inserted text is a suffix of an opening bracket and the + // // selection is preceded by the rest of the opening bracket, then + // // insert the closing bracket. + // let following_text_allows_autoclose = snapshot + // .chars_at(selection.start) + // .next() + // .map_or(true, |c| scope.should_autoclose_before(c)); + // let preceding_text_matches_prefix = prefix_len == 0 + // || (selection.start.column >= (prefix_len as u32) + // && snapshot.contains_str_at( + // Point::new( + // selection.start.row, + // selection.start.column - (prefix_len as u32), + // ), + // &bracket_pair.start[..prefix_len], + // )); + // if following_text_allows_autoclose && preceding_text_matches_prefix { + // let anchor = snapshot.anchor_before(selection.end); + // new_selections.push((selection.map(|_| anchor), text.len())); + // new_autoclose_regions.push(( + // anchor, + // text.len(), + // selection.id, + // bracket_pair.clone(), + // )); + // edits.push(( + // selection.range(), + // format!("{}{}", text, bracket_pair.end).into(), + // )); + // brace_inserted = true; + // continue; + // } + // } + + // if let Some(region) = autoclose_region { + // // If the selection is followed by an auto-inserted closing bracket, + // // then don't insert that closing bracket again; just move the selection + // // past the closing bracket. + // let should_skip = selection.end == region.range.end.to_point(&snapshot) + // && text.as_ref() == region.pair.end.as_str(); + // if should_skip { + // let anchor = snapshot.anchor_after(selection.end); + // new_selections + // .push((selection.map(|_| anchor), region.pair.end.len())); + // continue; + // } + // } + // } + // // If an opening bracket is 1 character long and is typed while + // // text is selected, then surround that text with the bracket pair. + // else if is_bracket_pair_start && bracket_pair.start.chars().count() == 1 { + // edits.push((selection.start..selection.start, text.clone())); + // edits.push(( + // selection.end..selection.end, + // bracket_pair.end.as_str().into(), + // )); + // brace_inserted = true; + // new_selections.push(( + // Selection { + // id: selection.id, + // start: snapshot.anchor_after(selection.start), + // end: snapshot.anchor_before(selection.end), + // reversed: selection.reversed, + // goal: selection.goal, + // }, + // 0, + // )); + // continue; + // } + // } + // } + + // // If not handling any auto-close operation, then just replace the selected + // // text with the given input and move the selection to the end of the + // // newly inserted text. + // let anchor = snapshot.anchor_after(selection.end); + // new_selections.push((selection.map(|_| anchor), 0)); + // edits.push((selection.start..selection.end, text.clone())); + // } + + // drop(snapshot); + // self.transact(cx, |this, cx| { + // this.buffer.update(cx, |buffer, cx| { + // buffer.edit(edits, this.autoindent_mode.clone(), cx); + // }); + + // let new_anchor_selections = new_selections.iter().map(|e| &e.0); + // let new_selection_deltas = new_selections.iter().map(|e| e.1); + // let snapshot = this.buffer.read(cx).read(cx); + // let new_selections = resolve_multiple::(new_anchor_selections, &snapshot) + // .zip(new_selection_deltas) + // .map(|(selection, delta)| Selection { + // id: selection.id, + // start: selection.start + delta, + // end: selection.end + delta, + // reversed: selection.reversed, + // goal: SelectionGoal::None, + // }) + // .collect::>(); + + // let mut i = 0; + // for (position, delta, selection_id, pair) in new_autoclose_regions { + // let position = position.to_offset(&snapshot) + delta; + // let start = snapshot.anchor_before(position); + // let end = snapshot.anchor_after(position); + // while let Some(existing_state) = this.autoclose_regions.get(i) { + // match existing_state.range.start.cmp(&start, &snapshot) { + // Ordering::Less => i += 1, + // Ordering::Greater => break, + // Ordering::Equal => match end.cmp(&existing_state.range.end, &snapshot) { + // Ordering::Less => i += 1, + // Ordering::Equal => break, + // Ordering::Greater => break, + // }, + // } + // } + // this.autoclose_regions.insert( + // i, + // AutocloseRegion { + // selection_id, + // range: start..end, + // pair, + // }, + // ); + // } + + // drop(snapshot); + // let had_active_copilot_suggestion = this.has_active_copilot_suggestion(cx); + // this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(new_selections)); + + // if !brace_inserted && settings::get::(cx).use_on_type_format { + // if let Some(on_type_format_task) = + // this.trigger_on_type_formatting(text.to_string(), cx) + // { + // on_type_format_task.detach_and_log_err(cx); + // } + // } + + // if had_active_copilot_suggestion { + // this.refresh_copilot_suggestions(true, cx); + // if !this.has_active_copilot_suggestion(cx) { + // this.trigger_completion_on_input(&text, cx); + // } + // } else { + // this.trigger_completion_on_input(&text, cx); + // this.refresh_copilot_suggestions(true, cx); + // } + // }); + // } + + // pub fn newline(&mut self, _: &Newline, cx: &mut ViewContext) { + // self.transact(cx, |this, cx| { + // let (edits, selection_fixup_info): (Vec<_>, Vec<_>) = { + // let selections = this.selections.all::(cx); + // let multi_buffer = this.buffer.read(cx); + // let buffer = multi_buffer.snapshot(cx); + // selections + // .iter() + // .map(|selection| { + // let start_point = selection.start.to_point(&buffer); + // let mut indent = buffer.indent_size_for_line(start_point.row); + // indent.len = cmp::min(indent.len, start_point.column); + // let start = selection.start; + // let end = selection.end; + // let is_cursor = start == end; + // let language_scope = buffer.language_scope_at(start); + // let (comment_delimiter, insert_extra_newline) = if let Some(language) = + // &language_scope + // { + // let leading_whitespace_len = buffer + // .reversed_chars_at(start) + // .take_while(|c| c.is_whitespace() && *c != '\n') + // .map(|c| c.len_utf8()) + // .sum::(); + + // let trailing_whitespace_len = buffer + // .chars_at(end) + // .take_while(|c| c.is_whitespace() && *c != '\n') + // .map(|c| c.len_utf8()) + // .sum::(); + + // let insert_extra_newline = + // language.brackets().any(|(pair, enabled)| { + // let pair_start = pair.start.trim_end(); + // let pair_end = pair.end.trim_start(); + + // enabled + // && pair.newline + // && buffer.contains_str_at( + // end + trailing_whitespace_len, + // pair_end, + // ) + // && buffer.contains_str_at( + // (start - leading_whitespace_len) + // .saturating_sub(pair_start.len()), + // pair_start, + // ) + // }); + // // Comment extension on newline is allowed only for cursor selections + // let comment_delimiter = language.line_comment_prefix().filter(|_| { + // let is_comment_extension_enabled = + // multi_buffer.settings_at(0, cx).extend_comment_on_newline; + // is_cursor && is_comment_extension_enabled + // }); + // let comment_delimiter = if let Some(delimiter) = comment_delimiter { + // buffer + // .buffer_line_for_row(start_point.row) + // .is_some_and(|(snapshot, range)| { + // let mut index_of_first_non_whitespace = 0; + // let line_starts_with_comment = snapshot + // .chars_for_range(range) + // .skip_while(|c| { + // let should_skip = c.is_whitespace(); + // if should_skip { + // index_of_first_non_whitespace += 1; + // } + // should_skip + // }) + // .take(delimiter.len()) + // .eq(delimiter.chars()); + // let cursor_is_placed_after_comment_marker = + // index_of_first_non_whitespace + delimiter.len() + // <= start_point.column as usize; + // line_starts_with_comment + // && cursor_is_placed_after_comment_marker + // }) + // .then(|| delimiter.clone()) + // } else { + // None + // }; + // (comment_delimiter, insert_extra_newline) + // } else { + // (None, false) + // }; + + // let capacity_for_delimiter = comment_delimiter + // .as_deref() + // .map(str::len) + // .unwrap_or_default(); + // let mut new_text = + // String::with_capacity(1 + capacity_for_delimiter + indent.len as usize); + // new_text.push_str("\n"); + // new_text.extend(indent.chars()); + // if let Some(delimiter) = &comment_delimiter { + // new_text.push_str(&delimiter); + // } + // if insert_extra_newline { + // new_text = new_text.repeat(2); + // } + + // let anchor = buffer.anchor_after(end); + // let new_selection = selection.map(|_| anchor); + // ( + // (start..end, new_text), + // (insert_extra_newline, new_selection), + // ) + // }) + // .unzip() + // }; + + // this.edit_with_autoindent(edits, cx); + // let buffer = this.buffer.read(cx).snapshot(cx); + // let new_selections = selection_fixup_info + // .into_iter() + // .map(|(extra_newline_inserted, new_selection)| { + // let mut cursor = new_selection.end.to_point(&buffer); + // if extra_newline_inserted { + // cursor.row -= 1; + // cursor.column = buffer.line_len(cursor.row); + // } + // new_selection.map(|_| cursor) + // }) + // .collect(); + + // this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(new_selections)); + // this.refresh_copilot_suggestions(true, cx); + // }); + // } + + // pub fn newline_above(&mut self, _: &NewlineAbove, cx: &mut ViewContext) { + // let buffer = self.buffer.read(cx); + // let snapshot = buffer.snapshot(cx); + + // let mut edits = Vec::new(); + // let mut rows = Vec::new(); + // let mut rows_inserted = 0; + + // for selection in self.selections.all_adjusted(cx) { + // let cursor = selection.head(); + // let row = cursor.row; + + // let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left); + + // let newline = "\n".to_string(); + // edits.push((start_of_line..start_of_line, newline)); + + // rows.push(row + rows_inserted); + // rows_inserted += 1; + // } + + // self.transact(cx, |editor, cx| { + // editor.edit(edits, cx); + + // editor.change_selections(Some(Autoscroll::fit()), cx, |s| { + // let mut index = 0; + // s.move_cursors_with(|map, _, _| { + // let row = rows[index]; + // index += 1; + + // let point = Point::new(row, 0); + // let boundary = map.next_line_boundary(point).1; + // let clipped = map.clip_point(boundary, Bias::Left); + + // (clipped, SelectionGoal::None) + // }); + // }); + + // let mut indent_edits = Vec::new(); + // let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx); + // for row in rows { + // let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx); + // for (row, indent) in indents { + // if indent.len == 0 { + // continue; + // } + + // let text = match indent.kind { + // IndentKind::Space => " ".repeat(indent.len as usize), + // IndentKind::Tab => "\t".repeat(indent.len as usize), + // }; + // let point = Point::new(row, 0); + // indent_edits.push((point..point, text)); + // } + // } + // editor.edit(indent_edits, cx); + // }); + // } + + // pub fn newline_below(&mut self, _: &NewlineBelow, cx: &mut ViewContext) { + // let buffer = self.buffer.read(cx); + // let snapshot = buffer.snapshot(cx); + + // let mut edits = Vec::new(); + // let mut rows = Vec::new(); + // let mut rows_inserted = 0; + + // for selection in self.selections.all_adjusted(cx) { + // let cursor = selection.head(); + // let row = cursor.row; + + // let point = Point::new(row + 1, 0); + // let start_of_line = snapshot.clip_point(point, Bias::Left); + + // let newline = "\n".to_string(); + // edits.push((start_of_line..start_of_line, newline)); + + // rows_inserted += 1; + // rows.push(row + rows_inserted); + // } + + // self.transact(cx, |editor, cx| { + // editor.edit(edits, cx); + + // editor.change_selections(Some(Autoscroll::fit()), cx, |s| { + // let mut index = 0; + // s.move_cursors_with(|map, _, _| { + // let row = rows[index]; + // index += 1; + + // let point = Point::new(row, 0); + // let boundary = map.next_line_boundary(point).1; + // let clipped = map.clip_point(boundary, Bias::Left); + + // (clipped, SelectionGoal::None) + // }); + // }); + + // let mut indent_edits = Vec::new(); + // let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx); + // for row in rows { + // let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx); + // for (row, indent) in indents { + // if indent.len == 0 { + // continue; + // } + + // let text = match indent.kind { + // IndentKind::Space => " ".repeat(indent.len as usize), + // IndentKind::Tab => "\t".repeat(indent.len as usize), + // }; + // let point = Point::new(row, 0); + // indent_edits.push((point..point, text)); + // } + // } + // editor.edit(indent_edits, cx); + // }); + // } + + // pub fn insert(&mut self, text: &str, cx: &mut ViewContext) { + // self.insert_with_autoindent_mode( + // text, + // Some(AutoindentMode::Block { + // original_indent_columns: Vec::new(), + // }), + // cx, + // ); + // } + + // fn insert_with_autoindent_mode( + // &mut self, + // text: &str, + // autoindent_mode: Option, + // cx: &mut ViewContext, + // ) { + // if self.read_only { + // return; + // } + + // let text: Arc = text.into(); + // self.transact(cx, |this, cx| { + // let old_selections = this.selections.all_adjusted(cx); + // let selection_anchors = this.buffer.update(cx, |buffer, cx| { + // let anchors = { + // let snapshot = buffer.read(cx); + // old_selections + // .iter() + // .map(|s| { + // let anchor = snapshot.anchor_after(s.head()); + // s.map(|_| anchor) + // }) + // .collect::>() + // }; + // buffer.edit( + // old_selections + // .iter() + // .map(|s| (s.start..s.end, text.clone())), + // autoindent_mode, + // cx, + // ); + // anchors + // }); + + // this.change_selections(Some(Autoscroll::fit()), cx, |s| { + // s.select_anchors(selection_anchors); + // }) + // }); + // } + + // fn trigger_completion_on_input(&mut self, text: &str, cx: &mut ViewContext) { + // if !settings::get::(cx).show_completions_on_input { + // return; + // } + + // let selection = self.selections.newest_anchor(); + // if self + // .buffer + // .read(cx) + // .is_completion_trigger(selection.head(), text, cx) + // { + // self.show_completions(&ShowCompletions, cx); + // } else { + // self.hide_context_menu(cx); + // } + // } + + // /// If any empty selections is touching the start of its innermost containing autoclose + // /// region, expand it to select the brackets. + // fn select_autoclose_pair(&mut self, cx: &mut ViewContext) { + // let selections = self.selections.all::(cx); + // let buffer = self.buffer.read(cx).read(cx); + // let mut new_selections = Vec::new(); + // for (mut selection, region) in self.selections_with_autoclose_regions(selections, &buffer) { + // if let (Some(region), true) = (region, selection.is_empty()) { + // let mut range = region.range.to_offset(&buffer); + // if selection.start == range.start { + // if range.start >= region.pair.start.len() { + // range.start -= region.pair.start.len(); + // if buffer.contains_str_at(range.start, ®ion.pair.start) { + // if buffer.contains_str_at(range.end, ®ion.pair.end) { + // range.end += region.pair.end.len(); + // selection.start = range.start; + // selection.end = range.end; + // } + // } + // } + // } + // } + // new_selections.push(selection); + // } + + // drop(buffer); + // self.change_selections(None, cx, |selections| selections.select(new_selections)); + // } + + // /// Iterate the given selections, and for each one, find the smallest surrounding + // /// autoclose region. This uses the ordering of the selections and the autoclose + // /// regions to avoid repeated comparisons. + // fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>( + // &'a self, + // selections: impl IntoIterator>, + // buffer: &'a MultiBufferSnapshot, + // ) -> impl Iterator, Option<&'a AutocloseRegion>)> { + // let mut i = 0; + // let mut regions = self.autoclose_regions.as_slice(); + // selections.into_iter().map(move |selection| { + // let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer); + + // let mut enclosing = None; + // while let Some(pair_state) = regions.get(i) { + // if pair_state.range.end.to_offset(buffer) < range.start { + // regions = ®ions[i + 1..]; + // i = 0; + // } else if pair_state.range.start.to_offset(buffer) > range.end { + // break; + // } else { + // if pair_state.selection_id == selection.id { + // enclosing = Some(pair_state); + // } + // i += 1; + // } + // } + + // (selection.clone(), enclosing) + // }) + // } + + // /// Remove any autoclose regions that no longer contain their selection. + // fn invalidate_autoclose_regions( + // &mut self, + // mut selections: &[Selection], + // buffer: &MultiBufferSnapshot, + // ) { + // self.autoclose_regions.retain(|state| { + // let mut i = 0; + // while let Some(selection) = selections.get(i) { + // if selection.end.cmp(&state.range.start, buffer).is_lt() { + // selections = &selections[1..]; + // continue; + // } + // if selection.start.cmp(&state.range.end, buffer).is_gt() { + // break; + // } + // if selection.id == state.selection_id { + // return true; + // } else { + // i += 1; + // } + // } + // false + // }); + // } + + // fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option { + // let offset = position.to_offset(buffer); + // let (word_range, kind) = buffer.surrounding_word(offset); + // if offset > word_range.start && kind == Some(CharKind::Word) { + // Some( + // buffer + // .text_for_range(word_range.start..offset) + // .collect::(), + // ) + // } else { + // None + // } + // } + + // pub fn toggle_inlay_hints(&mut self, _: &ToggleInlayHints, cx: &mut ViewContext) { + // todo!(); + // // self.refresh_inlay_hints( + // // InlayHintRefreshReason::Toggle(!self.inlay_hint_cache.enabled), + // // cx, + // // ); + // } + + // pub fn inlay_hints_enabled(&self) -> bool { + // todo!(); + // self.inlay_hint_cache.enabled + // } + + // fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut ViewContext) { + // if self.project.is_none() || self.mode != EditorMode::Full { + // return; + // } + + // let reason_description = reason.description(); + // let (invalidate_cache, required_languages) = match reason { + // InlayHintRefreshReason::Toggle(enabled) => { + // self.inlay_hint_cache.enabled = enabled; + // if enabled { + // (InvalidationStrategy::RefreshRequested, None) + // } else { + // self.inlay_hint_cache.clear(); + // self.splice_inlay_hints( + // self.visible_inlay_hints(cx) + // .iter() + // .map(|inlay| inlay.id) + // .collect(), + // Vec::new(), + // cx, + // ); + // return; + // } + // } + // InlayHintRefreshReason::SettingsChange(new_settings) => { + // match self.inlay_hint_cache.update_settings( + // &self.buffer, + // new_settings, + // self.visible_inlay_hints(cx), + // cx, + // ) { + // ControlFlow::Break(Some(InlaySplice { + // to_remove, + // to_insert, + // })) => { + // self.splice_inlay_hints(to_remove, to_insert, cx); + // return; + // } + // ControlFlow::Break(None) => return, + // ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None), + // } + // } + // InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => { + // if let Some(InlaySplice { + // to_remove, + // to_insert, + // }) = self.inlay_hint_cache.remove_excerpts(excerpts_removed) + // { + // self.splice_inlay_hints(to_remove, to_insert, cx); + // } + // return; + // } + // InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None), + // InlayHintRefreshReason::BufferEdited(buffer_languages) => { + // (InvalidationStrategy::BufferEdited, Some(buffer_languages)) + // } + // InlayHintRefreshReason::RefreshRequested => { + // (InvalidationStrategy::RefreshRequested, None) + // } + // }; + + // if let Some(InlaySplice { + // to_remove, + // to_insert, + // }) = self.inlay_hint_cache.spawn_hint_refresh( + // reason_description, + // self.excerpt_visible_offsets(required_languages.as_ref(), cx), + // invalidate_cache, + // cx, + // ) { + // self.splice_inlay_hints(to_remove, to_insert, cx); + // } + // } + + // fn visible_inlay_hints(&self, cx: &ViewContext<'_, '_, Editor>) -> Vec { + // self.display_map + // .read(cx) + // .current_inlays() + // .filter(move |inlay| { + // Some(inlay.id) != self.copilot_state.suggestion.as_ref().map(|h| h.id) + // }) + // .cloned() + // .collect() + // } + + // pub fn excerpt_visible_offsets( + // &self, + // restrict_to_languages: Option<&HashSet>>, + // cx: &mut ViewContext<'_, '_, Editor>, + // ) -> HashMap, Global, Range)> { + // let multi_buffer = self.buffer().read(cx); + // let multi_buffer_snapshot = multi_buffer.snapshot(cx); + // let multi_buffer_visible_start = self + // .scroll_manager + // .anchor() + // .anchor + // .to_point(&multi_buffer_snapshot); + // let multi_buffer_visible_end = multi_buffer_snapshot.clip_point( + // multi_buffer_visible_start + // + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0), + // Bias::Left, + // ); + // let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end; + // multi_buffer + // .range_to_buffer_ranges(multi_buffer_visible_range, cx) + // .into_iter() + // .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty()) + // .filter_map(|(buffer_handle, excerpt_visible_range, excerpt_id)| { + // let buffer = buffer_handle.read(cx); + // let language = buffer.language()?; + // if let Some(restrict_to_languages) = restrict_to_languages { + // if !restrict_to_languages.contains(language) { + // return None; + // } + // } + // Some(( + // excerpt_id, + // ( + // buffer_handle, + // buffer.version().clone(), + // excerpt_visible_range, + // ), + // )) + // }) + // .collect() + // } + + // pub fn text_layout_details(&self, cx: &WindowContext) -> TextLayoutDetails { + // TextLayoutDetails { + // font_cache: cx.font_cache().clone(), + // text_layout_cache: cx.text_layout_cache().clone(), + // editor_style: self.style(cx), + // } + // } + + // fn splice_inlay_hints( + // &self, + // to_remove: Vec, + // to_insert: Vec, + // cx: &mut ViewContext, + // ) { + // self.display_map.update(cx, |display_map, cx| { + // display_map.splice_inlays(to_remove, to_insert, cx); + // }); + // cx.notify(); + // } + + // fn trigger_on_type_formatting( + // &self, + // input: String, + // cx: &mut ViewContext, + // ) -> Option>> { + // if input.len() != 1 { + // return None; + // } + + // let project = self.project.as_ref()?; + // let position = self.selections.newest_anchor().head(); + // let (buffer, buffer_position) = self + // .buffer + // .read(cx) + // .text_anchor_for_position(position.clone(), cx)?; + + // // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances, + // // hence we do LSP request & edit on host side only — add formats to host's history. + // let push_to_lsp_host_history = true; + // // If this is not the host, append its history with new edits. + // let push_to_client_history = project.read(cx).is_remote(); + + // let on_type_formatting = project.update(cx, |project, cx| { + // project.on_type_format( + // buffer.clone(), + // buffer_position, + // input, + // push_to_lsp_host_history, + // cx, + // ) + // }); + // Some(cx.spawn(|editor, mut cx| async move { + // if let Some(transaction) = on_type_formatting.await? { + // if push_to_client_history { + // buffer.update(&mut cx, |buffer, _| { + // buffer.push_transaction(transaction, Instant::now()); + // }); + // } + // editor.update(&mut cx, |editor, cx| { + // editor.refresh_document_highlights(cx); + // })?; + // } + // Ok(()) + // })) + // } + + // fn show_completions(&mut self, _: &ShowCompletions, cx: &mut ViewContext) { + // if self.pending_rename.is_some() { + // return; + // } + + // let project = if let Some(project) = self.project.clone() { + // project + // } else { + // return; + // }; + + // let position = self.selections.newest_anchor().head(); + // let (buffer, buffer_position) = if let Some(output) = self + // .buffer + // .read(cx) + // .text_anchor_for_position(position.clone(), cx) + // { + // output + // } else { + // return; + // }; + + // let query = Self::completion_query(&self.buffer.read(cx).read(cx), position.clone()); + // let completions = project.update(cx, |project, cx| { + // project.completions(&buffer, buffer_position, cx) + // }); + + // let id = post_inc(&mut self.next_completion_id); + // let task = cx.spawn(|this, mut cx| { + // async move { + // let menu = if let Some(completions) = completions.await.log_err() { + // let mut menu = CompletionsMenu { + // id, + // initial_position: position, + // match_candidates: completions + // .iter() + // .enumerate() + // .map(|(id, completion)| { + // StringMatchCandidate::new( + // id, + // completion.label.text[completion.label.filter_range.clone()] + // .into(), + // ) + // }) + // .collect(), + // buffer, + // completions: Arc::new(RwLock::new(completions.into())), + // matches: Vec::new().into(), + // selected_item: 0, + // list: Default::default(), + // }; + // menu.filter(query.as_deref(), cx.background()).await; + // if menu.matches.is_empty() { + // None + // } else { + // _ = this.update(&mut cx, |editor, cx| { + // menu.pre_resolve_completion_documentation(editor.project.clone(), cx); + // }); + // Some(menu) + // } + // } else { + // None + // }; + + // this.update(&mut cx, |this, cx| { + // this.completion_tasks.retain(|(task_id, _)| *task_id > id); + + // let mut context_menu = this.context_menu.write(); + // match context_menu.as_ref() { + // None => {} + + // Some(ContextMenu::Completions(prev_menu)) => { + // if prev_menu.id > id { + // return; + // } + // } + + // _ => return, + // } + + // if this.focused && menu.is_some() { + // let menu = menu.unwrap(); + // *context_menu = Some(ContextMenu::Completions(menu)); + // drop(context_menu); + // this.discard_copilot_suggestion(cx); + // cx.notify(); + // } else if this.completion_tasks.is_empty() { + // // If there are no more completion tasks and the last menu was + // // empty, we should hide it. If it was already hidden, we should + // // also show the copilot suggestion when available. + // drop(context_menu); + // if this.hide_context_menu(cx).is_none() { + // this.update_visible_copilot_suggestion(cx); + // } + // } + // })?; + + // Ok::<_, anyhow::Error>(()) + // } + // .log_err() + // }); + // self.completion_tasks.push((id, task)); + // } + + // pub fn confirm_completion( + // &mut self, + // action: &ConfirmCompletion, + // cx: &mut ViewContext, + // ) -> Option>> { + // use language::ToOffset as _; + + // let completions_menu = if let ContextMenu::Completions(menu) = self.hide_context_menu(cx)? { + // menu + // } else { + // return None; + // }; + + // let mat = completions_menu + // .matches + // .get(action.item_ix.unwrap_or(completions_menu.selected_item))?; + // let buffer_handle = completions_menu.buffer; + // let completions = completions_menu.completions.read(); + // let completion = completions.get(mat.candidate_id)?; + + // let snippet; + // let text; + // if completion.is_snippet() { + // snippet = Some(Snippet::parse(&completion.new_text).log_err()?); + // text = snippet.as_ref().unwrap().text.clone(); + // } else { + // snippet = None; + // text = completion.new_text.clone(); + // }; + // let selections = self.selections.all::(cx); + // let buffer = buffer_handle.read(cx); + // let old_range = completion.old_range.to_offset(buffer); + // let old_text = buffer.text_for_range(old_range.clone()).collect::(); + + // let newest_selection = self.selections.newest_anchor(); + // if newest_selection.start.buffer_id != Some(buffer_handle.read(cx).remote_id()) { + // return None; + // } + + // let lookbehind = newest_selection + // .start + // .text_anchor + // .to_offset(buffer) + // .saturating_sub(old_range.start); + // let lookahead = old_range + // .end + // .saturating_sub(newest_selection.end.text_anchor.to_offset(buffer)); + // let mut common_prefix_len = old_text + // .bytes() + // .zip(text.bytes()) + // .take_while(|(a, b)| a == b) + // .count(); + + // let snapshot = self.buffer.read(cx).snapshot(cx); + // let mut range_to_replace: Option> = None; + // let mut ranges = Vec::new(); + // for selection in &selections { + // if snapshot.contains_str_at(selection.start.saturating_sub(lookbehind), &old_text) { + // let start = selection.start.saturating_sub(lookbehind); + // let end = selection.end + lookahead; + // if selection.id == newest_selection.id { + // range_to_replace = Some( + // ((start + common_prefix_len) as isize - selection.start as isize) + // ..(end as isize - selection.start as isize), + // ); + // } + // ranges.push(start + common_prefix_len..end); + // } else { + // common_prefix_len = 0; + // ranges.clear(); + // ranges.extend(selections.iter().map(|s| { + // if s.id == newest_selection.id { + // range_to_replace = Some( + // old_range.start.to_offset_utf16(&snapshot).0 as isize + // - selection.start as isize + // ..old_range.end.to_offset_utf16(&snapshot).0 as isize + // - selection.start as isize, + // ); + // old_range.clone() + // } else { + // s.start..s.end + // } + // })); + // break; + // } + // } + // let text = &text[common_prefix_len..]; + + // cx.emit(Event::InputHandled { + // utf16_range_to_replace: range_to_replace, + // text: text.into(), + // }); + + // self.transact(cx, |this, cx| { + // if let Some(mut snippet) = snippet { + // snippet.text = text.to_string(); + // for tabstop in snippet.tabstops.iter_mut().flatten() { + // tabstop.start -= common_prefix_len as isize; + // tabstop.end -= common_prefix_len as isize; + // } + + // this.insert_snippet(&ranges, snippet, cx).log_err(); + // } else { + // this.buffer.update(cx, |buffer, cx| { + // buffer.edit( + // ranges.iter().map(|range| (range.clone(), text)), + // this.autoindent_mode.clone(), + // cx, + // ); + // }); + // } + + // this.refresh_copilot_suggestions(true, cx); + // }); + + // let project = self.project.clone()?; + // let apply_edits = project.update(cx, |project, cx| { + // project.apply_additional_edits_for_completion( + // buffer_handle, + // completion.clone(), + // true, + // cx, + // ) + // }); + // Some(cx.foreground().spawn(async move { + // apply_edits.await?; + // Ok(()) + // })) + // } + + // pub fn toggle_code_actions(&mut self, action: &ToggleCodeActions, cx: &mut ViewContext) { + // let mut context_menu = self.context_menu.write(); + // if matches!(context_menu.as_ref(), Some(ContextMenu::CodeActions(_))) { + // *context_menu = None; + // cx.notify(); + // return; + // } + // drop(context_menu); + + // let deployed_from_indicator = action.deployed_from_indicator; + // let mut task = self.code_actions_task.take(); + // cx.spawn(|this, mut cx| async move { + // while let Some(prev_task) = task { + // prev_task.await; + // task = this.update(&mut cx, |this, _| this.code_actions_task.take())?; + // } + + // this.update(&mut cx, |this, cx| { + // if this.focused { + // if let Some((buffer, actions)) = this.available_code_actions.clone() { + // this.completion_tasks.clear(); + // this.discard_copilot_suggestion(cx); + // *this.context_menu.write() = + // Some(ContextMenu::CodeActions(CodeActionsMenu { + // buffer, + // actions, + // selected_item: Default::default(), + // list: Default::default(), + // deployed_from_indicator, + // })); + // } + // } + // })?; + + // Ok::<_, anyhow::Error>(()) + // }) + // .detach_and_log_err(cx); + // } + + // pub fn confirm_code_action( + // workspace: &mut Workspace, + // action: &ConfirmCodeAction, + // cx: &mut ViewContext, + // ) -> Option>> { + // let editor = workspace.active_item(cx)?.act_as::(cx)?; + // let actions_menu = if let ContextMenu::CodeActions(menu) = + // editor.update(cx, |editor, cx| editor.hide_context_menu(cx))? + // { + // menu + // } else { + // return None; + // }; + // let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item); + // let action = actions_menu.actions.get(action_ix)?.clone(); + // let title = action.lsp_action.title.clone(); + // let buffer = actions_menu.buffer; + + // let apply_code_actions = workspace.project().clone().update(cx, |project, cx| { + // project.apply_code_action(buffer, action, true, cx) + // }); + // let editor = editor.downgrade(); + // Some(cx.spawn(|workspace, cx| async move { + // let project_transaction = apply_code_actions.await?; + // Self::open_project_transaction(&editor, workspace, project_transaction, title, cx).await + // })) + // } + + // async fn open_project_transaction( + // this: &WeakViewHandle Result<()> { + // let replica_id = this.read_with(&cx, |this, cx| this.replica_id(cx))?; + + // let mut entries = transaction.0.into_iter().collect::>(); + // entries.sort_unstable_by_key(|(buffer, _)| { + // buffer.read_with(&cx, |buffer, _| buffer.file().map(|f| f.path().clone())) + // }); + + // // If the project transaction's edits are all contained within this editor, then + // // avoid opening a new editor to display them. + + // if let Some((buffer, transaction)) = entries.first() { + // if entries.len() == 1 { + // let excerpt = this.read_with(&cx, |editor, cx| { + // editor + // .buffer() + // .read(cx) + // .excerpt_containing(editor.selections.newest_anchor().head(), cx) + // })?; + // if let Some((_, excerpted_buffer, excerpt_range)) = excerpt { + // if excerpted_buffer == *buffer { + // let all_edits_within_excerpt = buffer.read_with(&cx, |buffer, _| { + // let excerpt_range = excerpt_range.to_offset(buffer); + // buffer + // .edited_ranges_for_transaction::(transaction) + // .all(|range| { + // excerpt_range.start <= range.start + // && excerpt_range.end >= range.end + // }) + // }); + + // if all_edits_within_excerpt { + // return Ok(()); + // } + // } + // } + // } + // } else { + // return Ok(()); + // } + + // let mut ranges_to_highlight = Vec::new(); + // let excerpt_buffer = cx.add_model(|cx| { + // let mut multibuffer = MultiBuffer::new(replica_id).with_title(title); + // for (buffer_handle, transaction) in &entries { + // let buffer = buffer_handle.read(cx); + // ranges_to_highlight.extend( + // multibuffer.push_excerpts_with_context_lines( + // buffer_handle.clone(), + // buffer + // .edited_ranges_for_transaction::(transaction) + // .collect(), + // 1, + // cx, + // ), + // ); + // } + // multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx); + // multibuffer + // }); + + // workspace.update(&mut cx, |workspace, cx| { + // let project = workspace.project().clone(); + // let editor = + // cx.add_view(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), cx)); + // workspace.add_item(Box::new(editor.clone()), cx); + // editor.update(cx, |editor, cx| { + // editor.highlight_background::( + // ranges_to_highlight, + // |theme| theme.editor.highlighted_line_background, + // cx, + // ); + // }); + // })?; + + // Ok(()) + // } + + // fn refresh_code_actions(&mut self, cx: &mut ViewContext) -> Option<()> { + // let project = self.project.clone()?; + // let buffer = self.buffer.read(cx); + // let newest_selection = self.selections.newest_anchor().clone(); + // let (start_buffer, start) = buffer.text_anchor_for_position(newest_selection.start, cx)?; + // let (end_buffer, end) = buffer.text_anchor_for_position(newest_selection.end, cx)?; + // if start_buffer != end_buffer { + // return None; + // } + + // self.code_actions_task = Some(cx.spawn(|this, mut cx| async move { + // cx.background().timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT).await; + + // let actions = project + // .update(&mut cx, |project, cx| { + // project.code_actions(&start_buffer, start..end, cx) + // }) + // .await; + + // this.update(&mut cx, |this, cx| { + // this.available_code_actions = actions.log_err().and_then(|actions| { + // if actions.is_empty() { + // None + // } else { + // Some((start_buffer, actions.into())) + // } + // }); + // cx.notify(); + // }) + // .log_err(); + // })); + // None + // } + + // fn refresh_document_highlights(&mut self, cx: &mut ViewContext) -> Option<()> { + // if self.pending_rename.is_some() { + // return None; + // } + + // let project = self.project.clone()?; + // let buffer = self.buffer.read(cx); + // let newest_selection = self.selections.newest_anchor().clone(); + // let cursor_position = newest_selection.head(); + // let (cursor_buffer, cursor_buffer_position) = + // buffer.text_anchor_for_position(cursor_position.clone(), cx)?; + // let (tail_buffer, _) = buffer.text_anchor_for_position(newest_selection.tail(), cx)?; + // if cursor_buffer != tail_buffer { + // return None; + // } + + // self.document_highlights_task = Some(cx.spawn(|this, mut cx| async move { + // cx.background() + // .timer(DOCUMENT_HIGHLIGHTS_DEBOUNCE_TIMEOUT) + // .await; + + // let highlights = project + // .update(&mut cx, |project, cx| { + // project.document_highlights(&cursor_buffer, cursor_buffer_position, cx) + // }) + // .await + // .log_err(); + + // if let Some(highlights) = highlights { + // this.update(&mut cx, |this, cx| { + // if this.pending_rename.is_some() { + // return; + // } + + // let buffer_id = cursor_position.buffer_id; + // let buffer = this.buffer.read(cx); + // if !buffer + // .text_anchor_for_position(cursor_position, cx) + // .map_or(false, |(buffer, _)| buffer == cursor_buffer) + // { + // return; + // } + + // let cursor_buffer_snapshot = cursor_buffer.read(cx); + // let mut write_ranges = Vec::new(); + // let mut read_ranges = Vec::new(); + // for highlight in highlights { + // for (excerpt_id, excerpt_range) in + // buffer.excerpts_for_buffer(&cursor_buffer, cx) + // { + // let start = highlight + // .range + // .start + // .max(&excerpt_range.context.start, cursor_buffer_snapshot); + // let end = highlight + // .range + // .end + // .min(&excerpt_range.context.end, cursor_buffer_snapshot); + // if start.cmp(&end, cursor_buffer_snapshot).is_ge() { + // continue; + // } + + // let range = Anchor { + // buffer_id, + // excerpt_id: excerpt_id.clone(), + // text_anchor: start, + // }..Anchor { + // buffer_id, + // excerpt_id, + // text_anchor: end, + // }; + // if highlight.kind == lsp::DocumentHighlightKind::WRITE { + // write_ranges.push(range); + // } else { + // read_ranges.push(range); + // } + // } + // } + + // this.highlight_background::( + // read_ranges, + // |theme| theme.editor.document_highlight_read_background, + // cx, + // ); + // this.highlight_background::( + // write_ranges, + // |theme| theme.editor.document_highlight_write_background, + // cx, + // ); + // cx.notify(); + // }) + // .log_err(); + // } + // })); + // None + // } + + // fn refresh_copilot_suggestions( + // &mut self, + // debounce: bool, + // cx: &mut ViewContext, + // ) -> Option<()> { + // let copilot = Copilot::global(cx)?; + // if self.mode != EditorMode::Full || !copilot.read(cx).status().is_authorized() { + // self.clear_copilot_suggestions(cx); + // return None; + // } + // self.update_visible_copilot_suggestion(cx); + + // let snapshot = self.buffer.read(cx).snapshot(cx); + // let cursor = self.selections.newest_anchor().head(); + // if !self.is_copilot_enabled_at(cursor, &snapshot, cx) { + // self.clear_copilot_suggestions(cx); + // return None; + // } + + // let (buffer, buffer_position) = + // self.buffer.read(cx).text_anchor_for_position(cursor, cx)?; + // self.copilot_state.pending_refresh = cx.spawn(|this, mut cx| async move { + // if debounce { + // cx.background().timer(COPILOT_DEBOUNCE_TIMEOUT).await; + // } + + // let completions = copilot + // .update(&mut cx, |copilot, cx| { + // copilot.completions(&buffer, buffer_position, cx) + // }) + // .await + // .log_err() + // .into_iter() + // .flatten() + // .collect_vec(); + + // this.update(&mut cx, |this, cx| { + // if !completions.is_empty() { + // this.copilot_state.cycled = false; + // this.copilot_state.pending_cycling_refresh = Task::ready(None); + // this.copilot_state.completions.clear(); + // this.copilot_state.active_completion_index = 0; + // this.copilot_state.excerpt_id = Some(cursor.excerpt_id); + // for completion in completions { + // this.copilot_state.push_completion(completion); + // } + // this.update_visible_copilot_suggestion(cx); + // } + // }) + // .log_err()?; + // Some(()) + // }); + + // Some(()) + // } + + // fn cycle_copilot_suggestions( + // &mut self, + // direction: Direction, + // cx: &mut ViewContext, + // ) -> Option<()> { + // let copilot = Copilot::global(cx)?; + // if self.mode != EditorMode::Full || !copilot.read(cx).status().is_authorized() { + // return None; + // } + + // if self.copilot_state.cycled { + // self.copilot_state.cycle_completions(direction); + // self.update_visible_copilot_suggestion(cx); + // } else { + // let cursor = self.selections.newest_anchor().head(); + // let (buffer, buffer_position) = + // self.buffer.read(cx).text_anchor_for_position(cursor, cx)?; + // self.copilot_state.pending_cycling_refresh = cx.spawn(|this, mut cx| async move { + // let completions = copilot + // .update(&mut cx, |copilot, cx| { + // copilot.completions_cycling(&buffer, buffer_position, cx) + // }) + // .await; + + // this.update(&mut cx, |this, cx| { + // this.copilot_state.cycled = true; + // for completion in completions.log_err().into_iter().flatten() { + // this.copilot_state.push_completion(completion); + // } + // this.copilot_state.cycle_completions(direction); + // this.update_visible_copilot_suggestion(cx); + // }) + // .log_err()?; + + // Some(()) + // }); + // } + + // Some(()) + // } + + // fn copilot_suggest(&mut self, _: &copilot::Suggest, cx: &mut ViewContext) { + // if !self.has_active_copilot_suggestion(cx) { + // self.refresh_copilot_suggestions(false, cx); + // return; + // } + + // self.update_visible_copilot_suggestion(cx); + // } + + // fn next_copilot_suggestion(&mut self, _: &copilot::NextSuggestion, cx: &mut ViewContext) { + // if self.has_active_copilot_suggestion(cx) { + // self.cycle_copilot_suggestions(Direction::Next, cx); + // } else { + // let is_copilot_disabled = self.refresh_copilot_suggestions(false, cx).is_none(); + // if is_copilot_disabled { + // cx.propagate_action(); + // } + // } + // } + + // fn previous_copilot_suggestion( + // &mut self, + // _: &copilot::PreviousSuggestion, + // cx: &mut ViewContext, + // ) { + // if self.has_active_copilot_suggestion(cx) { + // self.cycle_copilot_suggestions(Direction::Prev, cx); + // } else { + // let is_copilot_disabled = self.refresh_copilot_suggestions(false, cx).is_none(); + // if is_copilot_disabled { + // cx.propagate_action(); + // } + // } + // } + + // fn accept_copilot_suggestion(&mut self, cx: &mut ViewContext) -> bool { + // if let Some(suggestion) = self.take_active_copilot_suggestion(cx) { + // if let Some((copilot, completion)) = + // Copilot::global(cx).zip(self.copilot_state.active_completion()) + // { + // copilot + // .update(cx, |copilot, cx| copilot.accept_completion(completion, cx)) + // .detach_and_log_err(cx); + + // self.report_copilot_event(Some(completion.uuid.clone()), true, cx) + // } + // cx.emit(Event::InputHandled { + // utf16_range_to_replace: None, + // text: suggestion.text.to_string().into(), + // }); + // self.insert_with_autoindent_mode(&suggestion.text.to_string(), None, cx); + // cx.notify(); + // true + // } else { + // false + // } + // } + + // fn discard_copilot_suggestion(&mut self, cx: &mut ViewContext) -> bool { + // if let Some(suggestion) = self.take_active_copilot_suggestion(cx) { + // if let Some(copilot) = Copilot::global(cx) { + // copilot + // .update(cx, |copilot, cx| { + // copilot.discard_completions(&self.copilot_state.completions, cx) + // }) + // .detach_and_log_err(cx); + + // self.report_copilot_event(None, false, cx) + // } + + // self.display_map.update(cx, |map, cx| { + // map.splice_inlays(vec![suggestion.id], Vec::new(), cx) + // }); + // cx.notify(); + // true + // } else { + // false + // } + // } + + // fn is_copilot_enabled_at( + // &self, + // location: Anchor, + // snapshot: &MultiBufferSnapshot, + // cx: &mut ViewContext, + // ) -> bool { + // let file = snapshot.file_at(location); + // let language = snapshot.language_at(location); + // let settings = all_language_settings(file, cx); + // settings.copilot_enabled(language, file.map(|f| f.path().as_ref())) + // } + + // fn has_active_copilot_suggestion(&self, cx: &AppContext) -> bool { + // if let Some(suggestion) = self.copilot_state.suggestion.as_ref() { + // let buffer = self.buffer.read(cx).read(cx); + // suggestion.position.is_valid(&buffer) + // } else { + // false + // } + // } + + // fn take_active_copilot_suggestion(&mut self, cx: &mut ViewContext) -> Option { + // let suggestion = self.copilot_state.suggestion.take()?; + // self.display_map.update(cx, |map, cx| { + // map.splice_inlays(vec![suggestion.id], Default::default(), cx); + // }); + // let buffer = self.buffer.read(cx).read(cx); + + // if suggestion.position.is_valid(&buffer) { + // Some(suggestion) + // } else { + // None + // } + // } + + // fn update_visible_copilot_suggestion(&mut self, cx: &mut ViewContext) { + // let snapshot = self.buffer.read(cx).snapshot(cx); + // let selection = self.selections.newest_anchor(); + // let cursor = selection.head(); + + // if self.context_menu.read().is_some() + // || !self.completion_tasks.is_empty() + // || selection.start != selection.end + // { + // self.discard_copilot_suggestion(cx); + // } else if let Some(text) = self + // .copilot_state + // .text_for_active_completion(cursor, &snapshot) + // { + // let text = Rope::from(text); + // let mut to_remove = Vec::new(); + // if let Some(suggestion) = self.copilot_state.suggestion.take() { + // to_remove.push(suggestion.id); + // } + + // let suggestion_inlay = + // Inlay::suggestion(post_inc(&mut self.next_inlay_id), cursor, text); + // self.copilot_state.suggestion = Some(suggestion_inlay.clone()); + // self.display_map.update(cx, move |map, cx| { + // map.splice_inlays(to_remove, vec![suggestion_inlay], cx) + // }); + // cx.notify(); + // } else { + // self.discard_copilot_suggestion(cx); + // } + // } + + // fn clear_copilot_suggestions(&mut self, cx: &mut ViewContext) { + // self.copilot_state = Default::default(); + // self.discard_copilot_suggestion(cx); + // } + + // pub fn render_code_actions_indicator( + // &self, + // style: &EditorStyle, + // is_active: bool, + // cx: &mut ViewContext, + // ) -> Option> { + // if self.available_code_actions.is_some() { + // enum CodeActions {} + // Some( + // MouseEventHandler::new::(0, cx, |state, _| { + // Svg::new("icons/bolt.svg").with_color( + // style + // .code_actions + // .indicator + // .in_state(is_active) + // .style_for(state) + // .color, + // ) + // }) + // .with_cursor_style(CursorStyle::PointingHand) + // .with_padding(Padding::uniform(3.)) + // .on_down(MouseButton::Left, |_, this, cx| { + // this.toggle_code_actions( + // &ToggleCodeActions { + // deployed_from_indicator: true, + // }, + // cx, + // ); + // }) + // .into_any(), + // ) + // } else { + // None + // } + // } + + // pub fn render_fold_indicators( + // &self, + // fold_data: Vec>, + // style: &EditorStyle, + // gutter_hovered: bool, + // line_height: f32, + // gutter_margin: f32, + // cx: &mut ViewContext, + // ) -> Vec>> { + // enum FoldIndicators {} + + // let style = style.folds.clone(); + + // fold_data + // .iter() + // .enumerate() + // .map(|(ix, fold_data)| { + // fold_data + // .map(|(fold_status, buffer_row, active)| { + // (active || gutter_hovered || fold_status == FoldStatus::Folded).then(|| { + // MouseEventHandler::new::( + // ix as usize, + // cx, + // |mouse_state, _| { + // Svg::new(match fold_status { + // FoldStatus::Folded => style.folded_icon.clone(), + // FoldStatus::Foldable => style.foldable_icon.clone(), + // }) + // .with_color( + // style + // .indicator + // .in_state(fold_status == FoldStatus::Folded) + // .style_for(mouse_state) + // .color, + // ) + // .constrained() + // .with_width(gutter_margin * style.icon_margin_scale) + // .aligned() + // .constrained() + // .with_height(line_height) + // .with_width(gutter_margin) + // .aligned() + // }, + // ) + // .with_cursor_style(CursorStyle::PointingHand) + // .with_padding(Padding::uniform(3.)) + // .on_click(MouseButton::Left, { + // move |_, editor, cx| match fold_status { + // FoldStatus::Folded => { + // editor.unfold_at(&UnfoldAt { buffer_row }, cx); + // } + // FoldStatus::Foldable => { + // editor.fold_at(&FoldAt { buffer_row }, cx); + // } + // } + // }) + // .into_any() + // }) + // }) + // .flatten() + // }) + // .collect() + // } + + // pub fn context_menu_visible(&self) -> bool { + // self.context_menu + // .read() + // .as_ref() + // .map_or(false, |menu| menu.visible()) + // } + + // pub fn render_context_menu( + // &self, + // cursor_position: DisplayPoint, + // style: EditorStyle, + // cx: &mut ViewContext, + // ) -> Option<(DisplayPoint, AnyElement)> { + // self.context_menu.read().as_ref().map(|menu| { + // menu.render( + // cursor_position, + // style, + // self.workspace.as_ref().map(|(w, _)| w.clone()), + // cx, + // ) + // }) + // } + + // fn hide_context_menu(&mut self, cx: &mut ViewContext) -> Option { + // cx.notify(); + // self.completion_tasks.clear(); + // let context_menu = self.context_menu.write().take(); + // if context_menu.is_some() { + // self.update_visible_copilot_suggestion(cx); + // } + // context_menu + // } + + // pub fn insert_snippet( + // &mut self, + // insertion_ranges: &[Range], + // snippet: Snippet, + // cx: &mut ViewContext, + // ) -> Result<()> { + // let tabstops = self.buffer.update(cx, |buffer, cx| { + // let snippet_text: Arc = snippet.text.clone().into(); + // buffer.edit( + // insertion_ranges + // .iter() + // .cloned() + // .map(|range| (range, snippet_text.clone())), + // Some(AutoindentMode::EachLine), + // cx, + // ); + + // let snapshot = &*buffer.read(cx); + // let snippet = &snippet; + // snippet + // .tabstops + // .iter() + // .map(|tabstop| { + // let mut tabstop_ranges = tabstop + // .iter() + // .flat_map(|tabstop_range| { + // let mut delta = 0_isize; + // insertion_ranges.iter().map(move |insertion_range| { + // let insertion_start = insertion_range.start as isize + delta; + // delta += + // snippet.text.len() as isize - insertion_range.len() as isize; + + // let start = snapshot.anchor_before( + // (insertion_start + tabstop_range.start) as usize, + // ); + // let end = snapshot + // .anchor_after((insertion_start + tabstop_range.end) as usize); + // start..end + // }) + // }) + // .collect::>(); + // tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot)); + // tabstop_ranges + // }) + // .collect::>() + // }); + + // if let Some(tabstop) = tabstops.first() { + // self.change_selections(Some(Autoscroll::fit()), cx, |s| { + // s.select_ranges(tabstop.iter().cloned()); + // }); + // self.snippet_stack.push(SnippetState { + // active_index: 0, + // ranges: tabstops, + // }); + // } + + // Ok(()) + // } + + // pub fn move_to_next_snippet_tabstop(&mut self, cx: &mut ViewContext) -> bool { + // self.move_to_snippet_tabstop(Bias::Right, cx) + // } + + // pub fn move_to_prev_snippet_tabstop(&mut self, cx: &mut ViewContext) -> bool { + // self.move_to_snippet_tabstop(Bias::Left, cx) + // } + + // pub fn move_to_snippet_tabstop(&mut self, bias: Bias, cx: &mut ViewContext) -> bool { + // if let Some(mut snippet) = self.snippet_stack.pop() { + // match bias { + // Bias::Left => { + // if snippet.active_index > 0 { + // snippet.active_index -= 1; + // } else { + // self.snippet_stack.push(snippet); + // return false; + // } + // } + // Bias::Right => { + // if snippet.active_index + 1 < snippet.ranges.len() { + // snippet.active_index += 1; + // } else { + // self.snippet_stack.push(snippet); + // return false; + // } + // } + // } + // if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) { + // self.change_selections(Some(Autoscroll::fit()), cx, |s| { + // s.select_anchor_ranges(current_ranges.iter().cloned()) + // }); + // // If snippet state is not at the last tabstop, push it back on the stack + // if snippet.active_index + 1 < snippet.ranges.len() { + // self.snippet_stack.push(snippet); + // } + // return true; + // } + // } + + // false + // } + + // pub fn clear(&mut self, cx: &mut ViewContext) { + // self.transact(cx, |this, cx| { + // this.select_all(&SelectAll, cx); + // this.insert("", cx); + // }); + // } + + // pub fn backspace(&mut self, _: &Backspace, cx: &mut ViewContext) { + // self.transact(cx, |this, cx| { + // this.select_autoclose_pair(cx); + // let mut selections = this.selections.all::(cx); + // if !this.selections.line_mode { + // let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx)); + // for selection in &mut selections { + // if selection.is_empty() { + // let old_head = selection.head(); + // let mut new_head = + // movement::left(&display_map, old_head.to_display_point(&display_map)) + // .to_point(&display_map); + // if let Some((buffer, line_buffer_range)) = display_map + // .buffer_snapshot + // .buffer_line_for_row(old_head.row) + // { + // let indent_size = + // buffer.indent_size_for_line(line_buffer_range.start.row); + // let indent_len = match indent_size.kind { + // IndentKind::Space => { + // buffer.settings_at(line_buffer_range.start, cx).tab_size + // } + // IndentKind::Tab => NonZeroU32::new(1).unwrap(), + // }; + // if old_head.column <= indent_size.len && old_head.column > 0 { + // let indent_len = indent_len.get(); + // new_head = cmp::min( + // new_head, + // Point::new( + // old_head.row, + // ((old_head.column - 1) / indent_len) * indent_len, + // ), + // ); + // } + // } + + // selection.set_head(new_head, SelectionGoal::None); + // } + // } + // } + + // this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections)); + // this.insert("", cx); + // this.refresh_copilot_suggestions(true, cx); + // }); + // } + + // pub fn delete(&mut self, _: &Delete, cx: &mut ViewContext) { + // self.transact(cx, |this, cx| { + // this.change_selections(Some(Autoscroll::fit()), cx, |s| { + // let line_mode = s.line_mode; + // s.move_with(|map, selection| { + // if selection.is_empty() && !line_mode { + // let cursor = movement::right(map, selection.head()); + // selection.end = cursor; + // selection.reversed = true; + // selection.goal = SelectionGoal::None; + // } + // }) + // }); + // this.insert("", cx); + // this.refresh_copilot_suggestions(true, cx); + // }); + // } + + // pub fn tab_prev(&mut self, _: &TabPrev, cx: &mut ViewContext) { + // if self.move_to_prev_snippet_tabstop(cx) { + // return; + // } + + // self.outdent(&Outdent, cx); + // } + + // pub fn tab(&mut self, _: &Tab, cx: &mut ViewContext) { + // if self.move_to_next_snippet_tabstop(cx) { + // return; + // } + + // let mut selections = self.selections.all_adjusted(cx); + // let buffer = self.buffer.read(cx); + // let snapshot = buffer.snapshot(cx); + // let rows_iter = selections.iter().map(|s| s.head().row); + // let suggested_indents = snapshot.suggested_indents(rows_iter, cx); + + // let mut edits = Vec::new(); + // let mut prev_edited_row = 0; + // let mut row_delta = 0; + // for selection in &mut selections { + // if selection.start.row != prev_edited_row { + // row_delta = 0; + // } + // prev_edited_row = selection.end.row; + + // // If the selection is non-empty, then increase the indentation of the selected lines. + // if !selection.is_empty() { + // row_delta = + // Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx); + // continue; + // } + + // // If the selection is empty and the cursor is in the leading whitespace before the + // // suggested indentation, then auto-indent the line. + // let cursor = selection.head(); + // let current_indent = snapshot.indent_size_for_line(cursor.row); + // if let Some(suggested_indent) = suggested_indents.get(&cursor.row).copied() { + // if cursor.column < suggested_indent.len + // && cursor.column <= current_indent.len + // && current_indent.len <= suggested_indent.len + // { + // selection.start = Point::new(cursor.row, suggested_indent.len); + // selection.end = selection.start; + // if row_delta == 0 { + // edits.extend(Buffer::edit_for_indent_size_adjustment( + // cursor.row, + // current_indent, + // suggested_indent, + // )); + // row_delta = suggested_indent.len - current_indent.len; + // } + // continue; + // } + // } + + // // Accept copilot suggestion if there is only one selection and the cursor is not + // // in the leading whitespace. + // if self.selections.count() == 1 + // && cursor.column >= current_indent.len + // && self.has_active_copilot_suggestion(cx) + // { + // self.accept_copilot_suggestion(cx); + // return; + // } + + // // Otherwise, insert a hard or soft tab. + // let settings = buffer.settings_at(cursor, cx); + // let tab_size = if settings.hard_tabs { + // IndentSize::tab() + // } else { + // let tab_size = settings.tab_size.get(); + // let char_column = snapshot + // .text_for_range(Point::new(cursor.row, 0)..cursor) + // .flat_map(str::chars) + // .count() + // + row_delta as usize; + // let chars_to_next_tab_stop = tab_size - (char_column as u32 % tab_size); + // IndentSize::spaces(chars_to_next_tab_stop) + // }; + // selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len); + // selection.end = selection.start; + // edits.push((cursor..cursor, tab_size.chars().collect::())); + // row_delta += tab_size.len; + // } + + // self.transact(cx, |this, cx| { + // this.buffer.update(cx, |b, cx| b.edit(edits, None, cx)); + // this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections)); + // this.refresh_copilot_suggestions(true, cx); + // }); + // } + + // pub fn indent(&mut self, _: &Indent, cx: &mut ViewContext) { + // let mut selections = self.selections.all::(cx); + // let mut prev_edited_row = 0; + // let mut row_delta = 0; + // let mut edits = Vec::new(); + // let buffer = self.buffer.read(cx); + // let snapshot = buffer.snapshot(cx); + // for selection in &mut selections { + // if selection.start.row != prev_edited_row { + // row_delta = 0; + // } + // prev_edited_row = selection.end.row; + + // row_delta = + // Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx); + // } + + // self.transact(cx, |this, cx| { + // this.buffer.update(cx, |b, cx| b.edit(edits, None, cx)); + // this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections)); + // }); + // } + + // fn indent_selection( + // buffer: &MultiBuffer, + // snapshot: &MultiBufferSnapshot, + // selection: &mut Selection, + // edits: &mut Vec<(Range, String)>, + // delta_for_start_row: u32, + // cx: &AppContext, + // ) -> u32 { + // let settings = buffer.settings_at(selection.start, cx); + // let tab_size = settings.tab_size.get(); + // let indent_kind = if settings.hard_tabs { + // IndentKind::Tab + // } else { + // IndentKind::Space + // }; + // let mut start_row = selection.start.row; + // let mut end_row = selection.end.row + 1; + + // // If a selection ends at the beginning of a line, don't indent + // // that last line. + // if selection.end.column == 0 { + // end_row -= 1; + // } + + // // Avoid re-indenting a row that has already been indented by a + // // previous selection, but still update this selection's column + // // to reflect that indentation. + // if delta_for_start_row > 0 { + // start_row += 1; + // selection.start.column += delta_for_start_row; + // if selection.end.row == selection.start.row { + // selection.end.column += delta_for_start_row; + // } + // } + + // let mut delta_for_end_row = 0; + // for row in start_row..end_row { + // let current_indent = snapshot.indent_size_for_line(row); + // let indent_delta = match (current_indent.kind, indent_kind) { + // (IndentKind::Space, IndentKind::Space) => { + // let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size); + // IndentSize::spaces(columns_to_next_tab_stop) + // } + // (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size), + // (_, IndentKind::Tab) => IndentSize::tab(), + // }; + + // let row_start = Point::new(row, 0); + // edits.push(( + // row_start..row_start, + // indent_delta.chars().collect::(), + // )); + + // // Update this selection's endpoints to reflect the indentation. + // if row == selection.start.row { + // selection.start.column += indent_delta.len; + // } + // if row == selection.end.row { + // selection.end.column += indent_delta.len; + // delta_for_end_row = indent_delta.len; + // } + // } + + // if selection.start.row == selection.end.row { + // delta_for_start_row + delta_for_end_row + // } else { + // delta_for_end_row + // } + // } + + // pub fn outdent(&mut self, _: &Outdent, cx: &mut ViewContext) { + // let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); + // let selections = self.selections.all::(cx); + // let mut deletion_ranges = Vec::new(); + // let mut last_outdent = None; + // { + // let buffer = self.buffer.read(cx); + // let snapshot = buffer.snapshot(cx); + // for selection in &selections { + // let settings = buffer.settings_at(selection.start, cx); + // let tab_size = settings.tab_size.get(); + // let mut rows = selection.spanned_rows(false, &display_map); + + // // Avoid re-outdenting a row that has already been outdented by a + // // previous selection. + // if let Some(last_row) = last_outdent { + // if last_row == rows.start { + // rows.start += 1; + // } + // } + + // for row in rows { + // let indent_size = snapshot.indent_size_for_line(row); + // if indent_size.len > 0 { + // let deletion_len = match indent_size.kind { + // IndentKind::Space => { + // let columns_to_prev_tab_stop = indent_size.len % tab_size; + // if columns_to_prev_tab_stop == 0 { + // tab_size + // } else { + // columns_to_prev_tab_stop + // } + // } + // IndentKind::Tab => 1, + // }; + // deletion_ranges.push(Point::new(row, 0)..Point::new(row, deletion_len)); + // last_outdent = Some(row); + // } + // } + // } + // } + + // self.transact(cx, |this, cx| { + // this.buffer.update(cx, |buffer, cx| { + // let empty_str: Arc = "".into(); + // buffer.edit( + // deletion_ranges + // .into_iter() + // .map(|range| (range, empty_str.clone())), + // None, + // cx, + // ); + // }); + // let selections = this.selections.all::(cx); + // this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections)); + // }); + // } + + // pub fn delete_line(&mut self, _: &DeleteLine, cx: &mut ViewContext) { + // let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); + // let selections = self.selections.all::(cx); + + // let mut new_cursors = Vec::new(); + // let mut edit_ranges = Vec::new(); + // let mut selections = selections.iter().peekable(); + // while let Some(selection) = selections.next() { + // let mut rows = selection.spanned_rows(false, &display_map); + // let goal_display_column = selection.head().to_display_point(&display_map).column(); + + // // Accumulate contiguous regions of rows that we want to delete. + // while let Some(next_selection) = selections.peek() { + // let next_rows = next_selection.spanned_rows(false, &display_map); + // if next_rows.start <= rows.end { + // rows.end = next_rows.end; + // selections.next().unwrap(); + // } else { + // break; + // } + // } + + // let buffer = &display_map.buffer_snapshot; + // let mut edit_start = Point::new(rows.start, 0).to_offset(buffer); + // let edit_end; + // let cursor_buffer_row; + // if buffer.max_point().row >= rows.end { + // // If there's a line after the range, delete the \n from the end of the row range + // // and position the cursor on the next line. + // edit_end = Point::new(rows.end, 0).to_offset(buffer); + // cursor_buffer_row = rows.end; + // } else { + // // If there isn't a line after the range, delete the \n from the line before the + // // start of the row range and position the cursor there. + // edit_start = edit_start.saturating_sub(1); + // edit_end = buffer.len(); + // cursor_buffer_row = rows.start.saturating_sub(1); + // } + + // let mut cursor = Point::new(cursor_buffer_row, 0).to_display_point(&display_map); + // *cursor.column_mut() = + // cmp::min(goal_display_column, display_map.line_len(cursor.row())); + + // new_cursors.push(( + // selection.id, + // buffer.anchor_after(cursor.to_point(&display_map)), + // )); + // edit_ranges.push(edit_start..edit_end); + // } + + // self.transact(cx, |this, cx| { + // let buffer = this.buffer.update(cx, |buffer, cx| { + // let empty_str: Arc = "".into(); + // buffer.edit( + // edit_ranges + // .into_iter() + // .map(|range| (range, empty_str.clone())), + // None, + // cx, + // ); + // buffer.snapshot(cx) + // }); + // let new_selections = new_cursors + // .into_iter() + // .map(|(id, cursor)| { + // let cursor = cursor.to_point(&buffer); + // Selection { + // id, + // start: cursor, + // end: cursor, + // reversed: false, + // goal: SelectionGoal::None, + // } + // }) + // .collect(); + + // this.change_selections(Some(Autoscroll::fit()), cx, |s| { + // s.select(new_selections); + // }); + // }); + // } + + // pub fn join_lines(&mut self, _: &JoinLines, cx: &mut ViewContext) { + // let mut row_ranges = Vec::>::new(); + // for selection in self.selections.all::(cx) { + // let start = selection.start.row; + // let end = if selection.start.row == selection.end.row { + // selection.start.row + 1 + // } else { + // selection.end.row + // }; + + // if let Some(last_row_range) = row_ranges.last_mut() { + // if start <= last_row_range.end { + // last_row_range.end = end; + // continue; + // } + // } + // row_ranges.push(start..end); + // } + + // let snapshot = self.buffer.read(cx).snapshot(cx); + // let mut cursor_positions = Vec::new(); + // for row_range in &row_ranges { + // let anchor = snapshot.anchor_before(Point::new( + // row_range.end - 1, + // snapshot.line_len(row_range.end - 1), + // )); + // cursor_positions.push(anchor.clone()..anchor); + // } + + // self.transact(cx, |this, cx| { + // for row_range in row_ranges.into_iter().rev() { + // for row in row_range.rev() { + // let end_of_line = Point::new(row, snapshot.line_len(row)); + // let indent = snapshot.indent_size_for_line(row + 1); + // let start_of_next_line = Point::new(row + 1, indent.len); + + // let replace = if snapshot.line_len(row + 1) > indent.len { + // " " + // } else { + // "" + // }; + + // this.buffer.update(cx, |buffer, cx| { + // buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx) + // }); + // } + // } + + // this.change_selections(Some(Autoscroll::fit()), cx, |s| { + // s.select_anchor_ranges(cursor_positions) + // }); + // }); + // } + + // pub fn sort_lines_case_sensitive( + // &mut self, + // _: &SortLinesCaseSensitive, + // cx: &mut ViewContext, + // ) { + // self.manipulate_lines(cx, |lines| lines.sort()) + // } + + // pub fn sort_lines_case_insensitive( + // &mut self, + // _: &SortLinesCaseInsensitive, + // cx: &mut ViewContext, + // ) { + // self.manipulate_lines(cx, |lines| lines.sort_by_key(|line| line.to_lowercase())) + // } + + // pub fn reverse_lines(&mut self, _: &ReverseLines, cx: &mut ViewContext) { + // self.manipulate_lines(cx, |lines| lines.reverse()) + // } + + // pub fn shuffle_lines(&mut self, _: &ShuffleLines, cx: &mut ViewContext) { + // self.manipulate_lines(cx, |lines| lines.shuffle(&mut thread_rng())) + // } + + // fn manipulate_lines(&mut self, cx: &mut ViewContext, mut callback: Fn) + // where + // Fn: FnMut(&mut [&str]), + // { + // let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); + // let buffer = self.buffer.read(cx).snapshot(cx); + + // let mut edits = Vec::new(); + + // let selections = self.selections.all::(cx); + // let mut selections = selections.iter().peekable(); + // let mut contiguous_row_selections = Vec::new(); + // let mut new_selections = Vec::new(); + + // while let Some(selection) = selections.next() { + // let (start_row, end_row) = consume_contiguous_rows( + // &mut contiguous_row_selections, + // selection, + // &display_map, + // &mut selections, + // ); + + // let start_point = Point::new(start_row, 0); + // let end_point = Point::new(end_row - 1, buffer.line_len(end_row - 1)); + // let text = buffer + // .text_for_range(start_point..end_point) + // .collect::(); + // let mut lines = text.split("\n").collect_vec(); + + // let lines_len = lines.len(); + // callback(&mut lines); + + // // This is a current limitation with selections. + // // If we wanted to support removing or adding lines, we'd need to fix the logic associated with selections. + // debug_assert!( + // lines.len() == lines_len, + // "callback should not change the number of lines" + // ); + + // edits.push((start_point..end_point, lines.join("\n"))); + // let start_anchor = buffer.anchor_after(start_point); + // let end_anchor = buffer.anchor_before(end_point); + + // // Make selection and push + // new_selections.push(Selection { + // id: selection.id, + // start: start_anchor.to_offset(&buffer), + // end: end_anchor.to_offset(&buffer), + // goal: SelectionGoal::None, + // reversed: selection.reversed, + // }); + // } + + // self.transact(cx, |this, cx| { + // this.buffer.update(cx, |buffer, cx| { + // buffer.edit(edits, None, cx); + // }); + + // this.change_selections(Some(Autoscroll::fit()), cx, |s| { + // s.select(new_selections); + // }); + + // this.request_autoscroll(Autoscroll::fit(), cx); + // }); + // } + + // pub fn convert_to_upper_case(&mut self, _: &ConvertToUpperCase, cx: &mut ViewContext) { + // self.manipulate_text(cx, |text| text.to_uppercase()) + // } + + // pub fn convert_to_lower_case(&mut self, _: &ConvertToLowerCase, cx: &mut ViewContext) { + // self.manipulate_text(cx, |text| text.to_lowercase()) + // } + + // pub fn convert_to_title_case(&mut self, _: &ConvertToTitleCase, cx: &mut ViewContext) { + // self.manipulate_text(cx, |text| { + // // Hack to get around the fact that to_case crate doesn't support '\n' as a word boundary + // // https://github.com/rutrum/convert-case/issues/16 + // text.split("\n") + // .map(|line| line.to_case(Case::Title)) + // .join("\n") + // }) + // } + + // pub fn convert_to_snake_case(&mut self, _: &ConvertToSnakeCase, cx: &mut ViewContext) { + // self.manipulate_text(cx, |text| text.to_case(Case::Snake)) + // } + + // pub fn convert_to_kebab_case(&mut self, _: &ConvertToKebabCase, cx: &mut ViewContext) { + // self.manipulate_text(cx, |text| text.to_case(Case::Kebab)) + // } + + // pub fn convert_to_upper_camel_case( + // &mut self, + // _: &ConvertToUpperCamelCase, + // cx: &mut ViewContext, + // ) { + // self.manipulate_text(cx, |text| { + // // Hack to get around the fact that to_case crate doesn't support '\n' as a word boundary + // // https://github.com/rutrum/convert-case/issues/16 + // text.split("\n") + // .map(|line| line.to_case(Case::UpperCamel)) + // .join("\n") + // }) + // } + + // pub fn convert_to_lower_camel_case( + // &mut self, + // _: &ConvertToLowerCamelCase, + // cx: &mut ViewContext, + // ) { + // self.manipulate_text(cx, |text| text.to_case(Case::Camel)) + // } + + // fn manipulate_text(&mut self, cx: &mut ViewContext, mut callback: Fn) + // where + // Fn: FnMut(&str) -> String, + // { + // let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); + // let buffer = self.buffer.read(cx).snapshot(cx); + + // let mut new_selections = Vec::new(); + // let mut edits = Vec::new(); + // let mut selection_adjustment = 0i32; + + // for selection in self.selections.all::(cx) { + // let selection_is_empty = selection.is_empty(); + + // let (start, end) = if selection_is_empty { + // let word_range = movement::surrounding_word( + // &display_map, + // selection.start.to_display_point(&display_map), + // ); + // let start = word_range.start.to_offset(&display_map, Bias::Left); + // let end = word_range.end.to_offset(&display_map, Bias::Left); + // (start, end) + // } else { + // (selection.start, selection.end) + // }; + + // let text = buffer.text_for_range(start..end).collect::(); + // let old_length = text.len() as i32; + // let text = callback(&text); + + // new_selections.push(Selection { + // start: (start as i32 - selection_adjustment) as usize, + // end: ((start + text.len()) as i32 - selection_adjustment) as usize, + // goal: SelectionGoal::None, + // ..selection + // }); + + // selection_adjustment += old_length - text.len() as i32; + + // edits.push((start..end, text)); + // } + + // self.transact(cx, |this, cx| { + // this.buffer.update(cx, |buffer, cx| { + // buffer.edit(edits, None, cx); + // }); + + // this.change_selections(Some(Autoscroll::fit()), cx, |s| { + // s.select(new_selections); + // }); + + // this.request_autoscroll(Autoscroll::fit(), cx); + // }); + // } + + // pub fn duplicate_line(&mut self, _: &DuplicateLine, cx: &mut ViewContext) { + // let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); + // let buffer = &display_map.buffer_snapshot; + // let selections = self.selections.all::(cx); + + // let mut edits = Vec::new(); + // let mut selections_iter = selections.iter().peekable(); + // while let Some(selection) = selections_iter.next() { + // // Avoid duplicating the same lines twice. + // let mut rows = selection.spanned_rows(false, &display_map); + + // while let Some(next_selection) = selections_iter.peek() { + // let next_rows = next_selection.spanned_rows(false, &display_map); + // if next_rows.start < rows.end { + // rows.end = next_rows.end; + // selections_iter.next().unwrap(); + // } else { + // break; + // } + // } + + // // Copy the text from the selected row region and splice it at the start of the region. + // let start = Point::new(rows.start, 0); + // let end = Point::new(rows.end - 1, buffer.line_len(rows.end - 1)); + // let text = buffer + // .text_for_range(start..end) + // .chain(Some("\n")) + // .collect::(); + // edits.push((start..start, text)); + // } + + // self.transact(cx, |this, cx| { + // this.buffer.update(cx, |buffer, cx| { + // buffer.edit(edits, None, cx); + // }); + + // this.request_autoscroll(Autoscroll::fit(), cx); + // }); + // } + + // pub fn move_line_up(&mut self, _: &MoveLineUp, cx: &mut ViewContext) { + // let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); + // let buffer = self.buffer.read(cx).snapshot(cx); + + // let mut edits = Vec::new(); + // let mut unfold_ranges = Vec::new(); + // let mut refold_ranges = Vec::new(); + + // let selections = self.selections.all::(cx); + // let mut selections = selections.iter().peekable(); + // let mut contiguous_row_selections = Vec::new(); + // let mut new_selections = Vec::new(); + + // while let Some(selection) = selections.next() { + // // Find all the selections that span a contiguous row range + // let (start_row, end_row) = consume_contiguous_rows( + // &mut contiguous_row_selections, + // selection, + // &display_map, + // &mut selections, + // ); + + // // Move the text spanned by the row range to be before the line preceding the row range + // if start_row > 0 { + // let range_to_move = Point::new(start_row - 1, buffer.line_len(start_row - 1)) + // ..Point::new(end_row - 1, buffer.line_len(end_row - 1)); + // let insertion_point = display_map + // .prev_line_boundary(Point::new(start_row - 1, 0)) + // .0; + + // // Don't move lines across excerpts + // if buffer + // .excerpt_boundaries_in_range(( + // Bound::Excluded(insertion_point), + // Bound::Included(range_to_move.end), + // )) + // .next() + // .is_none() + // { + // let text = buffer + // .text_for_range(range_to_move.clone()) + // .flat_map(|s| s.chars()) + // .skip(1) + // .chain(['\n']) + // .collect::(); + + // edits.push(( + // buffer.anchor_after(range_to_move.start) + // ..buffer.anchor_before(range_to_move.end), + // String::new(), + // )); + // let insertion_anchor = buffer.anchor_after(insertion_point); + // edits.push((insertion_anchor..insertion_anchor, text)); + + // let row_delta = range_to_move.start.row - insertion_point.row + 1; + + // // Move selections up + // new_selections.extend(contiguous_row_selections.drain(..).map( + // |mut selection| { + // selection.start.row -= row_delta; + // selection.end.row -= row_delta; + // selection + // }, + // )); + + // // Move folds up + // unfold_ranges.push(range_to_move.clone()); + // for fold in display_map.folds_in_range( + // buffer.anchor_before(range_to_move.start) + // ..buffer.anchor_after(range_to_move.end), + // ) { + // let mut start = fold.start.to_point(&buffer); + // let mut end = fold.end.to_point(&buffer); + // start.row -= row_delta; + // end.row -= row_delta; + // refold_ranges.push(start..end); + // } + // } + // } + + // // If we didn't move line(s), preserve the existing selections + // new_selections.append(&mut contiguous_row_selections); + // } + + // self.transact(cx, |this, cx| { + // this.unfold_ranges(unfold_ranges, true, true, cx); + // this.buffer.update(cx, |buffer, cx| { + // for (range, text) in edits { + // buffer.edit([(range, text)], None, cx); + // } + // }); + // this.fold_ranges(refold_ranges, true, cx); + // this.change_selections(Some(Autoscroll::fit()), cx, |s| { + // s.select(new_selections); + // }) + // }); + // } + + // pub fn move_line_down(&mut self, _: &MoveLineDown, cx: &mut ViewContext) { + // let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); + // let buffer = self.buffer.read(cx).snapshot(cx); + + // let mut edits = Vec::new(); + // let mut unfold_ranges = Vec::new(); + // let mut refold_ranges = Vec::new(); + + // let selections = self.selections.all::(cx); + // let mut selections = selections.iter().peekable(); + // let mut contiguous_row_selections = Vec::new(); + // let mut new_selections = Vec::new(); + + // while let Some(selection) = selections.next() { + // // Find all the selections that span a contiguous row range + // let (start_row, end_row) = consume_contiguous_rows( + // &mut contiguous_row_selections, + // selection, + // &display_map, + // &mut selections, + // ); + + // // Move the text spanned by the row range to be after the last line of the row range + // if end_row <= buffer.max_point().row { + // let range_to_move = Point::new(start_row, 0)..Point::new(end_row, 0); + // let insertion_point = display_map.next_line_boundary(Point::new(end_row, 0)).0; + + // // Don't move lines across excerpt boundaries + // if buffer + // .excerpt_boundaries_in_range(( + // Bound::Excluded(range_to_move.start), + // Bound::Included(insertion_point), + // )) + // .next() + // .is_none() + // { + // let mut text = String::from("\n"); + // text.extend(buffer.text_for_range(range_to_move.clone())); + // text.pop(); // Drop trailing newline + // edits.push(( + // buffer.anchor_after(range_to_move.start) + // ..buffer.anchor_before(range_to_move.end), + // String::new(), + // )); + // let insertion_anchor = buffer.anchor_after(insertion_point); + // edits.push((insertion_anchor..insertion_anchor, text)); + + // let row_delta = insertion_point.row - range_to_move.end.row + 1; + + // // Move selections down + // new_selections.extend(contiguous_row_selections.drain(..).map( + // |mut selection| { + // selection.start.row += row_delta; + // selection.end.row += row_delta; + // selection + // }, + // )); + + // // Move folds down + // unfold_ranges.push(range_to_move.clone()); + // for fold in display_map.folds_in_range( + // buffer.anchor_before(range_to_move.start) + // ..buffer.anchor_after(range_to_move.end), + // ) { + // let mut start = fold.start.to_point(&buffer); + // let mut end = fold.end.to_point(&buffer); + // start.row += row_delta; + // end.row += row_delta; + // refold_ranges.push(start..end); + // } + // } + // } + + // // If we didn't move line(s), preserve the existing selections + // new_selections.append(&mut contiguous_row_selections); + // } + + // self.transact(cx, |this, cx| { + // this.unfold_ranges(unfold_ranges, true, true, cx); + // this.buffer.update(cx, |buffer, cx| { + // for (range, text) in edits { + // buffer.edit([(range, text)], None, cx); + // } + // }); + // this.fold_ranges(refold_ranges, true, cx); + // this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(new_selections)); + // }); + // } + + // pub fn transpose(&mut self, _: &Transpose, cx: &mut ViewContext) { + // let text_layout_details = &self.text_layout_details(cx); + // self.transact(cx, |this, cx| { + // let edits = this.change_selections(Some(Autoscroll::fit()), cx, |s| { + // let mut edits: Vec<(Range, String)> = Default::default(); + // let line_mode = s.line_mode; + // s.move_with(|display_map, selection| { + // if !selection.is_empty() || line_mode { + // return; + // } + + // let mut head = selection.head(); + // let mut transpose_offset = head.to_offset(display_map, Bias::Right); + // if head.column() == display_map.line_len(head.row()) { + // transpose_offset = display_map + // .buffer_snapshot + // .clip_offset(transpose_offset.saturating_sub(1), Bias::Left); + // } + + // if transpose_offset == 0 { + // return; + // } + + // *head.column_mut() += 1; + // head = display_map.clip_point(head, Bias::Right); + // let goal = SelectionGoal::HorizontalPosition( + // display_map.x_for_point(head, &text_layout_details), + // ); + // selection.collapse_to(head, goal); + + // let transpose_start = display_map + // .buffer_snapshot + // .clip_offset(transpose_offset.saturating_sub(1), Bias::Left); + // if edits.last().map_or(true, |e| e.0.end <= transpose_start) { + // let transpose_end = display_map + // .buffer_snapshot + // .clip_offset(transpose_offset + 1, Bias::Right); + // if let Some(ch) = + // display_map.buffer_snapshot.chars_at(transpose_start).next() + // { + // edits.push((transpose_start..transpose_offset, String::new())); + // edits.push((transpose_end..transpose_end, ch.to_string())); + // } + // } + // }); + // edits + // }); + // this.buffer + // .update(cx, |buffer, cx| buffer.edit(edits, None, cx)); + // let selections = this.selections.all::(cx); + // this.change_selections(Some(Autoscroll::fit()), cx, |s| { + // s.select(selections); + // }); + // }); + // } + + // pub fn cut(&mut self, _: &Cut, cx: &mut ViewContext) { + // let mut text = String::new(); + // let buffer = self.buffer.read(cx).snapshot(cx); + // let mut selections = self.selections.all::(cx); + // let mut clipboard_selections = Vec::with_capacity(selections.len()); + // { + // let max_point = buffer.max_point(); + // let mut is_first = true; + // for selection in &mut selections { + // let is_entire_line = selection.is_empty() || self.selections.line_mode; + // if is_entire_line { + // selection.start = Point::new(selection.start.row, 0); + // selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0)); + // selection.goal = SelectionGoal::None; + // } + // if is_first { + // is_first = false; + // } else { + // text += "\n"; + // } + // let mut len = 0; + // for chunk in buffer.text_for_range(selection.start..selection.end) { + // text.push_str(chunk); + // len += chunk.len(); + // } + // clipboard_selections.push(ClipboardSelection { + // len, + // is_entire_line, + // first_line_indent: buffer.indent_size_for_line(selection.start.row).len, + // }); + // } + // } + + // self.transact(cx, |this, cx| { + // this.change_selections(Some(Autoscroll::fit()), cx, |s| { + // s.select(selections); + // }); + // this.insert("", cx); + // cx.write_to_clipboard(ClipboardItem::new(text).with_metadata(clipboard_selections)); + // }); + // } + + // pub fn copy(&mut self, _: &Copy, cx: &mut ViewContext) { + // let selections = self.selections.all::(cx); + // let buffer = self.buffer.read(cx).read(cx); + // let mut text = String::new(); + + // let mut clipboard_selections = Vec::with_capacity(selections.len()); + // { + // let max_point = buffer.max_point(); + // let mut is_first = true; + // for selection in selections.iter() { + // let mut start = selection.start; + // let mut end = selection.end; + // let is_entire_line = selection.is_empty() || self.selections.line_mode; + // if is_entire_line { + // start = Point::new(start.row, 0); + // end = cmp::min(max_point, Point::new(end.row + 1, 0)); + // } + // if is_first { + // is_first = false; + // } else { + // text += "\n"; + // } + // let mut len = 0; + // for chunk in buffer.text_for_range(start..end) { + // text.push_str(chunk); + // len += chunk.len(); + // } + // clipboard_selections.push(ClipboardSelection { + // len, + // is_entire_line, + // first_line_indent: buffer.indent_size_for_line(start.row).len, + // }); + // } + // } + + // cx.write_to_clipboard(ClipboardItem::new(text).with_metadata(clipboard_selections)); + // } + + // pub fn paste(&mut self, _: &Paste, cx: &mut ViewContext) { + // self.transact(cx, |this, cx| { + // if let Some(item) = cx.read_from_clipboard() { + // let clipboard_text = Cow::Borrowed(item.text()); + // if let Some(mut clipboard_selections) = item.metadata::>() { + // let old_selections = this.selections.all::(cx); + // let all_selections_were_entire_line = + // clipboard_selections.iter().all(|s| s.is_entire_line); + // let first_selection_indent_column = + // clipboard_selections.first().map(|s| s.first_line_indent); + // if clipboard_selections.len() != old_selections.len() { + // clipboard_selections.drain(..); + // } + + // this.buffer.update(cx, |buffer, cx| { + // let snapshot = buffer.read(cx); + // let mut start_offset = 0; + // let mut edits = Vec::new(); + // let mut original_indent_columns = Vec::new(); + // let line_mode = this.selections.line_mode; + // for (ix, selection) in old_selections.iter().enumerate() { + // let to_insert; + // let entire_line; + // let original_indent_column; + // if let Some(clipboard_selection) = clipboard_selections.get(ix) { + // let end_offset = start_offset + clipboard_selection.len; + // to_insert = &clipboard_text[start_offset..end_offset]; + // entire_line = clipboard_selection.is_entire_line; + // start_offset = end_offset + 1; + // original_indent_column = + // Some(clipboard_selection.first_line_indent); + // } else { + // to_insert = clipboard_text.as_str(); + // entire_line = all_selections_were_entire_line; + // original_indent_column = first_selection_indent_column + // } + + // // If the corresponding selection was empty when this slice of the + // // clipboard text was written, then the entire line containing the + // // selection was copied. If this selection is also currently empty, + // // then paste the line before the current line of the buffer. + // let range = if selection.is_empty() && !line_mode && entire_line { + // let column = selection.start.to_point(&snapshot).column as usize; + // let line_start = selection.start - column; + // line_start..line_start + // } else { + // selection.range() + // }; + + // edits.push((range, to_insert)); + // original_indent_columns.extend(original_indent_column); + // } + // drop(snapshot); + + // buffer.edit( + // edits, + // Some(AutoindentMode::Block { + // original_indent_columns, + // }), + // cx, + // ); + // }); + + // let selections = this.selections.all::(cx); + // this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections)); + // } else { + // this.insert(&clipboard_text, cx); + // } + // } + // }); + // } + + // pub fn undo(&mut self, _: &Undo, cx: &mut ViewContext) { + // if let Some(tx_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) { + // if let Some((selections, _)) = self.selection_history.transaction(tx_id).cloned() { + // self.change_selections(None, cx, |s| { + // s.select_anchors(selections.to_vec()); + // }); + // } + // self.request_autoscroll(Autoscroll::fit(), cx); + // self.unmark_text(cx); + // self.refresh_copilot_suggestions(true, cx); + // cx.emit(Event::Edited); + // } + // } + + // pub fn redo(&mut self, _: &Redo, cx: &mut ViewContext) { + // if let Some(tx_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) { + // if let Some((_, Some(selections))) = self.selection_history.transaction(tx_id).cloned() + // { + // self.change_selections(None, cx, |s| { + // s.select_anchors(selections.to_vec()); + // }); + // } + // self.request_autoscroll(Autoscroll::fit(), cx); + // self.unmark_text(cx); + // self.refresh_copilot_suggestions(true, cx); + // cx.emit(Event::Edited); + // } + // } + + // pub fn finalize_last_transaction(&mut self, cx: &mut ViewContext) { + // self.buffer + // .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx)); + // } + + // pub fn move_left(&mut self, _: &MoveLeft, cx: &mut ViewContext) { + // self.change_selections(Some(Autoscroll::fit()), cx, |s| { + // let line_mode = s.line_mode; + // s.move_with(|map, selection| { + // let cursor = if selection.is_empty() && !line_mode { + // movement::left(map, selection.start) + // } else { + // selection.start + // }; + // selection.collapse_to(cursor, SelectionGoal::None); + // }); + // }) + // } + + // pub fn select_left(&mut self, _: &SelectLeft, cx: &mut ViewContext) { + // self.change_selections(Some(Autoscroll::fit()), cx, |s| { + // s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None)); + // }) + // } + + // pub fn move_right(&mut self, _: &MoveRight, cx: &mut ViewContext) { + // self.change_selections(Some(Autoscroll::fit()), cx, |s| { + // let line_mode = s.line_mode; + // s.move_with(|map, selection| { + // let cursor = if selection.is_empty() && !line_mode { + // movement::right(map, selection.end) + // } else { + // selection.end + // }; + // selection.collapse_to(cursor, SelectionGoal::None) + // }); + // }) + // } + + // pub fn select_right(&mut self, _: &SelectRight, cx: &mut ViewContext) { + // self.change_selections(Some(Autoscroll::fit()), cx, |s| { + // s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None)); + // }) + // } + + // pub fn move_up(&mut self, _: &MoveUp, cx: &mut ViewContext) { + // if self.take_rename(true, cx).is_some() { + // return; + // } + + // if matches!(self.mode, EditorMode::SingleLine) { + // cx.propagate_action(); + // return; + // } + + // let text_layout_details = &self.text_layout_details(cx); + + // self.change_selections(Some(Autoscroll::fit()), cx, |s| { + // let line_mode = s.line_mode; + // s.move_with(|map, selection| { + // if !selection.is_empty() && !line_mode { + // selection.goal = SelectionGoal::None; + // } + // let (cursor, goal) = movement::up( + // map, + // selection.start, + // selection.goal, + // false, + // &text_layout_details, + // ); + // selection.collapse_to(cursor, goal); + // }); + // }) + // } + + // pub fn move_page_up(&mut self, action: &MovePageUp, cx: &mut ViewContext) { + // if self.take_rename(true, cx).is_some() { + // return; + // } + + // if matches!(self.mode, EditorMode::SingleLine) { + // cx.propagate_action(); + // return; + // } + + // let row_count = if let Some(row_count) = self.visible_line_count() { + // row_count as u32 - 1 + // } else { + // return; + // }; + + // let autoscroll = if action.center_cursor { + // Autoscroll::center() + // } else { + // Autoscroll::fit() + // }; + + // let text_layout_details = &self.text_layout_details(cx); + + // self.change_selections(Some(autoscroll), cx, |s| { + // let line_mode = s.line_mode; + // s.move_with(|map, selection| { + // if !selection.is_empty() && !line_mode { + // selection.goal = SelectionGoal::None; + // } + // let (cursor, goal) = movement::up_by_rows( + // map, + // selection.end, + // row_count, + // selection.goal, + // false, + // &text_layout_details, + // ); + // selection.collapse_to(cursor, goal); + // }); + // }); + // } + + // pub fn select_up(&mut self, _: &SelectUp, cx: &mut ViewContext) { + // let text_layout_details = &self.text_layout_details(cx); + // self.change_selections(Some(Autoscroll::fit()), cx, |s| { + // s.move_heads_with(|map, head, goal| { + // movement::up(map, head, goal, false, &text_layout_details) + // }) + // }) + // } + + // pub fn move_down(&mut self, _: &MoveDown, cx: &mut ViewContext) { + // self.take_rename(true, cx); + + // if self.mode == EditorMode::SingleLine { + // cx.propagate_action(); + // return; + // } + + // let text_layout_details = &self.text_layout_details(cx); + // self.change_selections(Some(Autoscroll::fit()), cx, |s| { + // let line_mode = s.line_mode; + // s.move_with(|map, selection| { + // if !selection.is_empty() && !line_mode { + // selection.goal = SelectionGoal::None; + // } + // let (cursor, goal) = movement::down( + // map, + // selection.end, + // selection.goal, + // false, + // &text_layout_details, + // ); + // selection.collapse_to(cursor, goal); + // }); + // }); + // } + + // pub fn move_page_down(&mut self, action: &MovePageDown, cx: &mut ViewContext) { + // if self.take_rename(true, cx).is_some() { + // return; + // } + + // if self + // .context_menu + // .write() + // .as_mut() + // .map(|menu| menu.select_last(self.project.as_ref(), cx)) + // .unwrap_or(false) + // { + // return; + // } + + // if matches!(self.mode, EditorMode::SingleLine) { + // cx.propagate_action(); + // return; + // } + + // let row_count = if let Some(row_count) = self.visible_line_count() { + // row_count as u32 - 1 + // } else { + // return; + // }; + + // let autoscroll = if action.center_cursor { + // Autoscroll::center() + // } else { + // Autoscroll::fit() + // }; + + // let text_layout_details = &self.text_layout_details(cx); + // self.change_selections(Some(autoscroll), cx, |s| { + // let line_mode = s.line_mode; + // s.move_with(|map, selection| { + // if !selection.is_empty() && !line_mode { + // selection.goal = SelectionGoal::None; + // } + // let (cursor, goal) = movement::down_by_rows( + // map, + // selection.end, + // row_count, + // selection.goal, + // false, + // &text_layout_details, + // ); + // selection.collapse_to(cursor, goal); + // }); + // }); + // } + + // pub fn select_down(&mut self, _: &SelectDown, cx: &mut ViewContext) { + // let text_layout_details = &self.text_layout_details(cx); + // self.change_selections(Some(Autoscroll::fit()), cx, |s| { + // s.move_heads_with(|map, head, goal| { + // movement::down(map, head, goal, false, &text_layout_details) + // }) + // }); + // } + + // pub fn context_menu_first(&mut self, _: &ContextMenuFirst, cx: &mut ViewContext) { + // if let Some(context_menu) = self.context_menu.write().as_mut() { + // context_menu.select_first(self.project.as_ref(), cx); + // } + // } + + // pub fn context_menu_prev(&mut self, _: &ContextMenuPrev, cx: &mut ViewContext) { + // if let Some(context_menu) = self.context_menu.write().as_mut() { + // context_menu.select_prev(self.project.as_ref(), cx); + // } + // } + + // pub fn context_menu_next(&mut self, _: &ContextMenuNext, cx: &mut ViewContext) { + // if let Some(context_menu) = self.context_menu.write().as_mut() { + // context_menu.select_next(self.project.as_ref(), cx); + // } + // } + + // pub fn context_menu_last(&mut self, _: &ContextMenuLast, cx: &mut ViewContext) { + // if let Some(context_menu) = self.context_menu.write().as_mut() { + // context_menu.select_last(self.project.as_ref(), cx); + // } + // } + + // pub fn move_to_previous_word_start( + // &mut self, + // _: &MoveToPreviousWordStart, + // cx: &mut ViewContext, + // ) { + // self.change_selections(Some(Autoscroll::fit()), cx, |s| { + // s.move_cursors_with(|map, head, _| { + // ( + // movement::previous_word_start(map, head), + // SelectionGoal::None, + // ) + // }); + // }) + // } + + // pub fn move_to_previous_subword_start( + // &mut self, + // _: &MoveToPreviousSubwordStart, + // cx: &mut ViewContext, + // ) { + // self.change_selections(Some(Autoscroll::fit()), cx, |s| { + // s.move_cursors_with(|map, head, _| { + // ( + // movement::previous_subword_start(map, head), + // SelectionGoal::None, + // ) + // }); + // }) + // } + + // pub fn select_to_previous_word_start( + // &mut self, + // _: &SelectToPreviousWordStart, + // cx: &mut ViewContext, + // ) { + // self.change_selections(Some(Autoscroll::fit()), cx, |s| { + // s.move_heads_with(|map, head, _| { + // ( + // movement::previous_word_start(map, head), + // SelectionGoal::None, + // ) + // }); + // }) + // } + + // pub fn select_to_previous_subword_start( + // &mut self, + // _: &SelectToPreviousSubwordStart, + // cx: &mut ViewContext, + // ) { + // self.change_selections(Some(Autoscroll::fit()), cx, |s| { + // s.move_heads_with(|map, head, _| { + // ( + // movement::previous_subword_start(map, head), + // SelectionGoal::None, + // ) + // }); + // }) + // } + + // pub fn delete_to_previous_word_start( + // &mut self, + // _: &DeleteToPreviousWordStart, + // cx: &mut ViewContext, + // ) { + // self.transact(cx, |this, cx| { + // this.select_autoclose_pair(cx); + // this.change_selections(Some(Autoscroll::fit()), cx, |s| { + // let line_mode = s.line_mode; + // s.move_with(|map, selection| { + // if selection.is_empty() && !line_mode { + // let cursor = movement::previous_word_start(map, selection.head()); + // selection.set_head(cursor, SelectionGoal::None); + // } + // }); + // }); + // this.insert("", cx); + // }); + // } + + // pub fn delete_to_previous_subword_start( + // &mut self, + // _: &DeleteToPreviousSubwordStart, + // cx: &mut ViewContext, + // ) { + // self.transact(cx, |this, cx| { + // this.select_autoclose_pair(cx); + // this.change_selections(Some(Autoscroll::fit()), cx, |s| { + // let line_mode = s.line_mode; + // s.move_with(|map, selection| { + // if selection.is_empty() && !line_mode { + // let cursor = movement::previous_subword_start(map, selection.head()); + // selection.set_head(cursor, SelectionGoal::None); + // } + // }); + // }); + // this.insert("", cx); + // }); + // } + + // pub fn move_to_next_word_end(&mut self, _: &MoveToNextWordEnd, cx: &mut ViewContext) { + // self.change_selections(Some(Autoscroll::fit()), cx, |s| { + // s.move_cursors_with(|map, head, _| { + // (movement::next_word_end(map, head), SelectionGoal::None) + // }); + // }) + // } + + // pub fn move_to_next_subword_end( + // &mut self, + // _: &MoveToNextSubwordEnd, + // cx: &mut ViewContext, + // ) { + // self.change_selections(Some(Autoscroll::fit()), cx, |s| { + // s.move_cursors_with(|map, head, _| { + // (movement::next_subword_end(map, head), SelectionGoal::None) + // }); + // }) + // } + + // pub fn select_to_next_word_end(&mut self, _: &SelectToNextWordEnd, cx: &mut ViewContext) { + // self.change_selections(Some(Autoscroll::fit()), cx, |s| { + // s.move_heads_with(|map, head, _| { + // (movement::next_word_end(map, head), SelectionGoal::None) + // }); + // }) + // } + + // pub fn select_to_next_subword_end( + // &mut self, + // _: &SelectToNextSubwordEnd, + // cx: &mut ViewContext, + // ) { + // self.change_selections(Some(Autoscroll::fit()), cx, |s| { + // s.move_heads_with(|map, head, _| { + // (movement::next_subword_end(map, head), SelectionGoal::None) + // }); + // }) + // } + + // pub fn delete_to_next_word_end(&mut self, _: &DeleteToNextWordEnd, cx: &mut ViewContext) { + // self.transact(cx, |this, cx| { + // this.change_selections(Some(Autoscroll::fit()), cx, |s| { + // let line_mode = s.line_mode; + // s.move_with(|map, selection| { + // if selection.is_empty() && !line_mode { + // let cursor = movement::next_word_end(map, selection.head()); + // selection.set_head(cursor, SelectionGoal::None); + // } + // }); + // }); + // this.insert("", cx); + // }); + // } + + // pub fn delete_to_next_subword_end( + // &mut self, + // _: &DeleteToNextSubwordEnd, + // cx: &mut ViewContext, + // ) { + // self.transact(cx, |this, cx| { + // this.change_selections(Some(Autoscroll::fit()), cx, |s| { + // s.move_with(|map, selection| { + // if selection.is_empty() { + // let cursor = movement::next_subword_end(map, selection.head()); + // selection.set_head(cursor, SelectionGoal::None); + // } + // }); + // }); + // this.insert("", cx); + // }); + // } + + // pub fn move_to_beginning_of_line( + // &mut self, + // _: &MoveToBeginningOfLine, + // cx: &mut ViewContext, + // ) { + // self.change_selections(Some(Autoscroll::fit()), cx, |s| { + // s.move_cursors_with(|map, head, _| { + // ( + // movement::indented_line_beginning(map, head, true), + // SelectionGoal::None, + // ) + // }); + // }) + // } + + // pub fn select_to_beginning_of_line( + // &mut self, + // action: &SelectToBeginningOfLine, + // cx: &mut ViewContext, + // ) { + // self.change_selections(Some(Autoscroll::fit()), cx, |s| { + // s.move_heads_with(|map, head, _| { + // ( + // movement::indented_line_beginning(map, head, action.stop_at_soft_wraps), + // SelectionGoal::None, + // ) + // }); + // }); + // } + + // pub fn delete_to_beginning_of_line( + // &mut self, + // _: &DeleteToBeginningOfLine, + // cx: &mut ViewContext, + // ) { + // self.transact(cx, |this, cx| { + // this.change_selections(Some(Autoscroll::fit()), cx, |s| { + // s.move_with(|_, selection| { + // selection.reversed = true; + // }); + // }); + + // this.select_to_beginning_of_line( + // &SelectToBeginningOfLine { + // stop_at_soft_wraps: false, + // }, + // cx, + // ); + // this.backspace(&Backspace, cx); + // }); + // } + + // pub fn move_to_end_of_line(&mut self, _: &MoveToEndOfLine, cx: &mut ViewContext) { + // self.change_selections(Some(Autoscroll::fit()), cx, |s| { + // s.move_cursors_with(|map, head, _| { + // (movement::line_end(map, head, true), SelectionGoal::None) + // }); + // }) + // } + + // pub fn select_to_end_of_line( + // &mut self, + // action: &SelectToEndOfLine, + // cx: &mut ViewContext, + // ) { + // self.change_selections(Some(Autoscroll::fit()), cx, |s| { + // s.move_heads_with(|map, head, _| { + // ( + // movement::line_end(map, head, action.stop_at_soft_wraps), + // SelectionGoal::None, + // ) + // }); + // }) + // } + + // pub fn delete_to_end_of_line(&mut self, _: &DeleteToEndOfLine, cx: &mut ViewContext) { + // self.transact(cx, |this, cx| { + // this.select_to_end_of_line( + // &SelectToEndOfLine { + // stop_at_soft_wraps: false, + // }, + // cx, + // ); + // this.delete(&Delete, cx); + // }); + // } + + // pub fn cut_to_end_of_line(&mut self, _: &CutToEndOfLine, cx: &mut ViewContext) { + // self.transact(cx, |this, cx| { + // this.select_to_end_of_line( + // &SelectToEndOfLine { + // stop_at_soft_wraps: false, + // }, + // cx, + // ); + // this.cut(&Cut, cx); + // }); + // } + + // pub fn move_to_start_of_paragraph( + // &mut self, + // _: &MoveToStartOfParagraph, + // cx: &mut ViewContext, + // ) { + // if matches!(self.mode, EditorMode::SingleLine) { + // cx.propagate_action(); + // return; + // } + + // self.change_selections(Some(Autoscroll::fit()), cx, |s| { + // s.move_with(|map, selection| { + // selection.collapse_to( + // movement::start_of_paragraph(map, selection.head(), 1), + // SelectionGoal::None, + // ) + // }); + // }) + // } + + // pub fn move_to_end_of_paragraph( + // &mut self, + // _: &MoveToEndOfParagraph, + // cx: &mut ViewContext, + // ) { + // if matches!(self.mode, EditorMode::SingleLine) { + // cx.propagate_action(); + // return; + // } + + // self.change_selections(Some(Autoscroll::fit()), cx, |s| { + // s.move_with(|map, selection| { + // selection.collapse_to( + // movement::end_of_paragraph(map, selection.head(), 1), + // SelectionGoal::None, + // ) + // }); + // }) + // } + + // pub fn select_to_start_of_paragraph( + // &mut self, + // _: &SelectToStartOfParagraph, + // cx: &mut ViewContext, + // ) { + // if matches!(self.mode, EditorMode::SingleLine) { + // cx.propagate_action(); + // return; + // } + + // self.change_selections(Some(Autoscroll::fit()), cx, |s| { + // s.move_heads_with(|map, head, _| { + // ( + // movement::start_of_paragraph(map, head, 1), + // SelectionGoal::None, + // ) + // }); + // }) + // } + + // pub fn select_to_end_of_paragraph( + // &mut self, + // _: &SelectToEndOfParagraph, + // cx: &mut ViewContext, + // ) { + // if matches!(self.mode, EditorMode::SingleLine) { + // cx.propagate_action(); + // return; + // } + + // self.change_selections(Some(Autoscroll::fit()), cx, |s| { + // s.move_heads_with(|map, head, _| { + // ( + // movement::end_of_paragraph(map, head, 1), + // SelectionGoal::None, + // ) + // }); + // }) + // } + + // pub fn move_to_beginning(&mut self, _: &MoveToBeginning, cx: &mut ViewContext) { + // if matches!(self.mode, EditorMode::SingleLine) { + // cx.propagate_action(); + // return; + // } + + // self.change_selections(Some(Autoscroll::fit()), cx, |s| { + // s.select_ranges(vec![0..0]); + // }); + // } + + // pub fn select_to_beginning(&mut self, _: &SelectToBeginning, cx: &mut ViewContext) { + // let mut selection = self.selections.last::(cx); + // selection.set_head(Point::zero(), SelectionGoal::None); + + // self.change_selections(Some(Autoscroll::fit()), cx, |s| { + // s.select(vec![selection]); + // }); + // } + + // pub fn move_to_end(&mut self, _: &MoveToEnd, cx: &mut ViewContext) { + // if matches!(self.mode, EditorMode::SingleLine) { + // cx.propagate_action(); + // return; + // } + + // let cursor = self.buffer.read(cx).read(cx).len(); + // self.change_selections(Some(Autoscroll::fit()), cx, |s| { + // s.select_ranges(vec![cursor..cursor]) + // }); + // } + + // pub fn set_nav_history(&mut self, nav_history: Option) { + // self.nav_history = nav_history; + // } + + // pub fn nav_history(&self) -> Option<&ItemNavHistory> { + // self.nav_history.as_ref() + // } + + // fn push_to_nav_history( + // &mut self, + // cursor_anchor: Anchor, + // new_position: Option, + // cx: &mut ViewContext, + // ) { + // if let Some(nav_history) = self.nav_history.as_mut() { + // let buffer = self.buffer.read(cx).read(cx); + // let cursor_position = cursor_anchor.to_point(&buffer); + // let scroll_state = self.scroll_manager.anchor(); + // let scroll_top_row = scroll_state.top_row(&buffer); + // drop(buffer); + + // if let Some(new_position) = new_position { + // let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs(); + // if row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA { + // return; + // } + // } + + // nav_history.push( + // Some(NavigationData { + // cursor_anchor, + // cursor_position, + // scroll_anchor: scroll_state, + // scroll_top_row, + // }), + // cx, + // ); + // } + // } + + // pub fn select_to_end(&mut self, _: &SelectToEnd, cx: &mut ViewContext) { + // let buffer = self.buffer.read(cx).snapshot(cx); + // let mut selection = self.selections.first::(cx); + // selection.set_head(buffer.len(), SelectionGoal::None); + // self.change_selections(Some(Autoscroll::fit()), cx, |s| { + // s.select(vec![selection]); + // }); + // } + + // pub fn select_all(&mut self, _: &SelectAll, cx: &mut ViewContext) { + // let end = self.buffer.read(cx).read(cx).len(); + // self.change_selections(None, cx, |s| { + // s.select_ranges(vec![0..end]); + // }); + // } + + // pub fn select_line(&mut self, _: &SelectLine, cx: &mut ViewContext) { + // let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); + // let mut selections = self.selections.all::(cx); + // let max_point = display_map.buffer_snapshot.max_point(); + // for selection in &mut selections { + // let rows = selection.spanned_rows(true, &display_map); + // selection.start = Point::new(rows.start, 0); + // selection.end = cmp::min(max_point, Point::new(rows.end, 0)); + // selection.reversed = false; + // } + // self.change_selections(Some(Autoscroll::fit()), cx, |s| { + // s.select(selections); + // }); + // } + + // pub fn split_selection_into_lines( + // &mut self, + // _: &SplitSelectionIntoLines, + // cx: &mut ViewContext, + // ) { + // let mut to_unfold = Vec::new(); + // let mut new_selection_ranges = Vec::new(); + // { + // let selections = self.selections.all::(cx); + // let buffer = self.buffer.read(cx).read(cx); + // for selection in selections { + // for row in selection.start.row..selection.end.row { + // let cursor = Point::new(row, buffer.line_len(row)); + // new_selection_ranges.push(cursor..cursor); + // } + // new_selection_ranges.push(selection.end..selection.end); + // to_unfold.push(selection.start..selection.end); + // } + // } + // self.unfold_ranges(to_unfold, true, true, cx); + // self.change_selections(Some(Autoscroll::fit()), cx, |s| { + // s.select_ranges(new_selection_ranges); + // }); + // } + + // pub fn add_selection_above(&mut self, _: &AddSelectionAbove, cx: &mut ViewContext) { + // self.add_selection(true, cx); + // } + + // pub fn add_selection_below(&mut self, _: &AddSelectionBelow, cx: &mut ViewContext) { + // self.add_selection(false, cx); + // } + + // fn add_selection(&mut self, above: bool, cx: &mut ViewContext) { + // let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); + // let mut selections = self.selections.all::(cx); + // let text_layout_details = self.text_layout_details(cx); + // let mut state = self.add_selections_state.take().unwrap_or_else(|| { + // let oldest_selection = selections.iter().min_by_key(|s| s.id).unwrap().clone(); + // let range = oldest_selection.display_range(&display_map).sorted(); + + // let start_x = display_map.x_for_point(range.start, &text_layout_details); + // let end_x = display_map.x_for_point(range.end, &text_layout_details); + // let positions = start_x.min(end_x)..start_x.max(end_x); + + // selections.clear(); + // let mut stack = Vec::new(); + // for row in range.start.row()..=range.end.row() { + // if let Some(selection) = self.selections.build_columnar_selection( + // &display_map, + // row, + // &positions, + // oldest_selection.reversed, + // &text_layout_details, + // ) { + // stack.push(selection.id); + // selections.push(selection); + // } + // } + + // if above { + // stack.reverse(); + // } + + // AddSelectionsState { above, stack } + // }); + + // let last_added_selection = *state.stack.last().unwrap(); + // let mut new_selections = Vec::new(); + // if above == state.above { + // let end_row = if above { + // 0 + // } else { + // display_map.max_point().row() + // }; + + // 'outer: for selection in selections { + // if selection.id == last_added_selection { + // let range = selection.display_range(&display_map).sorted(); + // debug_assert_eq!(range.start.row(), range.end.row()); + // let mut row = range.start.row(); + // let positions = if let SelectionGoal::HorizontalRange { start, end } = + // selection.goal + // { + // start..end + // } else { + // let start_x = display_map.x_for_point(range.start, &text_layout_details); + // let end_x = display_map.x_for_point(range.end, &text_layout_details); + + // start_x.min(end_x)..start_x.max(end_x) + // }; + + // while row != end_row { + // if above { + // row -= 1; + // } else { + // row += 1; + // } + + // if let Some(new_selection) = self.selections.build_columnar_selection( + // &display_map, + // row, + // &positions, + // selection.reversed, + // &text_layout_details, + // ) { + // state.stack.push(new_selection.id); + // if above { + // new_selections.push(new_selection); + // new_selections.push(selection); + // } else { + // new_selections.push(selection); + // new_selections.push(new_selection); + // } + + // continue 'outer; + // } + // } + // } + + // new_selections.push(selection); + // } + // } else { + // new_selections = selections; + // new_selections.retain(|s| s.id != last_added_selection); + // state.stack.pop(); + // } + + // self.change_selections(Some(Autoscroll::fit()), cx, |s| { + // s.select(new_selections); + // }); + // if state.stack.len() > 1 { + // self.add_selections_state = Some(state); + // } + // } + + // pub fn select_next_match_internal( + // &mut self, + // display_map: &DisplaySnapshot, + // replace_newest: bool, + // autoscroll: Option, + // cx: &mut ViewContext, + // ) -> Result<()> { + // fn select_next_match_ranges( + // this: &mut Editor, + // range: Range, + // replace_newest: bool, + // auto_scroll: Option, + // cx: &mut ViewContext, + // ) { + // this.unfold_ranges([range.clone()], false, true, cx); + // this.change_selections(auto_scroll, cx, |s| { + // if replace_newest { + // s.delete(s.newest_anchor().id); + // } + // s.insert_range(range.clone()); + // }); + // } + + // let buffer = &display_map.buffer_snapshot; + // let mut selections = self.selections.all::(cx); + // if let Some(mut select_next_state) = self.select_next_state.take() { + // let query = &select_next_state.query; + // if !select_next_state.done { + // let first_selection = selections.iter().min_by_key(|s| s.id).unwrap(); + // let last_selection = selections.iter().max_by_key(|s| s.id).unwrap(); + // let mut next_selected_range = None; + + // let bytes_after_last_selection = + // buffer.bytes_in_range(last_selection.end..buffer.len()); + // let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start); + // let query_matches = query + // .stream_find_iter(bytes_after_last_selection) + // .map(|result| (last_selection.end, result)) + // .chain( + // query + // .stream_find_iter(bytes_before_first_selection) + // .map(|result| (0, result)), + // ); + + // for (start_offset, query_match) in query_matches { + // let query_match = query_match.unwrap(); // can only fail due to I/O + // let offset_range = + // start_offset + query_match.start()..start_offset + query_match.end(); + // let display_range = offset_range.start.to_display_point(&display_map) + // ..offset_range.end.to_display_point(&display_map); + + // if !select_next_state.wordwise + // || (!movement::is_inside_word(&display_map, display_range.start) + // && !movement::is_inside_word(&display_map, display_range.end)) + // { + // if selections + // .iter() + // .find(|selection| selection.range().overlaps(&offset_range)) + // .is_none() + // { + // next_selected_range = Some(offset_range); + // break; + // } + // } + // } + + // if let Some(next_selected_range) = next_selected_range { + // select_next_match_ranges( + // self, + // next_selected_range, + // replace_newest, + // autoscroll, + // cx, + // ); + // } else { + // select_next_state.done = true; + // } + // } + + // self.select_next_state = Some(select_next_state); + // } else if selections.len() == 1 { + // let selection = selections.last_mut().unwrap(); + // if selection.start == selection.end { + // let word_range = movement::surrounding_word( + // &display_map, + // selection.start.to_display_point(&display_map), + // ); + // selection.start = word_range.start.to_offset(&display_map, Bias::Left); + // selection.end = word_range.end.to_offset(&display_map, Bias::Left); + // selection.goal = SelectionGoal::None; + // selection.reversed = false; + + // let query = buffer + // .text_for_range(selection.start..selection.end) + // .collect::(); + + // let is_empty = query.is_empty(); + // let select_state = SelectNextState { + // query: AhoCorasick::new(&[query])?, + // wordwise: true, + // done: is_empty, + // }; + // select_next_match_ranges( + // self, + // selection.start..selection.end, + // replace_newest, + // autoscroll, + // cx, + // ); + // self.select_next_state = Some(select_state); + // } else { + // let query = buffer + // .text_for_range(selection.start..selection.end) + // .collect::(); + // self.select_next_state = Some(SelectNextState { + // query: AhoCorasick::new(&[query])?, + // wordwise: false, + // done: false, + // }); + // self.select_next_match_internal(display_map, replace_newest, autoscroll, cx)?; + // } + // } + // Ok(()) + // } + + // pub fn select_all_matches( + // &mut self, + // action: &SelectAllMatches, + // cx: &mut ViewContext, + // ) -> Result<()> { + // self.push_to_selection_history(); + // let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); + + // loop { + // self.select_next_match_internal(&display_map, action.replace_newest, None, cx)?; + + // if self + // .select_next_state + // .as_ref() + // .map(|selection_state| selection_state.done) + // .unwrap_or(true) + // { + // break; + // } + // } + + // Ok(()) + // } + + // pub fn select_next(&mut self, action: &SelectNext, cx: &mut ViewContext) -> Result<()> { + // self.push_to_selection_history(); + // let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); + // self.select_next_match_internal( + // &display_map, + // action.replace_newest, + // Some(Autoscroll::newest()), + // cx, + // )?; + // Ok(()) + // } + + // pub fn select_previous( + // &mut self, + // action: &SelectPrevious, + // cx: &mut ViewContext, + // ) -> Result<()> { + // self.push_to_selection_history(); + // let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); + // let buffer = &display_map.buffer_snapshot; + // let mut selections = self.selections.all::(cx); + // if let Some(mut select_prev_state) = self.select_prev_state.take() { + // let query = &select_prev_state.query; + // if !select_prev_state.done { + // let first_selection = selections.iter().min_by_key(|s| s.id).unwrap(); + // let last_selection = selections.iter().max_by_key(|s| s.id).unwrap(); + // let mut next_selected_range = None; + // // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer. + // let bytes_before_last_selection = + // buffer.reversed_bytes_in_range(0..last_selection.start); + // let bytes_after_first_selection = + // buffer.reversed_bytes_in_range(first_selection.end..buffer.len()); + // let query_matches = query + // .stream_find_iter(bytes_before_last_selection) + // .map(|result| (last_selection.start, result)) + // .chain( + // query + // .stream_find_iter(bytes_after_first_selection) + // .map(|result| (buffer.len(), result)), + // ); + // for (end_offset, query_match) in query_matches { + // let query_match = query_match.unwrap(); // can only fail due to I/O + // let offset_range = + // end_offset - query_match.end()..end_offset - query_match.start(); + // let display_range = offset_range.start.to_display_point(&display_map) + // ..offset_range.end.to_display_point(&display_map); + + // if !select_prev_state.wordwise + // || (!movement::is_inside_word(&display_map, display_range.start) + // && !movement::is_inside_word(&display_map, display_range.end)) + // { + // next_selected_range = Some(offset_range); + // break; + // } + // } + + // if let Some(next_selected_range) = next_selected_range { + // self.unfold_ranges([next_selected_range.clone()], false, true, cx); + // self.change_selections(Some(Autoscroll::newest()), cx, |s| { + // if action.replace_newest { + // s.delete(s.newest_anchor().id); + // } + // s.insert_range(next_selected_range); + // }); + // } else { + // select_prev_state.done = true; + // } + // } + + // self.select_prev_state = Some(select_prev_state); + // } else if selections.len() == 1 { + // let selection = selections.last_mut().unwrap(); + // if selection.start == selection.end { + // let word_range = movement::surrounding_word( + // &display_map, + // selection.start.to_display_point(&display_map), + // ); + // selection.start = word_range.start.to_offset(&display_map, Bias::Left); + // selection.end = word_range.end.to_offset(&display_map, Bias::Left); + // selection.goal = SelectionGoal::None; + // selection.reversed = false; + + // let query = buffer + // .text_for_range(selection.start..selection.end) + // .collect::(); + // let query = query.chars().rev().collect::(); + // let select_state = SelectNextState { + // query: AhoCorasick::new(&[query])?, + // wordwise: true, + // done: false, + // }; + // self.unfold_ranges([selection.start..selection.end], false, true, cx); + // self.change_selections(Some(Autoscroll::newest()), cx, |s| { + // s.select(selections); + // }); + // self.select_prev_state = Some(select_state); + // } else { + // let query = buffer + // .text_for_range(selection.start..selection.end) + // .collect::(); + // let query = query.chars().rev().collect::(); + // self.select_prev_state = Some(SelectNextState { + // query: AhoCorasick::new(&[query])?, + // wordwise: false, + // done: false, + // }); + // self.select_previous(action, cx)?; + // } + // } + // Ok(()) + // } + + // pub fn toggle_comments(&mut self, action: &ToggleComments, cx: &mut ViewContext) { + // let text_layout_details = &self.text_layout_details(cx); + // self.transact(cx, |this, cx| { + // let mut selections = this.selections.all::(cx); + // let mut edits = Vec::new(); + // let mut selection_edit_ranges = Vec::new(); + // let mut last_toggled_row = None; + // let snapshot = this.buffer.read(cx).read(cx); + // let empty_str: Arc = "".into(); + // let mut suffixes_inserted = Vec::new(); + + // fn comment_prefix_range( + // snapshot: &MultiBufferSnapshot, + // row: u32, + // comment_prefix: &str, + // comment_prefix_whitespace: &str, + // ) -> Range { + // let start = Point::new(row, snapshot.indent_size_for_line(row).len); + + // let mut line_bytes = snapshot + // .bytes_in_range(start..snapshot.max_point()) + // .flatten() + // .copied(); + + // // If this line currently begins with the line comment prefix, then record + // // the range containing the prefix. + // if line_bytes + // .by_ref() + // .take(comment_prefix.len()) + // .eq(comment_prefix.bytes()) + // { + // // Include any whitespace that matches the comment prefix. + // let matching_whitespace_len = line_bytes + // .zip(comment_prefix_whitespace.bytes()) + // .take_while(|(a, b)| a == b) + // .count() as u32; + // let end = Point::new( + // start.row, + // start.column + comment_prefix.len() as u32 + matching_whitespace_len, + // ); + // start..end + // } else { + // start..start + // } + // } + + // fn comment_suffix_range( + // snapshot: &MultiBufferSnapshot, + // row: u32, + // comment_suffix: &str, + // comment_suffix_has_leading_space: bool, + // ) -> Range { + // let end = Point::new(row, snapshot.line_len(row)); + // let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32); + + // let mut line_end_bytes = snapshot + // .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end) + // .flatten() + // .copied(); + + // let leading_space_len = if suffix_start_column > 0 + // && line_end_bytes.next() == Some(b' ') + // && comment_suffix_has_leading_space + // { + // 1 + // } else { + // 0 + // }; + + // // If this line currently begins with the line comment prefix, then record + // // the range containing the prefix. + // if line_end_bytes.by_ref().eq(comment_suffix.bytes()) { + // let start = Point::new(end.row, suffix_start_column - leading_space_len); + // start..end + // } else { + // end..end + // } + // } + + // // TODO: Handle selections that cross excerpts + // for selection in &mut selections { + // let start_column = snapshot.indent_size_for_line(selection.start.row).len; + // let language = if let Some(language) = + // snapshot.language_scope_at(Point::new(selection.start.row, start_column)) + // { + // language + // } else { + // continue; + // }; + + // selection_edit_ranges.clear(); + + // // If multiple selections contain a given row, avoid processing that + // // row more than once. + // let mut start_row = selection.start.row; + // if last_toggled_row == Some(start_row) { + // start_row += 1; + // } + // let end_row = + // if selection.end.row > selection.start.row && selection.end.column == 0 { + // selection.end.row - 1 + // } else { + // selection.end.row + // }; + // last_toggled_row = Some(end_row); + + // if start_row > end_row { + // continue; + // } + + // // If the language has line comments, toggle those. + // if let Some(full_comment_prefix) = language.line_comment_prefix() { + // // Split the comment prefix's trailing whitespace into a separate string, + // // as that portion won't be used for detecting if a line is a comment. + // let comment_prefix = full_comment_prefix.trim_end_matches(' '); + // let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..]; + // let mut all_selection_lines_are_comments = true; + + // for row in start_row..=end_row { + // if snapshot.is_line_blank(row) && start_row < end_row { + // continue; + // } + + // let prefix_range = comment_prefix_range( + // snapshot.deref(), + // row, + // comment_prefix, + // comment_prefix_whitespace, + // ); + // if prefix_range.is_empty() { + // all_selection_lines_are_comments = false; + // } + // selection_edit_ranges.push(prefix_range); + // } + + // if all_selection_lines_are_comments { + // edits.extend( + // selection_edit_ranges + // .iter() + // .cloned() + // .map(|range| (range, empty_str.clone())), + // ); + // } else { + // let min_column = selection_edit_ranges + // .iter() + // .map(|r| r.start.column) + // .min() + // .unwrap_or(0); + // edits.extend(selection_edit_ranges.iter().map(|range| { + // let position = Point::new(range.start.row, min_column); + // (position..position, full_comment_prefix.clone()) + // })); + // } + // } else if let Some((full_comment_prefix, comment_suffix)) = + // language.block_comment_delimiters() + // { + // let comment_prefix = full_comment_prefix.trim_end_matches(' '); + // let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..]; + // let prefix_range = comment_prefix_range( + // snapshot.deref(), + // start_row, + // comment_prefix, + // comment_prefix_whitespace, + // ); + // let suffix_range = comment_suffix_range( + // snapshot.deref(), + // end_row, + // comment_suffix.trim_start_matches(' '), + // comment_suffix.starts_with(' '), + // ); + + // if prefix_range.is_empty() || suffix_range.is_empty() { + // edits.push(( + // prefix_range.start..prefix_range.start, + // full_comment_prefix.clone(), + // )); + // edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone())); + // suffixes_inserted.push((end_row, comment_suffix.len())); + // } else { + // edits.push((prefix_range, empty_str.clone())); + // edits.push((suffix_range, empty_str.clone())); + // } + // } else { + // continue; + // } + // } + + // drop(snapshot); + // this.buffer.update(cx, |buffer, cx| { + // buffer.edit(edits, None, cx); + // }); + + // // Adjust selections so that they end before any comment suffixes that + // // were inserted. + // let mut suffixes_inserted = suffixes_inserted.into_iter().peekable(); + // let mut selections = this.selections.all::(cx); + // let snapshot = this.buffer.read(cx).read(cx); + // for selection in &mut selections { + // while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() { + // match row.cmp(&selection.end.row) { + // Ordering::Less => { + // suffixes_inserted.next(); + // continue; + // } + // Ordering::Greater => break, + // Ordering::Equal => { + // if selection.end.column == snapshot.line_len(row) { + // if selection.is_empty() { + // selection.start.column -= suffix_len as u32; + // } + // selection.end.column -= suffix_len as u32; + // } + // break; + // } + // } + // } + // } + + // drop(snapshot); + // this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections)); + + // let selections = this.selections.all::(cx); + // let selections_on_single_row = selections.windows(2).all(|selections| { + // selections[0].start.row == selections[1].start.row + // && selections[0].end.row == selections[1].end.row + // && selections[0].start.row == selections[0].end.row + // }); + // let selections_selecting = selections + // .iter() + // .any(|selection| selection.start != selection.end); + // let advance_downwards = action.advance_downwards + // && selections_on_single_row + // && !selections_selecting + // && this.mode != EditorMode::SingleLine; + + // if advance_downwards { + // let snapshot = this.buffer.read(cx).snapshot(cx); + + // this.change_selections(Some(Autoscroll::fit()), cx, |s| { + // s.move_cursors_with(|display_snapshot, display_point, _| { + // let mut point = display_point.to_point(display_snapshot); + // point.row += 1; + // point = snapshot.clip_point(point, Bias::Left); + // let display_point = point.to_display_point(display_snapshot); + // let goal = SelectionGoal::HorizontalPosition( + // display_snapshot.x_for_point(display_point, &text_layout_details), + // ); + // (display_point, goal) + // }) + // }); + // } + // }); + // } + + // pub fn select_larger_syntax_node( + // &mut self, + // _: &SelectLargerSyntaxNode, + // cx: &mut ViewContext, + // ) { + // let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); + // let buffer = self.buffer.read(cx).snapshot(cx); + // let old_selections = self.selections.all::(cx).into_boxed_slice(); + + // let mut stack = mem::take(&mut self.select_larger_syntax_node_stack); + // let mut selected_larger_node = false; + // let new_selections = old_selections + // .iter() + // .map(|selection| { + // let old_range = selection.start..selection.end; + // let mut new_range = old_range.clone(); + // while let Some(containing_range) = + // buffer.range_for_syntax_ancestor(new_range.clone()) + // { + // new_range = containing_range; + // if !display_map.intersects_fold(new_range.start) + // && !display_map.intersects_fold(new_range.end) + // { + // break; + // } + // } + + // selected_larger_node |= new_range != old_range; + // Selection { + // id: selection.id, + // start: new_range.start, + // end: new_range.end, + // goal: SelectionGoal::None, + // reversed: selection.reversed, + // } + // }) + // .collect::>(); + + // if selected_larger_node { + // stack.push(old_selections); + // self.change_selections(Some(Autoscroll::fit()), cx, |s| { + // s.select(new_selections); + // }); + // } + // self.select_larger_syntax_node_stack = stack; + // } + + // pub fn select_smaller_syntax_node( + // &mut self, + // _: &SelectSmallerSyntaxNode, + // cx: &mut ViewContext, + // ) { + // let mut stack = mem::take(&mut self.select_larger_syntax_node_stack); + // if let Some(selections) = stack.pop() { + // self.change_selections(Some(Autoscroll::fit()), cx, |s| { + // s.select(selections.to_vec()); + // }); + // } + // self.select_larger_syntax_node_stack = stack; + // } + + // pub fn move_to_enclosing_bracket( + // &mut self, + // _: &MoveToEnclosingBracket, + // cx: &mut ViewContext, + // ) { + // self.change_selections(Some(Autoscroll::fit()), cx, |s| { + // s.move_offsets_with(|snapshot, selection| { + // let Some(enclosing_bracket_ranges) = + // snapshot.enclosing_bracket_ranges(selection.start..selection.end) + // else { + // return; + // }; + + // let mut best_length = usize::MAX; + // let mut best_inside = false; + // let mut best_in_bracket_range = false; + // let mut best_destination = None; + // for (open, close) in enclosing_bracket_ranges { + // let close = close.to_inclusive(); + // let length = close.end() - open.start; + // let inside = selection.start >= open.end && selection.end <= *close.start(); + // let in_bracket_range = open.to_inclusive().contains(&selection.head()) + // || close.contains(&selection.head()); + + // // If best is next to a bracket and current isn't, skip + // if !in_bracket_range && best_in_bracket_range { + // continue; + // } + + // // Prefer smaller lengths unless best is inside and current isn't + // if length > best_length && (best_inside || !inside) { + // continue; + // } + + // best_length = length; + // best_inside = inside; + // best_in_bracket_range = in_bracket_range; + // best_destination = Some( + // if close.contains(&selection.start) && close.contains(&selection.end) { + // if inside { + // open.end + // } else { + // open.start + // } + // } else { + // if inside { + // *close.start() + // } else { + // *close.end() + // } + // }, + // ); + // } + + // if let Some(destination) = best_destination { + // selection.collapse_to(destination, SelectionGoal::None); + // } + // }) + // }); + // } + + // pub fn undo_selection(&mut self, _: &UndoSelection, cx: &mut ViewContext) { + // self.end_selection(cx); + // self.selection_history.mode = SelectionHistoryMode::Undoing; + // if let Some(entry) = self.selection_history.undo_stack.pop_back() { + // self.change_selections(None, cx, |s| s.select_anchors(entry.selections.to_vec())); + // self.select_next_state = entry.select_next_state; + // self.select_prev_state = entry.select_prev_state; + // self.add_selections_state = entry.add_selections_state; + // self.request_autoscroll(Autoscroll::newest(), cx); + // } + // self.selection_history.mode = SelectionHistoryMode::Normal; + // } + + // pub fn redo_selection(&mut self, _: &RedoSelection, cx: &mut ViewContext) { + // self.end_selection(cx); + // self.selection_history.mode = SelectionHistoryMode::Redoing; + // if let Some(entry) = self.selection_history.redo_stack.pop_back() { + // self.change_selections(None, cx, |s| s.select_anchors(entry.selections.to_vec())); + // self.select_next_state = entry.select_next_state; + // self.select_prev_state = entry.select_prev_state; + // self.add_selections_state = entry.add_selections_state; + // self.request_autoscroll(Autoscroll::newest(), cx); + // } + // self.selection_history.mode = SelectionHistoryMode::Normal; + // } + + // fn go_to_diagnostic(&mut self, _: &GoToDiagnostic, cx: &mut ViewContext) { + // self.go_to_diagnostic_impl(Direction::Next, cx) + // } + + // fn go_to_prev_diagnostic(&mut self, _: &GoToPrevDiagnostic, cx: &mut ViewContext) { + // self.go_to_diagnostic_impl(Direction::Prev, cx) + // } + + // pub fn go_to_diagnostic_impl(&mut self, direction: Direction, cx: &mut ViewContext) { + // let buffer = self.buffer.read(cx).snapshot(cx); + // let selection = self.selections.newest::(cx); + + // // If there is an active Diagnostic Popover. Jump to it's diagnostic instead. + // if direction == Direction::Next { + // if let Some(popover) = self.hover_state.diagnostic_popover.as_ref() { + // let (group_id, jump_to) = popover.activation_info(); + // if self.activate_diagnostics(group_id, cx) { + // self.change_selections(Some(Autoscroll::fit()), cx, |s| { + // let mut new_selection = s.newest_anchor().clone(); + // new_selection.collapse_to(jump_to, SelectionGoal::None); + // s.select_anchors(vec![new_selection.clone()]); + // }); + // } + // return; + // } + // } + + // let mut active_primary_range = self.active_diagnostics.as_ref().map(|active_diagnostics| { + // active_diagnostics + // .primary_range + // .to_offset(&buffer) + // .to_inclusive() + // }); + // let mut search_start = if let Some(active_primary_range) = active_primary_range.as_ref() { + // if active_primary_range.contains(&selection.head()) { + // *active_primary_range.end() + // } else { + // selection.head() + // } + // } else { + // selection.head() + // }; + + // loop { + // let mut diagnostics = if direction == Direction::Prev { + // buffer.diagnostics_in_range::<_, usize>(0..search_start, true) + // } else { + // buffer.diagnostics_in_range::<_, usize>(search_start..buffer.len(), false) + // }; + // let group = diagnostics.find_map(|entry| { + // if entry.diagnostic.is_primary + // && entry.diagnostic.severity <= DiagnosticSeverity::WARNING + // && !entry.range.is_empty() + // && Some(entry.range.end) != active_primary_range.as_ref().map(|r| *r.end()) + // && !entry.range.contains(&search_start) + // { + // Some((entry.range, entry.diagnostic.group_id)) + // } else { + // None + // } + // }); + + // if let Some((primary_range, group_id)) = group { + // if self.activate_diagnostics(group_id, cx) { + // self.change_selections(Some(Autoscroll::fit()), cx, |s| { + // s.select(vec![Selection { + // id: selection.id, + // start: primary_range.start, + // end: primary_range.start, + // reversed: false, + // goal: SelectionGoal::None, + // }]); + // }); + // } + // break; + // } else { + // // Cycle around to the start of the buffer, potentially moving back to the start of + // // the currently active diagnostic. + // active_primary_range.take(); + // if direction == Direction::Prev { + // if search_start == buffer.len() { + // break; + // } else { + // search_start = buffer.len(); + // } + // } else if search_start == 0 { + // break; + // } else { + // search_start = 0; + // } + // } + // } + // } + + // fn go_to_hunk(&mut self, _: &GoToHunk, cx: &mut ViewContext) { + // let snapshot = self + // .display_map + // .update(cx, |display_map, cx| display_map.snapshot(cx)); + // let selection = self.selections.newest::(cx); + + // if !self.seek_in_direction( + // &snapshot, + // selection.head(), + // false, + // snapshot + // .buffer_snapshot + // .git_diff_hunks_in_range((selection.head().row + 1)..u32::MAX), + // cx, + // ) { + // let wrapped_point = Point::zero(); + // self.seek_in_direction( + // &snapshot, + // wrapped_point, + // true, + // snapshot + // .buffer_snapshot + // .git_diff_hunks_in_range((wrapped_point.row + 1)..u32::MAX), + // cx, + // ); + // } + // } + + // fn go_to_prev_hunk(&mut self, _: &GoToPrevHunk, cx: &mut ViewContext) { + // let snapshot = self + // .display_map + // .update(cx, |display_map, cx| display_map.snapshot(cx)); + // let selection = self.selections.newest::(cx); + + // if !self.seek_in_direction( + // &snapshot, + // selection.head(), + // false, + // snapshot + // .buffer_snapshot + // .git_diff_hunks_in_range_rev(0..selection.head().row), + // cx, + // ) { + // let wrapped_point = snapshot.buffer_snapshot.max_point(); + // self.seek_in_direction( + // &snapshot, + // wrapped_point, + // true, + // snapshot + // .buffer_snapshot + // .git_diff_hunks_in_range_rev(0..wrapped_point.row), + // cx, + // ); + // } + // } + + // fn seek_in_direction( + // &mut self, + // snapshot: &DisplaySnapshot, + // initial_point: Point, + // is_wrapped: bool, + // hunks: impl Iterator>, + // cx: &mut ViewContext, + // ) -> bool { + // let display_point = initial_point.to_display_point(snapshot); + // let mut hunks = hunks + // .map(|hunk| diff_hunk_to_display(hunk, &snapshot)) + // .filter(|hunk| { + // if is_wrapped { + // true + // } else { + // !hunk.contains_display_row(display_point.row()) + // } + // }) + // .dedup(); + + // if let Some(hunk) = hunks.next() { + // self.change_selections(Some(Autoscroll::fit()), cx, |s| { + // let row = hunk.start_display_row(); + // let point = DisplayPoint::new(row, 0); + // s.select_display_ranges([point..point]); + // }); + + // true + // } else { + // false + // } + // } + + // pub fn go_to_definition(&mut self, _: &GoToDefinition, cx: &mut ViewContext) { + // self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, cx); + // } + + // pub fn go_to_type_definition(&mut self, _: &GoToTypeDefinition, cx: &mut ViewContext) { + // self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, cx); + // } + + // pub fn go_to_definition_split(&mut self, _: &GoToDefinitionSplit, cx: &mut ViewContext) { + // self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, cx); + // } + + // pub fn go_to_type_definition_split( + // &mut self, + // _: &GoToTypeDefinitionSplit, + // cx: &mut ViewContext, + // ) { + // self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, cx); + // } + + // fn go_to_definition_of_kind( + // &mut self, + // kind: GotoDefinitionKind, + // split: bool, + // cx: &mut ViewContext, + // ) { + // let Some(workspace) = self.workspace(cx) else { + // return; + // }; + // let buffer = self.buffer.read(cx); + // let head = self.selections.newest::(cx).head(); + // let (buffer, head) = if let Some(text_anchor) = buffer.text_anchor_for_position(head, cx) { + // text_anchor + // } else { + // return; + // }; + + // let project = workspace.read(cx).project().clone(); + // let definitions = project.update(cx, |project, cx| match kind { + // GotoDefinitionKind::Symbol => project.definition(&buffer, head, cx), + // GotoDefinitionKind::Type => project.type_definition(&buffer, head, cx), + // }); + + // cx.spawn_labeled("Fetching Definition...", |editor, mut cx| async move { + // let definitions = definitions.await?; + // editor.update(&mut cx, |editor, cx| { + // editor.navigate_to_definitions( + // definitions + // .into_iter() + // .map(GoToDefinitionLink::Text) + // .collect(), + // split, + // cx, + // ); + // })?; + // Ok::<(), anyhow::Error>(()) + // }) + // .detach_and_log_err(cx); + // } + + // pub fn navigate_to_definitions( + // &mut self, + // mut definitions: Vec, + // split: bool, + // cx: &mut ViewContext, + // ) { + // let Some(workspace) = self.workspace(cx) else { + // return; + // }; + // let pane = workspace.read(cx).active_pane().clone(); + // // If there is one definition, just open it directly + // if definitions.len() == 1 { + // let definition = definitions.pop().unwrap(); + // let target_task = match definition { + // GoToDefinitionLink::Text(link) => Task::Ready(Some(Ok(Some(link.target)))), + // GoToDefinitionLink::InlayHint(lsp_location, server_id) => { + // self.compute_target_location(lsp_location, server_id, cx) + // } + // }; + // cx.spawn(|editor, mut cx| async move { + // let target = target_task.await.context("target resolution task")?; + // if let Some(target) = target { + // editor.update(&mut cx, |editor, cx| { + // let range = target.range.to_offset(target.buffer.read(cx)); + // let range = editor.range_for_match(&range); + // if Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref() { + // editor.change_selections(Some(Autoscroll::fit()), cx, |s| { + // s.select_ranges([range]); + // }); + // } else { + // cx.window_context().defer(move |cx| { + // let target_editor: ViewHandle = + // workspace.update(cx, |workspace, cx| { + // if split { + // workspace.split_project_item(target.buffer.clone(), cx) + // } else { + // workspace.open_project_item(target.buffer.clone(), cx) + // } + // }); + // target_editor.update(cx, |target_editor, cx| { + // // When selecting a definition in a different buffer, disable the nav history + // // to avoid creating a history entry at the previous cursor location. + // pane.update(cx, |pane, _| pane.disable_history()); + // target_editor.change_selections( + // Some(Autoscroll::fit()), + // cx, + // |s| { + // s.select_ranges([range]); + // }, + // ); + // pane.update(cx, |pane, _| pane.enable_history()); + // }); + // }); + // } + // }) + // } else { + // Ok(()) + // } + // }) + // .detach_and_log_err(cx); + // } else if !definitions.is_empty() { + // let replica_id = self.replica_id(cx); + // cx.spawn(|editor, mut cx| async move { + // let (title, location_tasks) = editor + // .update(&mut cx, |editor, cx| { + // let title = definitions + // .iter() + // .find_map(|definition| match definition { + // GoToDefinitionLink::Text(link) => { + // link.origin.as_ref().map(|origin| { + // let buffer = origin.buffer.read(cx); + // format!( + // "Definitions for {}", + // buffer + // .text_for_range(origin.range.clone()) + // .collect::() + // ) + // }) + // } + // GoToDefinitionLink::InlayHint(_, _) => None, + // }) + // .unwrap_or("Definitions".to_string()); + // let location_tasks = definitions + // .into_iter() + // .map(|definition| match definition { + // GoToDefinitionLink::Text(link) => { + // Task::Ready(Some(Ok(Some(link.target)))) + // } + // GoToDefinitionLink::InlayHint(lsp_location, server_id) => { + // editor.compute_target_location(lsp_location, server_id, cx) + // } + // }) + // .collect::>(); + // (title, location_tasks) + // }) + // .context("location tasks preparation")?; + + // let locations = futures::future::join_all(location_tasks) + // .await + // .into_iter() + // .filter_map(|location| location.transpose()) + // .collect::>() + // .context("location tasks")?; + // workspace.update(&mut cx, |workspace, cx| { + // Self::open_locations_in_multibuffer( + // workspace, locations, replica_id, title, split, cx, + // ) + // }); + + // anyhow::Ok(()) + // }) + // .detach_and_log_err(cx); + // } + // } + + // fn compute_target_location( + // &self, + // lsp_location: lsp::Location, + // server_id: LanguageServerId, + // cx: &mut ViewContext, + // ) -> Task>> { + // let Some(project) = self.project.clone() else { + // return Task::Ready(Some(Ok(None))); + // }; + + // cx.spawn(move |editor, mut cx| async move { + // let location_task = editor.update(&mut cx, |editor, cx| { + // project.update(cx, |project, cx| { + // let language_server_name = + // editor.buffer.read(cx).as_singleton().and_then(|buffer| { + // project + // .language_server_for_buffer(buffer.read(cx), server_id, cx) + // .map(|(_, lsp_adapter)| { + // LanguageServerName(Arc::from(lsp_adapter.name())) + // }) + // }); + // language_server_name.map(|language_server_name| { + // project.open_local_buffer_via_lsp( + // lsp_location.uri.clone(), + // server_id, + // language_server_name, + // cx, + // ) + // }) + // }) + // })?; + // let location = match location_task { + // Some(task) => Some({ + // let target_buffer_handle = task.await.context("open local buffer")?; + // let range = { + // target_buffer_handle.update(&mut cx, |target_buffer, _| { + // let target_start = target_buffer.clip_point_utf16( + // point_from_lsp(lsp_location.range.start), + // Bias::Left, + // ); + // let target_end = target_buffer.clip_point_utf16( + // point_from_lsp(lsp_location.range.end), + // Bias::Left, + // ); + // target_buffer.anchor_after(target_start) + // ..target_buffer.anchor_before(target_end) + // }) + // }; + // Location { + // buffer: target_buffer_handle, + // range, + // } + // }), + // None => None, + // }; + // Ok(location) + // }) + // } + + // pub fn find_all_references( + // workspace: &mut Workspace, + // _: &FindAllReferences, + // cx: &mut ViewContext, + // ) -> Option>> { + // let active_item = workspace.active_item(cx)?; + // let editor_handle = active_item.act_as::(cx)?; + + // let editor = editor_handle.read(cx); + // let buffer = editor.buffer.read(cx); + // let head = editor.selections.newest::(cx).head(); + // let (buffer, head) = buffer.text_anchor_for_position(head, cx)?; + // let replica_id = editor.replica_id(cx); + + // let project = workspace.project().clone(); + // let references = project.update(cx, |project, cx| project.references(&buffer, head, cx)); + // Some(cx.spawn_labeled( + // "Finding All References...", + // |workspace, mut cx| async move { + // let locations = references.await?; + // if locations.is_empty() { + // return Ok(()); + // } + + // workspace.update(&mut cx, |workspace, cx| { + // let title = locations + // .first() + // .as_ref() + // .map(|location| { + // let buffer = location.buffer.read(cx); + // format!( + // "References to `{}`", + // buffer + // .text_for_range(location.range.clone()) + // .collect::() + // ) + // }) + // .unwrap(); + // Self::open_locations_in_multibuffer( + // workspace, locations, replica_id, title, false, cx, + // ); + // })?; + + // Ok(()) + // }, + // )) + // } + + // /// Opens a multibuffer with the given project locations in it + // pub fn open_locations_in_multibuffer( + // workspace: &mut Workspace, + // mut locations: Vec, + // replica_id: ReplicaId, + // title: String, + // split: bool, + // cx: &mut ViewContext, + // ) { + // // If there are multiple definitions, open them in a multibuffer + // locations.sort_by_key(|location| location.buffer.read(cx).remote_id()); + // let mut locations = locations.into_iter().peekable(); + // let mut ranges_to_highlight = Vec::new(); + + // let excerpt_buffer = cx.add_model(|cx| { + // let mut multibuffer = MultiBuffer::new(replica_id); + // while let Some(location) = locations.next() { + // let buffer = location.buffer.read(cx); + // let mut ranges_for_buffer = Vec::new(); + // let range = location.range.to_offset(buffer); + // ranges_for_buffer.push(range.clone()); + + // while let Some(next_location) = locations.peek() { + // if next_location.buffer == location.buffer { + // ranges_for_buffer.push(next_location.range.to_offset(buffer)); + // locations.next(); + // } else { + // break; + // } + // } + + // ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end))); + // ranges_to_highlight.extend(multibuffer.push_excerpts_with_context_lines( + // location.buffer.clone(), + // ranges_for_buffer, + // 1, + // cx, + // )) + // } + + // multibuffer.with_title(title) + // }); + + // let editor = cx.add_view(|cx| { + // Editor::for_multibuffer(excerpt_buffer, Some(workspace.project().clone()), cx) + // }); + // editor.update(cx, |editor, cx| { + // editor.highlight_background::( + // ranges_to_highlight, + // |theme| theme.editor.highlighted_line_background, + // cx, + // ); + // }); + // if split { + // workspace.split_item(SplitDirection::Right, Box::new(editor), cx); + // } else { + // workspace.add_item(Box::new(editor), cx); + // } + // } + + // pub fn rename(&mut self, _: &Rename, cx: &mut ViewContext) -> Option>> { + // use language::ToOffset as _; + + // let project = self.project.clone()?; + // let selection = self.selections.newest_anchor().clone(); + // let (cursor_buffer, cursor_buffer_position) = self + // .buffer + // .read(cx) + // .text_anchor_for_position(selection.head(), cx)?; + // let (tail_buffer, _) = self + // .buffer + // .read(cx) + // .text_anchor_for_position(selection.tail(), cx)?; + // if tail_buffer != cursor_buffer { + // return None; + // } + + // let snapshot = cursor_buffer.read(cx).snapshot(); + // let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot); + // let prepare_rename = project.update(cx, |project, cx| { + // project.prepare_rename(cursor_buffer, cursor_buffer_offset, cx) + // }); + + // Some(cx.spawn(|this, mut cx| async move { + // let rename_range = if let Some(range) = prepare_rename.await? { + // Some(range) + // } else { + // this.update(&mut cx, |this, cx| { + // let buffer = this.buffer.read(cx).snapshot(cx); + // let mut buffer_highlights = this + // .document_highlights_for_position(selection.head(), &buffer) + // .filter(|highlight| { + // highlight.start.excerpt_id == selection.head().excerpt_id + // && highlight.end.excerpt_id == selection.head().excerpt_id + // }); + // buffer_highlights + // .next() + // .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor) + // })? + // }; + // if let Some(rename_range) = rename_range { + // let rename_buffer_range = rename_range.to_offset(&snapshot); + // let cursor_offset_in_rename_range = + // cursor_buffer_offset.saturating_sub(rename_buffer_range.start); + + // this.update(&mut cx, |this, cx| { + // this.take_rename(false, cx); + // let style = this.style(cx); + // let buffer = this.buffer.read(cx).read(cx); + // let cursor_offset = selection.head().to_offset(&buffer); + // let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range); + // let rename_end = rename_start + rename_buffer_range.len(); + // let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end); + // let mut old_highlight_id = None; + // let old_name: Arc = buffer + // .chunks(rename_start..rename_end, true) + // .map(|chunk| { + // if old_highlight_id.is_none() { + // old_highlight_id = chunk.syntax_highlight_id; + // } + // chunk.text + // }) + // .collect::() + // .into(); + + // drop(buffer); + + // // Position the selection in the rename editor so that it matches the current selection. + // this.show_local_selections = false; + // let rename_editor = cx.add_view(|cx| { + // let mut editor = Editor::single_line(None, cx); + // if let Some(old_highlight_id) = old_highlight_id { + // editor.override_text_style = + // Some(Box::new(move |style| old_highlight_id.style(&style.syntax))); + // } + // editor.buffer.update(cx, |buffer, cx| { + // buffer.edit([(0..0, old_name.clone())], None, cx) + // }); + // editor.select_all(&SelectAll, cx); + // editor + // }); + + // let ranges = this + // .clear_background_highlights::(cx) + // .into_iter() + // .flat_map(|(_, ranges)| ranges.into_iter()) + // .chain( + // this.clear_background_highlights::(cx) + // .into_iter() + // .flat_map(|(_, ranges)| ranges.into_iter()), + // ) + // .collect(); + + // this.highlight_text::( + // ranges, + // HighlightStyle { + // fade_out: Some(style.rename_fade), + // ..Default::default() + // }, + // cx, + // ); + // cx.focus(&rename_editor); + // let block_id = this.insert_blocks( + // [BlockProperties { + // style: BlockStyle::Flex, + // position: range.start.clone(), + // height: 1, + // render: Arc::new({ + // let editor = rename_editor.clone(); + // move |cx: &mut BlockContext| { + // ChildView::new(&editor, cx) + // .contained() + // .with_padding_left(cx.anchor_x) + // .into_any() + // } + // }), + // disposition: BlockDisposition::Below, + // }], + // Some(Autoscroll::fit()), + // cx, + // )[0]; + // this.pending_rename = Some(RenameState { + // range, + // old_name, + // editor: rename_editor, + // block_id, + // }); + // })?; + // } + + // Ok(()) + // })) + // } + + // pub fn confirm_rename( + // workspace: &mut Workspace, + // _: &ConfirmRename, + // cx: &mut ViewContext, + // ) -> Option>> { + // let editor = workspace.active_item(cx)?.act_as::(cx)?; + + // let (buffer, range, old_name, new_name) = editor.update(cx, |editor, cx| { + // let rename = editor.take_rename(false, cx)?; + // let buffer = editor.buffer.read(cx); + // let (start_buffer, start) = + // buffer.text_anchor_for_position(rename.range.start.clone(), cx)?; + // let (end_buffer, end) = + // buffer.text_anchor_for_position(rename.range.end.clone(), cx)?; + // if start_buffer == end_buffer { + // let new_name = rename.editor.read(cx).text(cx); + // Some((start_buffer, start..end, rename.old_name, new_name)) + // } else { + // None + // } + // })?; + + // let rename = workspace.project().clone().update(cx, |project, cx| { + // project.perform_rename(buffer.clone(), range.start, new_name.clone(), true, cx) + // }); + + // let editor = editor.downgrade(); + // Some(cx.spawn(|workspace, mut cx| async move { + // let project_transaction = rename.await?; + // Self::open_project_transaction( + // &editor, + // workspace, + // project_transaction, + // format!("Rename: {} → {}", old_name, new_name), + // cx.clone(), + // ) + // .await?; + + // editor.update(&mut cx, |editor, cx| { + // editor.refresh_document_highlights(cx); + // })?; + // Ok(()) + // })) + // } + + // fn take_rename( + // &mut self, + // moving_cursor: bool, + // cx: &mut ViewContext, + // ) -> Option { + // let rename = self.pending_rename.take()?; + // self.remove_blocks( + // [rename.block_id].into_iter().collect(), + // Some(Autoscroll::fit()), + // cx, + // ); + // self.clear_highlights::(cx); + // self.show_local_selections = true; + + // if moving_cursor { + // let rename_editor = rename.editor.read(cx); + // let cursor_in_rename_editor = rename_editor.selections.newest::(cx).head(); + + // // Update the selection to match the position of the selection inside + // // the rename editor. + // let snapshot = self.buffer.read(cx).read(cx); + // let rename_range = rename.range.to_offset(&snapshot); + // let cursor_in_editor = snapshot + // .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left) + // .min(rename_range.end); + // drop(snapshot); + + // self.change_selections(None, cx, |s| { + // s.select_ranges(vec![cursor_in_editor..cursor_in_editor]) + // }); + // } else { + // self.refresh_document_highlights(cx); + // } + + // Some(rename) + // } + + // #[cfg(any(test, feature = "test-support"))] + // pub fn pending_rename(&self) -> Option<&RenameState> { + // self.pending_rename.as_ref() + // } + + // fn format(&mut self, _: &Format, cx: &mut ViewContext) -> Option>> { + // let project = match &self.project { + // Some(project) => project.clone(), + // None => return None, + // }; + + // Some(self.perform_format(project, FormatTrigger::Manual, cx)) + // } + + // fn perform_format( + // &mut self, + // project: Model, + // trigger: FormatTrigger, + // cx: &mut ViewContext, + // ) -> Task> { + // let buffer = self.buffer().clone(); + // let buffers = buffer.read(cx).all_buffers(); + + // let mut timeout = cx.background().timer(FORMAT_TIMEOUT).fuse(); + // let format = project.update(cx, |project, cx| project.format(buffers, true, trigger, cx)); + + // cx.spawn(|_, mut cx| async move { + // let transaction = futures::select_biased! { + // _ = timeout => { + // log::warn!("timed out waiting for formatting"); + // None + // } + // transaction = format.log_err().fuse() => transaction, + // }; + + // buffer.update(&mut cx, |buffer, cx| { + // if let Some(transaction) = transaction { + // if !buffer.is_singleton() { + // buffer.push_transaction(&transaction.0, cx); + // } + // } + + // cx.notify(); + // }); + + // Ok(()) + // }) + // } + + // fn restart_language_server(&mut self, _: &RestartLanguageServer, cx: &mut ViewContext) { + // if let Some(project) = self.project.clone() { + // self.buffer.update(cx, |multi_buffer, cx| { + // project.update(cx, |project, cx| { + // project.restart_language_servers_for_buffers(multi_buffer.all_buffers(), cx); + // }); + // }) + // } + // } + + // fn show_character_palette(&mut self, _: &ShowCharacterPalette, cx: &mut ViewContext) { + // cx.show_character_palette(); + // } + + // fn refresh_active_diagnostics(&mut self, cx: &mut ViewContext) { + // if let Some(active_diagnostics) = self.active_diagnostics.as_mut() { + // let buffer = self.buffer.read(cx).snapshot(cx); + // let primary_range_start = active_diagnostics.primary_range.start.to_offset(&buffer); + // let is_valid = buffer + // .diagnostics_in_range::<_, usize>(active_diagnostics.primary_range.clone(), false) + // .any(|entry| { + // entry.diagnostic.is_primary + // && !entry.range.is_empty() + // && entry.range.start == primary_range_start + // && entry.diagnostic.message == active_diagnostics.primary_message + // }); + + // if is_valid != active_diagnostics.is_valid { + // active_diagnostics.is_valid = is_valid; + // let mut new_styles = HashMap::default(); + // for (block_id, diagnostic) in &active_diagnostics.blocks { + // new_styles.insert( + // *block_id, + // diagnostic_block_renderer(diagnostic.clone(), is_valid), + // ); + // } + // self.display_map + // .update(cx, |display_map, _| display_map.replace_blocks(new_styles)); + // } + // } + // } + + // fn activate_diagnostics(&mut self, group_id: usize, cx: &mut ViewContext) -> bool { + // self.dismiss_diagnostics(cx); + // self.active_diagnostics = self.display_map.update(cx, |display_map, cx| { + // let buffer = self.buffer.read(cx).snapshot(cx); + + // let mut primary_range = None; + // let mut primary_message = None; + // let mut group_end = Point::zero(); + // let diagnostic_group = buffer + // .diagnostic_group::(group_id) + // .map(|entry| { + // if entry.range.end > group_end { + // group_end = entry.range.end; + // } + // if entry.diagnostic.is_primary { + // primary_range = Some(entry.range.clone()); + // primary_message = Some(entry.diagnostic.message.clone()); + // } + // entry + // }) + // .collect::>(); + // let primary_range = primary_range?; + // let primary_message = primary_message?; + // let primary_range = + // buffer.anchor_after(primary_range.start)..buffer.anchor_before(primary_range.end); + + // let blocks = display_map + // .insert_blocks( + // diagnostic_group.iter().map(|entry| { + // let diagnostic = entry.diagnostic.clone(); + // let message_height = diagnostic.message.lines().count() as u8; + // BlockProperties { + // style: BlockStyle::Fixed, + // position: buffer.anchor_after(entry.range.start), + // height: message_height, + // render: diagnostic_block_renderer(diagnostic, true), + // disposition: BlockDisposition::Below, + // } + // }), + // cx, + // ) + // .into_iter() + // .zip(diagnostic_group.into_iter().map(|entry| entry.diagnostic)) + // .collect(); + + // Some(ActiveDiagnosticGroup { + // primary_range, + // primary_message, + // blocks, + // is_valid: true, + // }) + // }); + // self.active_diagnostics.is_some() + // } + + // fn dismiss_diagnostics(&mut self, cx: &mut ViewContext) { + // if let Some(active_diagnostic_group) = self.active_diagnostics.take() { + // self.display_map.update(cx, |display_map, cx| { + // display_map.remove_blocks(active_diagnostic_group.blocks.into_keys().collect(), cx); + // }); + // cx.notify(); + // } + // } + + // pub fn set_selections_from_remote( + // &mut self, + // selections: Vec>, + // pending_selection: Option>, + // cx: &mut ViewContext, + // ) { + // let old_cursor_position = self.selections.newest_anchor().head(); + // self.selections.change_with(cx, |s| { + // s.select_anchors(selections); + // if let Some(pending_selection) = pending_selection { + // s.set_pending(pending_selection, SelectMode::Character); + // } else { + // s.clear_pending(); + // } + // }); + // self.selections_did_change(false, &old_cursor_position, cx); + // } + + // fn push_to_selection_history(&mut self) { + // self.selection_history.push(SelectionHistoryEntry { + // selections: self.selections.disjoint_anchors(), + // select_next_state: self.select_next_state.clone(), + // select_prev_state: self.select_prev_state.clone(), + // add_selections_state: self.add_selections_state.clone(), + // }); + // } + + // pub fn transact( + // &mut self, + // cx: &mut ViewContext, + // update: impl FnOnce(&mut Self, &mut ViewContext), + // ) -> Option { + // self.start_transaction_at(Instant::now(), cx); + // update(self, cx); + // self.end_transaction_at(Instant::now(), cx) + // } + + // fn start_transaction_at(&mut self, now: Instant, cx: &mut ViewContext) { + // self.end_selection(cx); + // if let Some(tx_id) = self + // .buffer + // .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx)) + // { + // self.selection_history + // .insert_transaction(tx_id, self.selections.disjoint_anchors()); + // } + // } + + // fn end_transaction_at( + // &mut self, + // now: Instant, + // cx: &mut ViewContext, + // ) -> Option { + // if let Some(tx_id) = self + // .buffer + // .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx)) + // { + // if let Some((_, end_selections)) = self.selection_history.transaction_mut(tx_id) { + // *end_selections = Some(self.selections.disjoint_anchors()); + // } else { + // error!("unexpectedly ended a transaction that wasn't started by this editor"); + // } + + // cx.emit(Event::Edited); + // Some(tx_id) + // } else { + // None + // } + // } + + // pub fn fold(&mut self, _: &Fold, cx: &mut ViewContext) { + // let mut fold_ranges = Vec::new(); + + // let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); + + // let selections = self.selections.all_adjusted(cx); + // for selection in selections { + // let range = selection.range().sorted(); + // let buffer_start_row = range.start.row; + + // for row in (0..=range.end.row).rev() { + // let fold_range = display_map.foldable_range(row); + + // if let Some(fold_range) = fold_range { + // if fold_range.end.row >= buffer_start_row { + // fold_ranges.push(fold_range); + // if row <= range.start.row { + // break; + // } + // } + // } + // } + // } + + // self.fold_ranges(fold_ranges, true, cx); + // } + + // pub fn fold_at(&mut self, fold_at: &FoldAt, cx: &mut ViewContext) { + // let buffer_row = fold_at.buffer_row; + // let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); + + // if let Some(fold_range) = display_map.foldable_range(buffer_row) { + // let autoscroll = self + // .selections + // .all::(cx) + // .iter() + // .any(|selection| fold_range.overlaps(&selection.range())); + + // self.fold_ranges(std::iter::once(fold_range), autoscroll, cx); + // } + // } + + // pub fn unfold_lines(&mut self, _: &UnfoldLines, cx: &mut ViewContext) { + // let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); + // let buffer = &display_map.buffer_snapshot; + // let selections = self.selections.all::(cx); + // let ranges = selections + // .iter() + // .map(|s| { + // let range = s.display_range(&display_map).sorted(); + // let mut start = range.start.to_point(&display_map); + // let mut end = range.end.to_point(&display_map); + // start.column = 0; + // end.column = buffer.line_len(end.row); + // start..end + // }) + // .collect::>(); + + // self.unfold_ranges(ranges, true, true, cx); + // } + + // pub fn unfold_at(&mut self, unfold_at: &UnfoldAt, cx: &mut ViewContext) { + // let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); + + // let intersection_range = Point::new(unfold_at.buffer_row, 0) + // ..Point::new( + // unfold_at.buffer_row, + // display_map.buffer_snapshot.line_len(unfold_at.buffer_row), + // ); + + // let autoscroll = self + // .selections + // .all::(cx) + // .iter() + // .any(|selection| selection.range().overlaps(&intersection_range)); + + // self.unfold_ranges(std::iter::once(intersection_range), true, autoscroll, cx) + // } + + // pub fn fold_selected_ranges(&mut self, _: &FoldSelectedRanges, cx: &mut ViewContext) { + // let selections = self.selections.all::(cx); + // let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); + // let line_mode = self.selections.line_mode; + // let ranges = selections.into_iter().map(|s| { + // if line_mode { + // let start = Point::new(s.start.row, 0); + // let end = Point::new(s.end.row, display_map.buffer_snapshot.line_len(s.end.row)); + // start..end + // } else { + // s.start..s.end + // } + // }); + // self.fold_ranges(ranges, true, cx); + // } + + // pub fn fold_ranges( + // &mut self, + // ranges: impl IntoIterator>, + // auto_scroll: bool, + // cx: &mut ViewContext, + // ) { + // let mut ranges = ranges.into_iter().peekable(); + // if ranges.peek().is_some() { + // self.display_map.update(cx, |map, cx| map.fold(ranges, cx)); + + // if auto_scroll { + // self.request_autoscroll(Autoscroll::fit(), cx); + // } + + // cx.notify(); + // } + // } + + // pub fn unfold_ranges( + // &mut self, + // ranges: impl IntoIterator>, + // inclusive: bool, + // auto_scroll: bool, + // cx: &mut ViewContext, + // ) { + // let mut ranges = ranges.into_iter().peekable(); + // if ranges.peek().is_some() { + // self.display_map + // .update(cx, |map, cx| map.unfold(ranges, inclusive, cx)); + // if auto_scroll { + // self.request_autoscroll(Autoscroll::fit(), cx); + // } + + // cx.notify(); + // } + // } + + // pub fn gutter_hover( + // &mut self, + // GutterHover { hovered }: &GutterHover, + // cx: &mut ViewContext, + // ) { + // self.gutter_hovered = *hovered; + // cx.notify(); + // } + + // pub fn insert_blocks( + // &mut self, + // blocks: impl IntoIterator>, + // autoscroll: Option, + // cx: &mut ViewContext, + // ) -> Vec { + // let blocks = self + // .display_map + // .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx)); + // if let Some(autoscroll) = autoscroll { + // self.request_autoscroll(autoscroll, cx); + // } + // blocks + // } + + // pub fn replace_blocks( + // &mut self, + // blocks: HashMap, + // autoscroll: Option, + // cx: &mut ViewContext, + // ) { + // self.display_map + // .update(cx, |display_map, _| display_map.replace_blocks(blocks)); + // if let Some(autoscroll) = autoscroll { + // self.request_autoscroll(autoscroll, cx); + // } + // } + + // pub fn remove_blocks( + // &mut self, + // block_ids: HashSet, + // autoscroll: Option, + // cx: &mut ViewContext, + // ) { + // self.display_map.update(cx, |display_map, cx| { + // display_map.remove_blocks(block_ids, cx) + // }); + // if let Some(autoscroll) = autoscroll { + // self.request_autoscroll(autoscroll, cx); + // } + // } + + // pub fn longest_row(&self, cx: &mut AppContext) -> u32 { + // self.display_map + // .update(cx, |map, cx| map.snapshot(cx)) + // .longest_row() + // } + + // pub fn max_point(&self, cx: &mut AppContext) -> DisplayPoint { + // self.display_map + // .update(cx, |map, cx| map.snapshot(cx)) + // .max_point() + // } + + // pub fn text(&self, cx: &AppContext) -> String { + // self.buffer.read(cx).read(cx).text() + // } + + // pub fn set_text(&mut self, text: impl Into>, cx: &mut ViewContext) { + // self.transact(cx, |this, cx| { + // this.buffer + // .read(cx) + // .as_singleton() + // .expect("you can only call set_text on editors for singleton buffers") + // .update(cx, |buffer, cx| buffer.set_text(text, cx)); + // }); + // } + + // pub fn display_text(&self, cx: &mut AppContext) -> String { + // self.display_map + // .update(cx, |map, cx| map.snapshot(cx)) + // .text() + // } + + // pub fn wrap_guides(&self, cx: &AppContext) -> SmallVec<[(usize, bool); 2]> { + // let mut wrap_guides = smallvec::smallvec![]; + + // if self.show_wrap_guides == Some(false) { + // return wrap_guides; + // } + + // let settings = self.buffer.read(cx).settings_at(0, cx); + // if settings.show_wrap_guides { + // if let SoftWrap::Column(soft_wrap) = self.soft_wrap_mode(cx) { + // wrap_guides.push((soft_wrap as usize, true)); + // } + // wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false))) + // } + + // wrap_guides + // } + + // pub fn soft_wrap_mode(&self, cx: &AppContext) -> SoftWrap { + // let settings = self.buffer.read(cx).settings_at(0, cx); + // let mode = self + // .soft_wrap_mode_override + // .unwrap_or_else(|| settings.soft_wrap); + // match mode { + // language_settings::SoftWrap::None => SoftWrap::None, + // language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth, + // language_settings::SoftWrap::PreferredLineLength => { + // SoftWrap::Column(settings.preferred_line_length) + // } + // } + // } + + // pub fn set_soft_wrap_mode( + // &mut self, + // mode: language_settings::SoftWrap, + // cx: &mut ViewContext, + // ) { + // self.soft_wrap_mode_override = Some(mode); + // cx.notify(); + // } + + // pub fn set_wrap_width(&self, width: Option, cx: &mut AppContext) -> bool { + // self.display_map + // .update(cx, |map, cx| map.set_wrap_width(width, cx)) + // } + + // pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, cx: &mut ViewContext) { + // if self.soft_wrap_mode_override.is_some() { + // self.soft_wrap_mode_override.take(); + // } else { + // let soft_wrap = match self.soft_wrap_mode(cx) { + // SoftWrap::None => language_settings::SoftWrap::EditorWidth, + // SoftWrap::EditorWidth | SoftWrap::Column(_) => language_settings::SoftWrap::None, + // }; + // self.soft_wrap_mode_override = Some(soft_wrap); + // } + // cx.notify(); + // } + + // pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut ViewContext) { + // self.show_gutter = show_gutter; + // cx.notify(); + // } + + // pub fn set_show_wrap_guides(&mut self, show_gutter: bool, cx: &mut ViewContext) { + // self.show_wrap_guides = Some(show_gutter); + // cx.notify(); + // } + + // pub fn reveal_in_finder(&mut self, _: &RevealInFinder, cx: &mut ViewContext) { + // if let Some(buffer) = self.buffer().read(cx).as_singleton() { + // if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) { + // cx.reveal_path(&file.abs_path(cx)); + // } + // } + // } + + // pub fn copy_path(&mut self, _: &CopyPath, cx: &mut ViewContext) { + // if let Some(buffer) = self.buffer().read(cx).as_singleton() { + // if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) { + // if let Some(path) = file.abs_path(cx).to_str() { + // cx.write_to_clipboard(ClipboardItem::new(path.to_string())); + // } + // } + // } + // } + + // pub fn copy_relative_path(&mut self, _: &CopyRelativePath, cx: &mut ViewContext) { + // if let Some(buffer) = self.buffer().read(cx).as_singleton() { + // if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) { + // if let Some(path) = file.path().to_str() { + // cx.write_to_clipboard(ClipboardItem::new(path.to_string())); + // } + // } + // } + // } + + // pub fn highlight_rows(&mut self, rows: Option>) { + // self.highlighted_rows = rows; + // } + + // pub fn highlighted_rows(&self) -> Option> { + // self.highlighted_rows.clone() + // } + + // pub fn highlight_background( + // &mut self, + // ranges: Vec>, + // color_fetcher: fn(&Theme) -> Color, + // cx: &mut ViewContext, + // ) { + // self.background_highlights + // .insert(TypeId::of::(), (color_fetcher, ranges)); + // cx.notify(); + // } + + // pub fn highlight_inlay_background( + // &mut self, + // ranges: Vec, + // color_fetcher: fn(&Theme) -> Color, + // cx: &mut ViewContext, + // ) { + // // TODO: no actual highlights happen for inlays currently, find a way to do that + // self.inlay_background_highlights + // .insert(Some(TypeId::of::()), (color_fetcher, ranges)); + // cx.notify(); + // } + + // pub fn clear_background_highlights( + // &mut self, + // cx: &mut ViewContext, + // ) -> Option { + // let text_highlights = self.background_highlights.remove(&TypeId::of::()); + // let inlay_highlights = self + // .inlay_background_highlights + // .remove(&Some(TypeId::of::())); + // if text_highlights.is_some() || inlay_highlights.is_some() { + // cx.notify(); + // } + // text_highlights + // } + + // #[cfg(feature = "test-support")] + // pub fn all_text_background_highlights( + // &mut self, + // cx: &mut ViewContext, + // ) -> Vec<(Range, Color)> { + // let snapshot = self.snapshot(cx); + // let buffer = &snapshot.buffer_snapshot; + // let start = buffer.anchor_before(0); + // let end = buffer.anchor_after(buffer.len()); + // let theme = theme::current(cx); + // self.background_highlights_in_range(start..end, &snapshot, theme.as_ref()) + // } + + // fn document_highlights_for_position<'a>( + // &'a self, + // position: Anchor, + // buffer: &'a MultiBufferSnapshot, + // ) -> impl 'a + Iterator> { + // let read_highlights = self + // .background_highlights + // .get(&TypeId::of::()) + // .map(|h| &h.1); + // let write_highlights = self + // .background_highlights + // .get(&TypeId::of::()) + // .map(|h| &h.1); + // let left_position = position.bias_left(buffer); + // let right_position = position.bias_right(buffer); + // read_highlights + // .into_iter() + // .chain(write_highlights) + // .flat_map(move |ranges| { + // let start_ix = match ranges.binary_search_by(|probe| { + // let cmp = probe.end.cmp(&left_position, buffer); + // if cmp.is_ge() { + // Ordering::Greater + // } else { + // Ordering::Less + // } + // }) { + // Ok(i) | Err(i) => i, + // }; + + // let right_position = right_position.clone(); + // ranges[start_ix..] + // .iter() + // .take_while(move |range| range.start.cmp(&right_position, buffer).is_le()) + // }) + // } + + // pub fn background_highlights_in_range( + // &self, + // search_range: Range, + // display_snapshot: &DisplaySnapshot, + // theme: &Theme, + // ) -> Vec<(Range, Color)> { + // let mut results = Vec::new(); + // for (color_fetcher, ranges) in self.background_highlights.values() { + // let color = color_fetcher(theme); + // let start_ix = match ranges.binary_search_by(|probe| { + // let cmp = probe + // .end + // .cmp(&search_range.start, &display_snapshot.buffer_snapshot); + // if cmp.is_gt() { + // Ordering::Greater + // } else { + // Ordering::Less + // } + // }) { + // Ok(i) | Err(i) => i, + // }; + // for range in &ranges[start_ix..] { + // if range + // .start + // .cmp(&search_range.end, &display_snapshot.buffer_snapshot) + // .is_ge() + // { + // break; + // } + + // let start = range.start.to_display_point(&display_snapshot); + // let end = range.end.to_display_point(&display_snapshot); + // results.push((start..end, color)) + // } + // } + // results + // } + + // pub fn background_highlight_row_ranges( + // &self, + // search_range: Range, + // display_snapshot: &DisplaySnapshot, + // count: usize, + // ) -> Vec> { + // let mut results = Vec::new(); + // let Some((_, ranges)) = self.background_highlights.get(&TypeId::of::()) else { + // return vec![]; + // }; + + // let start_ix = match ranges.binary_search_by(|probe| { + // let cmp = probe + // .end + // .cmp(&search_range.start, &display_snapshot.buffer_snapshot); + // if cmp.is_gt() { + // Ordering::Greater + // } else { + // Ordering::Less + // } + // }) { + // Ok(i) | Err(i) => i, + // }; + // let mut push_region = |start: Option, end: Option| { + // if let (Some(start_display), Some(end_display)) = (start, end) { + // results.push( + // start_display.to_display_point(display_snapshot) + // ..=end_display.to_display_point(display_snapshot), + // ); + // } + // }; + // let mut start_row: Option = None; + // let mut end_row: Option = None; + // if ranges.len() > count { + // return Vec::new(); + // } + // for range in &ranges[start_ix..] { + // if range + // .start + // .cmp(&search_range.end, &display_snapshot.buffer_snapshot) + // .is_ge() + // { + // break; + // } + // let end = range.end.to_point(&display_snapshot.buffer_snapshot); + // if let Some(current_row) = &end_row { + // if end.row == current_row.row { + // continue; + // } + // } + // let start = range.start.to_point(&display_snapshot.buffer_snapshot); + // if start_row.is_none() { + // assert_eq!(end_row, None); + // start_row = Some(start); + // end_row = Some(end); + // continue; + // } + // if let Some(current_end) = end_row.as_mut() { + // if start.row > current_end.row + 1 { + // push_region(start_row, end_row); + // start_row = Some(start); + // end_row = Some(end); + // } else { + // // Merge two hunks. + // *current_end = end; + // } + // } else { + // unreachable!(); + // } + // } + // // We might still have a hunk that was not rendered (if there was a search hit on the last line) + // push_region(start_row, end_row); + // results + // } + + // pub fn highlight_text( + // &mut self, + // ranges: Vec>, + // style: HighlightStyle, + // cx: &mut ViewContext, + // ) { + // self.display_map.update(cx, |map, _| { + // map.highlight_text(TypeId::of::(), ranges, style) + // }); + // cx.notify(); + // } + + // pub fn highlight_inlays( + // &mut self, + // highlights: Vec, + // style: HighlightStyle, + // cx: &mut ViewContext, + // ) { + // self.display_map.update(cx, |map, _| { + // map.highlight_inlays(TypeId::of::(), highlights, style) + // }); + // cx.notify(); + // } + + // pub fn text_highlights<'a, T: 'static>( + // &'a self, + // cx: &'a AppContext, + // ) -> Option<(HighlightStyle, &'a [Range])> { + // self.display_map.read(cx).text_highlights(TypeId::of::()) + // } + + // pub fn clear_highlights(&mut self, cx: &mut ViewContext) { + // let cleared = self + // .display_map + // .update(cx, |map, _| map.clear_highlights(TypeId::of::())); + // if cleared { + // cx.notify(); + // } + // } + + // pub fn show_local_cursors(&self, cx: &AppContext) -> bool { + // self.blink_manager.read(cx).visible() && self.focused + // } + + // fn on_buffer_changed(&mut self, _: Model, cx: &mut ViewContext) { + // cx.notify(); + // } + + // fn on_buffer_event( + // &mut self, + // multibuffer: Model, + // event: &multi_buffer::Event, + // cx: &mut ViewContext, + // ) { + // match event { + // multi_buffer::Event::Edited { + // sigleton_buffer_edited, + // } => { + // self.refresh_active_diagnostics(cx); + // self.refresh_code_actions(cx); + // if self.has_active_copilot_suggestion(cx) { + // self.update_visible_copilot_suggestion(cx); + // } + // cx.emit(Event::BufferEdited); + + // if *sigleton_buffer_edited { + // if let Some(project) = &self.project { + // let project = project.read(cx); + // let languages_affected = multibuffer + // .read(cx) + // .all_buffers() + // .into_iter() + // .filter_map(|buffer| { + // let buffer = buffer.read(cx); + // let language = buffer.language()?; + // if project.is_local() + // && project.language_servers_for_buffer(buffer, cx).count() == 0 + // { + // None + // } else { + // Some(language) + // } + // }) + // .cloned() + // .collect::>(); + // if !languages_affected.is_empty() { + // self.refresh_inlay_hints( + // InlayHintRefreshReason::BufferEdited(languages_affected), + // cx, + // ); + // } + // } + // } + // } + // multi_buffer::Event::ExcerptsAdded { + // buffer, + // predecessor, + // excerpts, + // } => { + // cx.emit(Event::ExcerptsAdded { + // buffer: buffer.clone(), + // predecessor: *predecessor, + // excerpts: excerpts.clone(), + // }); + // self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx); + // } + // multi_buffer::Event::ExcerptsRemoved { ids } => { + // self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx); + // cx.emit(Event::ExcerptsRemoved { ids: ids.clone() }) + // } + // multi_buffer::Event::Reparsed => cx.emit(Event::Reparsed), + // multi_buffer::Event::DirtyChanged => cx.emit(Event::DirtyChanged), + // multi_buffer::Event::Saved => cx.emit(Event::Saved), + // multi_buffer::Event::FileHandleChanged => cx.emit(Event::TitleChanged), + // multi_buffer::Event::Reloaded => cx.emit(Event::TitleChanged), + // multi_buffer::Event::DiffBaseChanged => cx.emit(Event::DiffBaseChanged), + // multi_buffer::Event::Closed => cx.emit(Event::Closed), + // multi_buffer::Event::DiagnosticsUpdated => { + // self.refresh_active_diagnostics(cx); + // } + // _ => {} + // }; + // } + + // fn on_display_map_changed(&mut self, _: Model, cx: &mut ViewContext) { + // cx.notify(); + // } + + // fn settings_changed(&mut self, cx: &mut ViewContext) { + // self.refresh_copilot_suggestions(true, cx); + // self.refresh_inlay_hints( + // InlayHintRefreshReason::SettingsChange(inlay_hint_settings( + // self.selections.newest_anchor().head(), + // &self.buffer.read(cx).snapshot(cx), + // cx, + // )), + // cx, + // ); + // } + + // pub fn set_searchable(&mut self, searchable: bool) { + // self.searchable = searchable; + // } + + // pub fn searchable(&self) -> bool { + // self.searchable + // } + + // fn open_excerpts(workspace: &mut Workspace, _: &OpenExcerpts, cx: &mut ViewContext) { + // let active_item = workspace.active_item(cx); + // let editor_handle = if let Some(editor) = active_item + // .as_ref() + // .and_then(|item| item.act_as::(cx)) + // { + // editor + // } else { + // cx.propagate_action(); + // return; + // }; + + // let editor = editor_handle.read(cx); + // let buffer = editor.buffer.read(cx); + // if buffer.is_singleton() { + // cx.propagate_action(); + // return; + // } + + // let mut new_selections_by_buffer = HashMap::default(); + // for selection in editor.selections.all::(cx) { + // for (buffer, mut range, _) in + // buffer.range_to_buffer_ranges(selection.start..selection.end, cx) + // { + // if selection.reversed { + // mem::swap(&mut range.start, &mut range.end); + // } + // new_selections_by_buffer + // .entry(buffer) + // .or_insert(Vec::new()) + // .push(range) + // } + // } + + // editor_handle.update(cx, |editor, cx| { + // editor.push_to_nav_history(editor.selections.newest_anchor().head(), None, cx); + // }); + // let pane = workspace.active_pane().clone(); + // pane.update(cx, |pane, _| pane.disable_history()); + + // // We defer the pane interaction because we ourselves are a workspace item + // // and activating a new item causes the pane to call a method on us reentrantly, + // // which panics if we're on the stack. + // cx.defer(move |workspace, cx| { + // for (buffer, ranges) in new_selections_by_buffer.into_iter() { + // let editor = workspace.open_project_item::(buffer, cx); + // editor.update(cx, |editor, cx| { + // editor.change_selections(Some(Autoscroll::newest()), cx, |s| { + // s.select_ranges(ranges); + // }); + // }); + // } + + // pane.update(cx, |pane, _| pane.enable_history()); + // }); + // } + + // fn jump( + // workspace: &mut Workspace, + // path: ProjectPath, + // position: Point, + // anchor: language::Anchor, + // cx: &mut ViewContext, + // ) { + // let editor = workspace.open_path(path, None, true, cx); + // cx.spawn(|_, mut cx| async move { + // let editor = editor + // .await? + // .downcast::() + // .ok_or_else(|| anyhow!("opened item was not an editor"))? + // .downgrade(); + // editor.update(&mut cx, |editor, cx| { + // let buffer = editor + // .buffer() + // .read(cx) + // .as_singleton() + // .ok_or_else(|| anyhow!("cannot jump in a multi-buffer"))?; + // let buffer = buffer.read(cx); + // let cursor = if buffer.can_resolve(&anchor) { + // language::ToPoint::to_point(&anchor, buffer) + // } else { + // buffer.clip_point(position, Bias::Left) + // }; + + // let nav_history = editor.nav_history.take(); + // editor.change_selections(Some(Autoscroll::newest()), cx, |s| { + // s.select_ranges([cursor..cursor]); + // }); + // editor.nav_history = nav_history; + + // anyhow::Ok(()) + // })??; + + // anyhow::Ok(()) + // }) + // .detach_and_log_err(cx); + // } + + // fn marked_text_ranges(&self, cx: &AppContext) -> Option>> { + // let snapshot = self.buffer.read(cx).read(cx); + // let (_, ranges) = self.text_highlights::(cx)?; + // Some( + // ranges + // .iter() + // .map(move |range| { + // range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot) + // }) + // .collect(), + // ) + // } + + // fn selection_replacement_ranges( + // &self, + // range: Range, + // cx: &AppContext, + // ) -> Vec> { + // let selections = self.selections.all::(cx); + // let newest_selection = selections + // .iter() + // .max_by_key(|selection| selection.id) + // .unwrap(); + // let start_delta = range.start.0 as isize - newest_selection.start.0 as isize; + // let end_delta = range.end.0 as isize - newest_selection.end.0 as isize; + // let snapshot = self.buffer.read(cx).read(cx); + // selections + // .into_iter() + // .map(|mut selection| { + // selection.start.0 = + // (selection.start.0 as isize).saturating_add(start_delta) as usize; + // selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize; + // snapshot.clip_offset_utf16(selection.start, Bias::Left) + // ..snapshot.clip_offset_utf16(selection.end, Bias::Right) + // }) + // .collect() + // } + + // fn report_copilot_event( + // &self, + // suggestion_id: Option, + // suggestion_accepted: bool, + // cx: &AppContext, + // ) { + // let Some(project) = &self.project else { return }; + + // // If None, we are either getting suggestions in a new, unsaved file, or in a file without an extension + // let file_extension = self + // .buffer + // .read(cx) + // .as_singleton() + // .and_then(|b| b.read(cx).file()) + // .and_then(|file| Path::new(file.file_name(cx)).extension()) + // .and_then(|e| e.to_str()) + // .map(|a| a.to_string()); + + // let telemetry = project.read(cx).client().telemetry().clone(); + // let telemetry_settings = *settings::get::(cx); + + // let event = ClickhouseEvent::Copilot { + // suggestion_id, + // suggestion_accepted, + // file_extension, + // }; + // telemetry.report_clickhouse_event(event, telemetry_settings); + // } + + // #[cfg(any(test, feature = "test-support"))] + // fn report_editor_event( + // &self, + // _operation: &'static str, + // _file_extension: Option, + // _cx: &AppContext, + // ) { + // } + + // #[cfg(not(any(test, feature = "test-support")))] + // fn report_editor_event( + // &self, + // operation: &'static str, + // file_extension: Option, + // cx: &AppContext, + // ) { + // let Some(project) = &self.project else { return }; + + // // If None, we are in a file without an extension + // let file = self + // .buffer + // .read(cx) + // .as_singleton() + // .and_then(|b| b.read(cx).file()); + // let file_extension = file_extension.or(file + // .as_ref() + // .and_then(|file| Path::new(file.file_name(cx)).extension()) + // .and_then(|e| e.to_str()) + // .map(|a| a.to_string())); + + // let vim_mode = cx + // .global::() + // .raw_user_settings() + // .get("vim_mode") + // == Some(&serde_json::Value::Bool(true)); + // let telemetry_settings = *settings::get::(cx); + // let copilot_enabled = all_language_settings(file, cx).copilot_enabled(None, None); + // let copilot_enabled_for_language = self + // .buffer + // .read(cx) + // .settings_at(0, cx) + // .show_copilot_suggestions; + + // let telemetry = project.read(cx).client().telemetry().clone(); + // let event = ClickhouseEvent::Editor { + // file_extension, + // vim_mode, + // operation, + // copilot_enabled, + // copilot_enabled_for_language, + // }; + // telemetry.report_clickhouse_event(event, telemetry_settings) + // } + + // /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines, + // /// with each line being an array of {text, highlight} objects. + // fn copy_highlight_json(&mut self, _: &CopyHighlightJson, cx: &mut ViewContext) { + // let Some(buffer) = self.buffer.read(cx).as_singleton() else { + // return; + // }; + + // #[derive(Serialize)] + // struct Chunk<'a> { + // text: String, + // highlight: Option<&'a str>, + // } + + // let snapshot = buffer.read(cx).snapshot(); + // let range = self + // .selected_text_range(cx) + // .and_then(|selected_range| { + // if selected_range.is_empty() { + // None + // } else { + // Some(selected_range) + // } + // }) + // .unwrap_or_else(|| 0..snapshot.len()); + + // let chunks = snapshot.chunks(range, true); + // let mut lines = Vec::new(); + // let mut line: VecDeque = VecDeque::new(); + + // let theme = &theme::current(cx).editor.syntax; + + // for chunk in chunks { + // let highlight = chunk.syntax_highlight_id.and_then(|id| id.name(theme)); + // let mut chunk_lines = chunk.text.split("\n").peekable(); + // while let Some(text) = chunk_lines.next() { + // let mut merged_with_last_token = false; + // if let Some(last_token) = line.back_mut() { + // if last_token.highlight == highlight { + // last_token.text.push_str(text); + // merged_with_last_token = true; + // } + // } + + // if !merged_with_last_token { + // line.push_back(Chunk { + // text: text.into(), + // highlight, + // }); + // } + + // if chunk_lines.peek().is_some() { + // if line.len() > 1 && line.front().unwrap().text.is_empty() { + // line.pop_front(); + // } + // if line.len() > 1 && line.back().unwrap().text.is_empty() { + // line.pop_back(); + // } + + // lines.push(mem::take(&mut line)); + // } + // } + // } + + // let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else { + // return; + // }; + // cx.write_to_clipboard(ClipboardItem::new(lines)); + // } + + // pub fn inlay_hint_cache(&self) -> &InlayHintCache { + // &self.inlay_hint_cache + // } + + // pub fn replay_insert_event( + // &mut self, + // text: &str, + // relative_utf16_range: Option>, + // cx: &mut ViewContext, + // ) { + // if !self.input_enabled { + // cx.emit(Event::InputIgnored { text: text.into() }); + // return; + // } + // if let Some(relative_utf16_range) = relative_utf16_range { + // let selections = self.selections.all::(cx); + // self.change_selections(None, cx, |s| { + // let new_ranges = selections.into_iter().map(|range| { + // let start = OffsetUtf16( + // range + // .head() + // .0 + // .saturating_add_signed(relative_utf16_range.start), + // ); + // let end = OffsetUtf16( + // range + // .head() + // .0 + // .saturating_add_signed(relative_utf16_range.end), + // ); + // start..end + // }); + // s.select_ranges(new_ranges); + // }); + // } + + // self.handle_input(text, cx); + // } + + // pub fn supports_inlay_hints(&self, cx: &AppContext) -> bool { + // let Some(project) = self.project.as_ref() else { + // return false; + // }; + // let project = project.read(cx); + + // let mut supports = false; + // self.buffer().read(cx).for_each_buffer(|buffer| { + // if !supports { + // supports = project + // .language_servers_for_buffer(buffer.read(cx), cx) + // .any( + // |(_, server)| match server.capabilities().inlay_hint_provider { + // Some(lsp::OneOf::Left(enabled)) => enabled, + // Some(lsp::OneOf::Right(_)) => true, + // None => false, + // }, + // ) + // } + // }); + // supports + // } } -// fn workspace(&self, cx: &AppContext) -> Option> { -// self.workspace.as_ref()?.0.upgrade(cx) -// } - -// pub fn title<'a>(&self, cx: &'a AppContext) -> Cow<'a, str> { -// self.buffer().read(cx).title(cx) -// } - -// pub fn snapshot(&mut self, cx: &mut WindowContext) -> EditorSnapshot { -// EditorSnapshot { -// mode: self.mode, -// show_gutter: self.show_gutter, -// display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)), -// scroll_anchor: self.scroll_manager.anchor(), -// ongoing_scroll: self.scroll_manager.ongoing_scroll(), -// placeholder_text: self.placeholder_text.clone(), -// is_focused: self -// .handle -// .upgrade(cx) -// .map_or(false, |handle| handle.is_focused(cx)), -// } -// } - -// pub fn language_at<'a, T: ToOffset>( -// &self, -// point: T, -// cx: &'a AppContext, -// ) -> Option> { -// self.buffer.read(cx).language_at(point, cx) -// } - -// pub fn file_at<'a, T: ToOffset>(&self, point: T, cx: &'a AppContext) -> Option> { -// self.buffer.read(cx).read(cx).file_at(point).cloned() -// } - -// pub fn active_excerpt( -// &self, -// cx: &AppContext, -// ) -> Option<(ExcerptId, Model, Range)> { -// self.buffer -// .read(cx) -// .excerpt_containing(self.selections.newest_anchor().head(), cx) -// } - -// pub fn style(&self, cx: &AppContext) -> EditorStyle { -// build_style( -// settings::get::(cx), -// self.get_field_editor_theme.as_deref(), -// self.override_text_style.as_deref(), -// cx, -// ) -// } - -// pub fn mode(&self) -> EditorMode { -// self.mode -// } - -// pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> { -// self.collaboration_hub.as_deref() -// } - -// pub fn set_collaboration_hub(&mut self, hub: Box) { -// self.collaboration_hub = Some(hub); -// } - -// pub fn set_placeholder_text( -// &mut self, -// placeholder_text: impl Into>, -// cx: &mut ViewContext, -// ) { -// self.placeholder_text = Some(placeholder_text.into()); -// cx.notify(); -// } - -// pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut ViewContext) { -// self.cursor_shape = cursor_shape; -// cx.notify(); -// } - -// pub fn set_collapse_matches(&mut self, collapse_matches: bool) { -// self.collapse_matches = collapse_matches; -// } - -// pub fn range_for_match(&self, range: &Range) -> Range { -// if self.collapse_matches { -// return range.start..range.start; -// } -// range.clone() -// } - -// pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut ViewContext) { -// if self.display_map.read(cx).clip_at_line_ends != clip { -// self.display_map -// .update(cx, |map, _| map.clip_at_line_ends = clip); -// } -// } - -// pub fn set_keymap_context_layer( -// &mut self, -// context: KeymapContext, -// cx: &mut ViewContext, -// ) { -// self.keymap_context_layers -// .insert(TypeId::of::(), context); -// cx.notify(); -// } - -// pub fn remove_keymap_context_layer(&mut self, cx: &mut ViewContext) { -// self.keymap_context_layers.remove(&TypeId::of::()); -// cx.notify(); -// } - -// pub fn set_input_enabled(&mut self, input_enabled: bool) { -// self.input_enabled = input_enabled; -// } - -// pub fn set_autoindent(&mut self, autoindent: bool) { -// if autoindent { -// self.autoindent_mode = Some(AutoindentMode::EachLine); -// } else { -// self.autoindent_mode = None; -// } -// } - -// pub fn read_only(&self) -> bool { -// self.read_only -// } - -// pub fn set_read_only(&mut self, read_only: bool) { -// self.read_only = read_only; -// } - -// pub fn set_field_editor_style( -// &mut self, -// style: Option>, -// cx: &mut ViewContext, -// ) { -// self.get_field_editor_theme = style; -// cx.notify(); -// } - -// fn selections_did_change( -// &mut self, -// local: bool, -// old_cursor_position: &Anchor, -// cx: &mut ViewContext, -// ) { -// if self.focused && self.leader_peer_id.is_none() { -// self.buffer.update(cx, |buffer, cx| { -// buffer.set_active_selections( -// &self.selections.disjoint_anchors(), -// self.selections.line_mode, -// self.cursor_shape, -// cx, -// ) -// }); -// } - -// let display_map = self -// .display_map -// .update(cx, |display_map, cx| display_map.snapshot(cx)); -// let buffer = &display_map.buffer_snapshot; -// self.add_selections_state = None; -// self.select_next_state = None; -// self.select_prev_state = None; -// self.select_larger_syntax_node_stack.clear(); -// self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), buffer); -// self.snippet_stack -// .invalidate(&self.selections.disjoint_anchors(), buffer); -// self.take_rename(false, cx); - -// let new_cursor_position = self.selections.newest_anchor().head(); - -// self.push_to_nav_history( -// old_cursor_position.clone(), -// Some(new_cursor_position.to_point(buffer)), -// cx, -// ); - -// if local { -// let new_cursor_position = self.selections.newest_anchor().head(); -// let mut context_menu = self.context_menu.write(); -// let completion_menu = match context_menu.as_ref() { -// Some(ContextMenu::Completions(menu)) => Some(menu), - -// _ => { -// *context_menu = None; -// None -// } -// }; - -// if let Some(completion_menu) = completion_menu { -// let cursor_position = new_cursor_position.to_offset(buffer); -// let (word_range, kind) = -// buffer.surrounding_word(completion_menu.initial_position.clone()); -// if kind == Some(CharKind::Word) -// && word_range.to_inclusive().contains(&cursor_position) -// { -// let mut completion_menu = completion_menu.clone(); -// drop(context_menu); - -// let query = Self::completion_query(buffer, cursor_position); -// cx.spawn(move |this, mut cx| async move { -// completion_menu -// .filter(query.as_deref(), cx.background().clone()) -// .await; - -// this.update(&mut cx, |this, cx| { -// let mut context_menu = this.context_menu.write(); -// let Some(ContextMenu::Completions(menu)) = context_menu.as_ref() else { -// return; -// }; - -// if menu.id > completion_menu.id { -// return; -// } - -// *context_menu = Some(ContextMenu::Completions(completion_menu)); -// drop(context_menu); -// cx.notify(); -// }) -// }) -// .detach(); - -// self.show_completions(&ShowCompletions, cx); -// } else { -// drop(context_menu); -// self.hide_context_menu(cx); -// } -// } else { -// drop(context_menu); -// } - -// hide_hover(self, cx); - -// if old_cursor_position.to_display_point(&display_map).row() -// != new_cursor_position.to_display_point(&display_map).row() -// { -// self.available_code_actions.take(); -// } -// self.refresh_code_actions(cx); -// self.refresh_document_highlights(cx); -// refresh_matching_bracket_highlights(self, cx); -// self.discard_copilot_suggestion(cx); -// } - -// self.blink_manager.update(cx, BlinkManager::pause_blinking); -// cx.emit(Event::SelectionsChanged { local }); -// cx.notify(); -// } - -// pub fn change_selections( -// &mut self, -// autoscroll: Option, -// cx: &mut ViewContext, -// change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R, -// ) -> R { -// let old_cursor_position = self.selections.newest_anchor().head(); -// self.push_to_selection_history(); - -// let (changed, result) = self.selections.change_with(cx, change); - -// if changed { -// if let Some(autoscroll) = autoscroll { -// self.request_autoscroll(autoscroll, cx); -// } -// self.selections_did_change(true, &old_cursor_position, cx); -// } - -// result -// } - -// pub fn edit(&mut self, edits: I, cx: &mut ViewContext) -// where -// I: IntoIterator, T)>, -// S: ToOffset, -// T: Into>, -// { -// if self.read_only { -// return; -// } - -// self.buffer -// .update(cx, |buffer, cx| buffer.edit(edits, None, cx)); -// } - -// pub fn edit_with_autoindent(&mut self, edits: I, cx: &mut ViewContext) -// where -// I: IntoIterator, T)>, -// S: ToOffset, -// T: Into>, -// { -// if self.read_only { -// return; -// } - -// self.buffer.update(cx, |buffer, cx| { -// buffer.edit(edits, self.autoindent_mode.clone(), cx) -// }); -// } - -// pub fn edit_with_block_indent( -// &mut self, -// edits: I, -// original_indent_columns: Vec, -// cx: &mut ViewContext, -// ) where -// I: IntoIterator, T)>, -// S: ToOffset, -// T: Into>, -// { -// if self.read_only { -// return; -// } - -// self.buffer.update(cx, |buffer, cx| { -// buffer.edit( -// edits, -// Some(AutoindentMode::Block { -// original_indent_columns, -// }), -// cx, -// ) -// }); -// } - -// fn select(&mut self, phase: SelectPhase, cx: &mut ViewContext) { -// self.hide_context_menu(cx); - -// match phase { -// SelectPhase::Begin { -// position, -// add, -// click_count, -// } => self.begin_selection(position, add, click_count, cx), -// SelectPhase::BeginColumnar { -// position, -// goal_column, -// } => self.begin_columnar_selection(position, goal_column, cx), -// SelectPhase::Extend { -// position, -// click_count, -// } => self.extend_selection(position, click_count, cx), -// SelectPhase::Update { -// position, -// goal_column, -// scroll_position, -// } => self.update_selection(position, goal_column, scroll_position, cx), -// SelectPhase::End => self.end_selection(cx), -// } -// } - -// fn extend_selection( -// &mut self, -// position: DisplayPoint, -// click_count: usize, -// cx: &mut ViewContext, -// ) { -// let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); -// let tail = self.selections.newest::(cx).tail(); -// self.begin_selection(position, false, click_count, cx); - -// let position = position.to_offset(&display_map, Bias::Left); -// let tail_anchor = display_map.buffer_snapshot.anchor_before(tail); - -// let mut pending_selection = self -// .selections -// .pending_anchor() -// .expect("extend_selection not called with pending selection"); -// if position >= tail { -// pending_selection.start = tail_anchor; -// } else { -// pending_selection.end = tail_anchor; -// pending_selection.reversed = true; -// } - -// let mut pending_mode = self.selections.pending_mode().unwrap(); -// match &mut pending_mode { -// SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor, -// _ => {} -// } - -// self.change_selections(Some(Autoscroll::fit()), cx, |s| { -// s.set_pending(pending_selection, pending_mode) -// }); -// } - -// fn begin_selection( -// &mut self, -// position: DisplayPoint, -// add: bool, -// click_count: usize, -// cx: &mut ViewContext, -// ) { -// if !self.focused { -// cx.focus_self(); -// } - -// let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); -// let buffer = &display_map.buffer_snapshot; -// let newest_selection = self.selections.newest_anchor().clone(); -// let position = display_map.clip_point(position, Bias::Left); - -// let start; -// let end; -// let mode; -// let auto_scroll; -// match click_count { -// 1 => { -// start = buffer.anchor_before(position.to_point(&display_map)); -// end = start.clone(); -// mode = SelectMode::Character; -// auto_scroll = true; -// } -// 2 => { -// let range = movement::surrounding_word(&display_map, position); -// start = buffer.anchor_before(range.start.to_point(&display_map)); -// end = buffer.anchor_before(range.end.to_point(&display_map)); -// mode = SelectMode::Word(start.clone()..end.clone()); -// auto_scroll = true; -// } -// 3 => { -// let position = display_map -// .clip_point(position, Bias::Left) -// .to_point(&display_map); -// let line_start = display_map.prev_line_boundary(position).0; -// let next_line_start = buffer.clip_point( -// display_map.next_line_boundary(position).0 + Point::new(1, 0), -// Bias::Left, -// ); -// start = buffer.anchor_before(line_start); -// end = buffer.anchor_before(next_line_start); -// mode = SelectMode::Line(start.clone()..end.clone()); -// auto_scroll = true; -// } -// _ => { -// start = buffer.anchor_before(0); -// end = buffer.anchor_before(buffer.len()); -// mode = SelectMode::All; -// auto_scroll = false; -// } -// } - -// self.change_selections(auto_scroll.then(|| Autoscroll::newest()), cx, |s| { -// if !add { -// s.clear_disjoint(); -// } else if click_count > 1 { -// s.delete(newest_selection.id) -// } - -// s.set_pending_anchor_range(start..end, mode); -// }); -// } - -// fn begin_columnar_selection( -// &mut self, -// position: DisplayPoint, -// goal_column: u32, -// cx: &mut ViewContext, -// ) { -// if !self.focused { -// cx.focus_self(); -// } - -// let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); -// let tail = self.selections.newest::(cx).tail(); -// self.columnar_selection_tail = Some(display_map.buffer_snapshot.anchor_before(tail)); - -// self.select_columns( -// tail.to_display_point(&display_map), -// position, -// goal_column, -// &display_map, -// cx, -// ); -// } - -// fn update_selection( -// &mut self, -// position: DisplayPoint, -// goal_column: u32, -// scroll_position: Vector2F, -// cx: &mut ViewContext, -// ) { -// let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); - -// if let Some(tail) = self.columnar_selection_tail.as_ref() { -// let tail = tail.to_display_point(&display_map); -// self.select_columns(tail, position, goal_column, &display_map, cx); -// } else if let Some(mut pending) = self.selections.pending_anchor() { -// let buffer = self.buffer.read(cx).snapshot(cx); -// let head; -// let tail; -// let mode = self.selections.pending_mode().unwrap(); -// match &mode { -// SelectMode::Character => { -// head = position.to_point(&display_map); -// tail = pending.tail().to_point(&buffer); -// } -// SelectMode::Word(original_range) => { -// let original_display_range = original_range.start.to_display_point(&display_map) -// ..original_range.end.to_display_point(&display_map); -// let original_buffer_range = original_display_range.start.to_point(&display_map) -// ..original_display_range.end.to_point(&display_map); -// if movement::is_inside_word(&display_map, position) -// || original_display_range.contains(&position) -// { -// let word_range = movement::surrounding_word(&display_map, position); -// if word_range.start < original_display_range.start { -// head = word_range.start.to_point(&display_map); -// } else { -// head = word_range.end.to_point(&display_map); -// } -// } else { -// head = position.to_point(&display_map); -// } - -// if head <= original_buffer_range.start { -// tail = original_buffer_range.end; -// } else { -// tail = original_buffer_range.start; -// } -// } -// SelectMode::Line(original_range) => { -// let original_range = original_range.to_point(&display_map.buffer_snapshot); - -// let position = display_map -// .clip_point(position, Bias::Left) -// .to_point(&display_map); -// let line_start = display_map.prev_line_boundary(position).0; -// let next_line_start = buffer.clip_point( -// display_map.next_line_boundary(position).0 + Point::new(1, 0), -// Bias::Left, -// ); - -// if line_start < original_range.start { -// head = line_start -// } else { -// head = next_line_start -// } - -// if head <= original_range.start { -// tail = original_range.end; -// } else { -// tail = original_range.start; -// } -// } -// SelectMode::All => { -// return; -// } -// }; - -// if head < tail { -// pending.start = buffer.anchor_before(head); -// pending.end = buffer.anchor_before(tail); -// pending.reversed = true; -// } else { -// pending.start = buffer.anchor_before(tail); -// pending.end = buffer.anchor_before(head); -// pending.reversed = false; -// } - -// self.change_selections(None, cx, |s| { -// s.set_pending(pending, mode); -// }); -// } else { -// error!("update_selection dispatched with no pending selection"); -// return; -// } - -// self.set_scroll_position(scroll_position, cx); -// cx.notify(); -// } - -// fn end_selection(&mut self, cx: &mut ViewContext) { -// self.columnar_selection_tail.take(); -// if self.selections.pending_anchor().is_some() { -// let selections = self.selections.all::(cx); -// self.change_selections(None, cx, |s| { -// s.select(selections); -// s.clear_pending(); -// }); -// } -// } - -// fn select_columns( -// &mut self, -// tail: DisplayPoint, -// head: DisplayPoint, -// goal_column: u32, -// display_map: &DisplaySnapshot, -// cx: &mut ViewContext, -// ) { -// let start_row = cmp::min(tail.row(), head.row()); -// let end_row = cmp::max(tail.row(), head.row()); -// let start_column = cmp::min(tail.column(), goal_column); -// let end_column = cmp::max(tail.column(), goal_column); -// let reversed = start_column < tail.column(); - -// let selection_ranges = (start_row..=end_row) -// .filter_map(|row| { -// if start_column <= display_map.line_len(row) && !display_map.is_block_line(row) { -// let start = display_map -// .clip_point(DisplayPoint::new(row, start_column), Bias::Left) -// .to_point(display_map); -// let end = display_map -// .clip_point(DisplayPoint::new(row, end_column), Bias::Right) -// .to_point(display_map); -// if reversed { -// Some(end..start) -// } else { -// Some(start..end) -// } -// } else { -// None -// } -// }) -// .collect::>(); - -// self.change_selections(None, cx, |s| { -// s.select_ranges(selection_ranges); -// }); -// cx.notify(); -// } - -// pub fn has_pending_nonempty_selection(&self) -> bool { -// let pending_nonempty_selection = match self.selections.pending_anchor() { -// Some(Selection { start, end, .. }) => start != end, -// None => false, -// }; -// pending_nonempty_selection || self.columnar_selection_tail.is_some() -// } - -// pub fn has_pending_selection(&self) -> bool { -// self.selections.pending_anchor().is_some() || self.columnar_selection_tail.is_some() -// } - -// pub fn cancel(&mut self, _: &Cancel, cx: &mut ViewContext) { -// if self.take_rename(false, cx).is_some() { -// return; -// } - -// if hide_hover(self, cx) { -// return; -// } - -// if self.hide_context_menu(cx).is_some() { -// return; -// } - -// if self.discard_copilot_suggestion(cx) { -// return; -// } - -// if self.snippet_stack.pop().is_some() { -// return; -// } - -// if self.mode == EditorMode::Full { -// if self.active_diagnostics.is_some() { -// self.dismiss_diagnostics(cx); -// return; -// } - -// if self.change_selections(Some(Autoscroll::fit()), cx, |s| s.try_cancel()) { -// return; -// } -// } - -// cx.propagate_action(); -// } - -// pub fn handle_input(&mut self, text: &str, cx: &mut ViewContext) { -// let text: Arc = text.into(); - -// if self.read_only { -// return; -// } - -// let selections = self.selections.all_adjusted(cx); -// let mut brace_inserted = false; -// let mut edits = Vec::new(); -// let mut new_selections = Vec::with_capacity(selections.len()); -// let mut new_autoclose_regions = Vec::new(); -// let snapshot = self.buffer.read(cx).read(cx); - -// for (selection, autoclose_region) in -// self.selections_with_autoclose_regions(selections, &snapshot) -// { -// if let Some(scope) = snapshot.language_scope_at(selection.head()) { -// // Determine if the inserted text matches the opening or closing -// // bracket of any of this language's bracket pairs. -// let mut bracket_pair = None; -// let mut is_bracket_pair_start = false; -// if !text.is_empty() { -// // `text` can be empty when an user is using IME (e.g. Chinese Wubi Simplified) -// // and they are removing the character that triggered IME popup. -// for (pair, enabled) in scope.brackets() { -// if enabled && pair.close && pair.start.ends_with(text.as_ref()) { -// bracket_pair = Some(pair.clone()); -// is_bracket_pair_start = true; -// break; -// } else if pair.end.as_str() == text.as_ref() { -// bracket_pair = Some(pair.clone()); -// break; -// } -// } -// } - -// if let Some(bracket_pair) = bracket_pair { -// if selection.is_empty() { -// if is_bracket_pair_start { -// let prefix_len = bracket_pair.start.len() - text.len(); - -// // If the inserted text is a suffix of an opening bracket and the -// // selection is preceded by the rest of the opening bracket, then -// // insert the closing bracket. -// let following_text_allows_autoclose = snapshot -// .chars_at(selection.start) -// .next() -// .map_or(true, |c| scope.should_autoclose_before(c)); -// let preceding_text_matches_prefix = prefix_len == 0 -// || (selection.start.column >= (prefix_len as u32) -// && snapshot.contains_str_at( -// Point::new( -// selection.start.row, -// selection.start.column - (prefix_len as u32), -// ), -// &bracket_pair.start[..prefix_len], -// )); -// if following_text_allows_autoclose && preceding_text_matches_prefix { -// let anchor = snapshot.anchor_before(selection.end); -// new_selections.push((selection.map(|_| anchor), text.len())); -// new_autoclose_regions.push(( -// anchor, -// text.len(), -// selection.id, -// bracket_pair.clone(), -// )); -// edits.push(( -// selection.range(), -// format!("{}{}", text, bracket_pair.end).into(), -// )); -// brace_inserted = true; -// continue; -// } -// } - -// if let Some(region) = autoclose_region { -// // If the selection is followed by an auto-inserted closing bracket, -// // then don't insert that closing bracket again; just move the selection -// // past the closing bracket. -// let should_skip = selection.end == region.range.end.to_point(&snapshot) -// && text.as_ref() == region.pair.end.as_str(); -// if should_skip { -// let anchor = snapshot.anchor_after(selection.end); -// new_selections -// .push((selection.map(|_| anchor), region.pair.end.len())); -// continue; -// } -// } -// } -// // If an opening bracket is 1 character long and is typed while -// // text is selected, then surround that text with the bracket pair. -// else if is_bracket_pair_start && bracket_pair.start.chars().count() == 1 { -// edits.push((selection.start..selection.start, text.clone())); -// edits.push(( -// selection.end..selection.end, -// bracket_pair.end.as_str().into(), -// )); -// brace_inserted = true; -// new_selections.push(( -// Selection { -// id: selection.id, -// start: snapshot.anchor_after(selection.start), -// end: snapshot.anchor_before(selection.end), -// reversed: selection.reversed, -// goal: selection.goal, -// }, -// 0, -// )); -// continue; -// } -// } -// } - -// // If not handling any auto-close operation, then just replace the selected -// // text with the given input and move the selection to the end of the -// // newly inserted text. -// let anchor = snapshot.anchor_after(selection.end); -// new_selections.push((selection.map(|_| anchor), 0)); -// edits.push((selection.start..selection.end, text.clone())); -// } - -// drop(snapshot); -// self.transact(cx, |this, cx| { -// this.buffer.update(cx, |buffer, cx| { -// buffer.edit(edits, this.autoindent_mode.clone(), cx); -// }); - -// let new_anchor_selections = new_selections.iter().map(|e| &e.0); -// let new_selection_deltas = new_selections.iter().map(|e| e.1); -// let snapshot = this.buffer.read(cx).read(cx); -// let new_selections = resolve_multiple::(new_anchor_selections, &snapshot) -// .zip(new_selection_deltas) -// .map(|(selection, delta)| Selection { -// id: selection.id, -// start: selection.start + delta, -// end: selection.end + delta, -// reversed: selection.reversed, -// goal: SelectionGoal::None, -// }) -// .collect::>(); - -// let mut i = 0; -// for (position, delta, selection_id, pair) in new_autoclose_regions { -// let position = position.to_offset(&snapshot) + delta; -// let start = snapshot.anchor_before(position); -// let end = snapshot.anchor_after(position); -// while let Some(existing_state) = this.autoclose_regions.get(i) { -// match existing_state.range.start.cmp(&start, &snapshot) { -// Ordering::Less => i += 1, -// Ordering::Greater => break, -// Ordering::Equal => match end.cmp(&existing_state.range.end, &snapshot) { -// Ordering::Less => i += 1, -// Ordering::Equal => break, -// Ordering::Greater => break, -// }, -// } -// } -// this.autoclose_regions.insert( -// i, -// AutocloseRegion { -// selection_id, -// range: start..end, -// pair, -// }, -// ); -// } - -// drop(snapshot); -// let had_active_copilot_suggestion = this.has_active_copilot_suggestion(cx); -// this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(new_selections)); - -// if !brace_inserted && settings::get::(cx).use_on_type_format { -// if let Some(on_type_format_task) = -// this.trigger_on_type_formatting(text.to_string(), cx) -// { -// on_type_format_task.detach_and_log_err(cx); -// } -// } - -// if had_active_copilot_suggestion { -// this.refresh_copilot_suggestions(true, cx); -// if !this.has_active_copilot_suggestion(cx) { -// this.trigger_completion_on_input(&text, cx); -// } -// } else { -// this.trigger_completion_on_input(&text, cx); -// this.refresh_copilot_suggestions(true, cx); -// } -// }); -// } - -// pub fn newline(&mut self, _: &Newline, cx: &mut ViewContext) { -// self.transact(cx, |this, cx| { -// let (edits, selection_fixup_info): (Vec<_>, Vec<_>) = { -// let selections = this.selections.all::(cx); -// let multi_buffer = this.buffer.read(cx); -// let buffer = multi_buffer.snapshot(cx); -// selections -// .iter() -// .map(|selection| { -// let start_point = selection.start.to_point(&buffer); -// let mut indent = buffer.indent_size_for_line(start_point.row); -// indent.len = cmp::min(indent.len, start_point.column); -// let start = selection.start; -// let end = selection.end; -// let is_cursor = start == end; -// let language_scope = buffer.language_scope_at(start); -// let (comment_delimiter, insert_extra_newline) = if let Some(language) = -// &language_scope -// { -// let leading_whitespace_len = buffer -// .reversed_chars_at(start) -// .take_while(|c| c.is_whitespace() && *c != '\n') -// .map(|c| c.len_utf8()) -// .sum::(); - -// let trailing_whitespace_len = buffer -// .chars_at(end) -// .take_while(|c| c.is_whitespace() && *c != '\n') -// .map(|c| c.len_utf8()) -// .sum::(); - -// let insert_extra_newline = -// language.brackets().any(|(pair, enabled)| { -// let pair_start = pair.start.trim_end(); -// let pair_end = pair.end.trim_start(); - -// enabled -// && pair.newline -// && buffer.contains_str_at( -// end + trailing_whitespace_len, -// pair_end, -// ) -// && buffer.contains_str_at( -// (start - leading_whitespace_len) -// .saturating_sub(pair_start.len()), -// pair_start, -// ) -// }); -// // Comment extension on newline is allowed only for cursor selections -// let comment_delimiter = language.line_comment_prefix().filter(|_| { -// let is_comment_extension_enabled = -// multi_buffer.settings_at(0, cx).extend_comment_on_newline; -// is_cursor && is_comment_extension_enabled -// }); -// let comment_delimiter = if let Some(delimiter) = comment_delimiter { -// buffer -// .buffer_line_for_row(start_point.row) -// .is_some_and(|(snapshot, range)| { -// let mut index_of_first_non_whitespace = 0; -// let line_starts_with_comment = snapshot -// .chars_for_range(range) -// .skip_while(|c| { -// let should_skip = c.is_whitespace(); -// if should_skip { -// index_of_first_non_whitespace += 1; -// } -// should_skip -// }) -// .take(delimiter.len()) -// .eq(delimiter.chars()); -// let cursor_is_placed_after_comment_marker = -// index_of_first_non_whitespace + delimiter.len() -// <= start_point.column as usize; -// line_starts_with_comment -// && cursor_is_placed_after_comment_marker -// }) -// .then(|| delimiter.clone()) -// } else { -// None -// }; -// (comment_delimiter, insert_extra_newline) -// } else { -// (None, false) -// }; - -// let capacity_for_delimiter = comment_delimiter -// .as_deref() -// .map(str::len) -// .unwrap_or_default(); -// let mut new_text = -// String::with_capacity(1 + capacity_for_delimiter + indent.len as usize); -// new_text.push_str("\n"); -// new_text.extend(indent.chars()); -// if let Some(delimiter) = &comment_delimiter { -// new_text.push_str(&delimiter); -// } -// if insert_extra_newline { -// new_text = new_text.repeat(2); -// } - -// let anchor = buffer.anchor_after(end); -// let new_selection = selection.map(|_| anchor); -// ( -// (start..end, new_text), -// (insert_extra_newline, new_selection), -// ) -// }) -// .unzip() -// }; - -// this.edit_with_autoindent(edits, cx); -// let buffer = this.buffer.read(cx).snapshot(cx); -// let new_selections = selection_fixup_info -// .into_iter() -// .map(|(extra_newline_inserted, new_selection)| { -// let mut cursor = new_selection.end.to_point(&buffer); -// if extra_newline_inserted { -// cursor.row -= 1; -// cursor.column = buffer.line_len(cursor.row); -// } -// new_selection.map(|_| cursor) -// }) -// .collect(); - -// this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(new_selections)); -// this.refresh_copilot_suggestions(true, cx); -// }); -// } - -// pub fn newline_above(&mut self, _: &NewlineAbove, cx: &mut ViewContext) { -// let buffer = self.buffer.read(cx); -// let snapshot = buffer.snapshot(cx); - -// let mut edits = Vec::new(); -// let mut rows = Vec::new(); -// let mut rows_inserted = 0; - -// for selection in self.selections.all_adjusted(cx) { -// let cursor = selection.head(); -// let row = cursor.row; - -// let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left); - -// let newline = "\n".to_string(); -// edits.push((start_of_line..start_of_line, newline)); - -// rows.push(row + rows_inserted); -// rows_inserted += 1; -// } - -// self.transact(cx, |editor, cx| { -// editor.edit(edits, cx); - -// editor.change_selections(Some(Autoscroll::fit()), cx, |s| { -// let mut index = 0; -// s.move_cursors_with(|map, _, _| { -// let row = rows[index]; -// index += 1; - -// let point = Point::new(row, 0); -// let boundary = map.next_line_boundary(point).1; -// let clipped = map.clip_point(boundary, Bias::Left); - -// (clipped, SelectionGoal::None) -// }); -// }); - -// let mut indent_edits = Vec::new(); -// let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx); -// for row in rows { -// let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx); -// for (row, indent) in indents { -// if indent.len == 0 { -// continue; -// } - -// let text = match indent.kind { -// IndentKind::Space => " ".repeat(indent.len as usize), -// IndentKind::Tab => "\t".repeat(indent.len as usize), -// }; -// let point = Point::new(row, 0); -// indent_edits.push((point..point, text)); -// } -// } -// editor.edit(indent_edits, cx); -// }); -// } - -// pub fn newline_below(&mut self, _: &NewlineBelow, cx: &mut ViewContext) { -// let buffer = self.buffer.read(cx); -// let snapshot = buffer.snapshot(cx); - -// let mut edits = Vec::new(); -// let mut rows = Vec::new(); -// let mut rows_inserted = 0; - -// for selection in self.selections.all_adjusted(cx) { -// let cursor = selection.head(); -// let row = cursor.row; - -// let point = Point::new(row + 1, 0); -// let start_of_line = snapshot.clip_point(point, Bias::Left); - -// let newline = "\n".to_string(); -// edits.push((start_of_line..start_of_line, newline)); - -// rows_inserted += 1; -// rows.push(row + rows_inserted); -// } - -// self.transact(cx, |editor, cx| { -// editor.edit(edits, cx); - -// editor.change_selections(Some(Autoscroll::fit()), cx, |s| { -// let mut index = 0; -// s.move_cursors_with(|map, _, _| { -// let row = rows[index]; -// index += 1; - -// let point = Point::new(row, 0); -// let boundary = map.next_line_boundary(point).1; -// let clipped = map.clip_point(boundary, Bias::Left); - -// (clipped, SelectionGoal::None) -// }); -// }); - -// let mut indent_edits = Vec::new(); -// let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx); -// for row in rows { -// let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx); -// for (row, indent) in indents { -// if indent.len == 0 { -// continue; -// } - -// let text = match indent.kind { -// IndentKind::Space => " ".repeat(indent.len as usize), -// IndentKind::Tab => "\t".repeat(indent.len as usize), -// }; -// let point = Point::new(row, 0); -// indent_edits.push((point..point, text)); -// } -// } -// editor.edit(indent_edits, cx); -// }); -// } - -// pub fn insert(&mut self, text: &str, cx: &mut ViewContext) { -// self.insert_with_autoindent_mode( -// text, -// Some(AutoindentMode::Block { -// original_indent_columns: Vec::new(), -// }), -// cx, -// ); -// } - -// fn insert_with_autoindent_mode( -// &mut self, -// text: &str, -// autoindent_mode: Option, -// cx: &mut ViewContext, -// ) { -// if self.read_only { -// return; -// } - -// let text: Arc = text.into(); -// self.transact(cx, |this, cx| { -// let old_selections = this.selections.all_adjusted(cx); -// let selection_anchors = this.buffer.update(cx, |buffer, cx| { -// let anchors = { -// let snapshot = buffer.read(cx); -// old_selections -// .iter() -// .map(|s| { -// let anchor = snapshot.anchor_after(s.head()); -// s.map(|_| anchor) -// }) -// .collect::>() -// }; -// buffer.edit( -// old_selections -// .iter() -// .map(|s| (s.start..s.end, text.clone())), -// autoindent_mode, -// cx, -// ); -// anchors -// }); - -// this.change_selections(Some(Autoscroll::fit()), cx, |s| { -// s.select_anchors(selection_anchors); -// }) -// }); -// } - -// fn trigger_completion_on_input(&mut self, text: &str, cx: &mut ViewContext) { -// if !settings::get::(cx).show_completions_on_input { -// return; -// } - -// let selection = self.selections.newest_anchor(); -// if self -// .buffer -// .read(cx) -// .is_completion_trigger(selection.head(), text, cx) -// { -// self.show_completions(&ShowCompletions, cx); -// } else { -// self.hide_context_menu(cx); -// } -// } - -// /// If any empty selections is touching the start of its innermost containing autoclose -// /// region, expand it to select the brackets. -// fn select_autoclose_pair(&mut self, cx: &mut ViewContext) { -// let selections = self.selections.all::(cx); -// let buffer = self.buffer.read(cx).read(cx); -// let mut new_selections = Vec::new(); -// for (mut selection, region) in self.selections_with_autoclose_regions(selections, &buffer) { -// if let (Some(region), true) = (region, selection.is_empty()) { -// let mut range = region.range.to_offset(&buffer); -// if selection.start == range.start { -// if range.start >= region.pair.start.len() { -// range.start -= region.pair.start.len(); -// if buffer.contains_str_at(range.start, ®ion.pair.start) { -// if buffer.contains_str_at(range.end, ®ion.pair.end) { -// range.end += region.pair.end.len(); -// selection.start = range.start; -// selection.end = range.end; -// } -// } -// } -// } -// } -// new_selections.push(selection); -// } - -// drop(buffer); -// self.change_selections(None, cx, |selections| selections.select(new_selections)); -// } - -// /// Iterate the given selections, and for each one, find the smallest surrounding -// /// autoclose region. This uses the ordering of the selections and the autoclose -// /// regions to avoid repeated comparisons. -// fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>( -// &'a self, -// selections: impl IntoIterator>, -// buffer: &'a MultiBufferSnapshot, -// ) -> impl Iterator, Option<&'a AutocloseRegion>)> { -// let mut i = 0; -// let mut regions = self.autoclose_regions.as_slice(); -// selections.into_iter().map(move |selection| { -// let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer); - -// let mut enclosing = None; -// while let Some(pair_state) = regions.get(i) { -// if pair_state.range.end.to_offset(buffer) < range.start { -// regions = ®ions[i + 1..]; -// i = 0; -// } else if pair_state.range.start.to_offset(buffer) > range.end { -// break; -// } else { -// if pair_state.selection_id == selection.id { -// enclosing = Some(pair_state); -// } -// i += 1; -// } -// } - -// (selection.clone(), enclosing) -// }) -// } - -// /// Remove any autoclose regions that no longer contain their selection. -// fn invalidate_autoclose_regions( -// &mut self, -// mut selections: &[Selection], -// buffer: &MultiBufferSnapshot, -// ) { -// self.autoclose_regions.retain(|state| { -// let mut i = 0; -// while let Some(selection) = selections.get(i) { -// if selection.end.cmp(&state.range.start, buffer).is_lt() { -// selections = &selections[1..]; -// continue; -// } -// if selection.start.cmp(&state.range.end, buffer).is_gt() { -// break; -// } -// if selection.id == state.selection_id { -// return true; -// } else { -// i += 1; -// } -// } -// false -// }); -// } - -// fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option { -// let offset = position.to_offset(buffer); -// let (word_range, kind) = buffer.surrounding_word(offset); -// if offset > word_range.start && kind == Some(CharKind::Word) { -// Some( -// buffer -// .text_for_range(word_range.start..offset) -// .collect::(), -// ) -// } else { -// None -// } -// } - -// pub fn toggle_inlay_hints(&mut self, _: &ToggleInlayHints, cx: &mut ViewContext) { -// todo!(); -// // self.refresh_inlay_hints( -// // InlayHintRefreshReason::Toggle(!self.inlay_hint_cache.enabled), -// // cx, -// // ); -// } - -// pub fn inlay_hints_enabled(&self) -> bool { -// todo!(); -// self.inlay_hint_cache.enabled -// } - -// fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut ViewContext) { -// if self.project.is_none() || self.mode != EditorMode::Full { -// return; -// } - -// let reason_description = reason.description(); -// let (invalidate_cache, required_languages) = match reason { -// InlayHintRefreshReason::Toggle(enabled) => { -// self.inlay_hint_cache.enabled = enabled; -// if enabled { -// (InvalidationStrategy::RefreshRequested, None) -// } else { -// self.inlay_hint_cache.clear(); -// self.splice_inlay_hints( -// self.visible_inlay_hints(cx) -// .iter() -// .map(|inlay| inlay.id) -// .collect(), -// Vec::new(), -// cx, -// ); -// return; -// } -// } -// InlayHintRefreshReason::SettingsChange(new_settings) => { -// match self.inlay_hint_cache.update_settings( -// &self.buffer, -// new_settings, -// self.visible_inlay_hints(cx), -// cx, -// ) { -// ControlFlow::Break(Some(InlaySplice { -// to_remove, -// to_insert, -// })) => { -// self.splice_inlay_hints(to_remove, to_insert, cx); -// return; -// } -// ControlFlow::Break(None) => return, -// ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None), -// } -// } -// InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => { -// if let Some(InlaySplice { -// to_remove, -// to_insert, -// }) = self.inlay_hint_cache.remove_excerpts(excerpts_removed) -// { -// self.splice_inlay_hints(to_remove, to_insert, cx); -// } -// return; -// } -// InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None), -// InlayHintRefreshReason::BufferEdited(buffer_languages) => { -// (InvalidationStrategy::BufferEdited, Some(buffer_languages)) -// } -// InlayHintRefreshReason::RefreshRequested => { -// (InvalidationStrategy::RefreshRequested, None) -// } -// }; - -// if let Some(InlaySplice { -// to_remove, -// to_insert, -// }) = self.inlay_hint_cache.spawn_hint_refresh( -// reason_description, -// self.excerpt_visible_offsets(required_languages.as_ref(), cx), -// invalidate_cache, -// cx, -// ) { -// self.splice_inlay_hints(to_remove, to_insert, cx); -// } -// } - -// fn visible_inlay_hints(&self, cx: &ViewContext<'_, '_, Editor>) -> Vec { -// self.display_map -// .read(cx) -// .current_inlays() -// .filter(move |inlay| { -// Some(inlay.id) != self.copilot_state.suggestion.as_ref().map(|h| h.id) -// }) -// .cloned() -// .collect() -// } - -// pub fn excerpt_visible_offsets( -// &self, -// restrict_to_languages: Option<&HashSet>>, -// cx: &mut ViewContext<'_, '_, Editor>, -// ) -> HashMap, Global, Range)> { -// let multi_buffer = self.buffer().read(cx); -// let multi_buffer_snapshot = multi_buffer.snapshot(cx); -// let multi_buffer_visible_start = self -// .scroll_manager -// .anchor() -// .anchor -// .to_point(&multi_buffer_snapshot); -// let multi_buffer_visible_end = multi_buffer_snapshot.clip_point( -// multi_buffer_visible_start -// + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0), -// Bias::Left, -// ); -// let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end; -// multi_buffer -// .range_to_buffer_ranges(multi_buffer_visible_range, cx) -// .into_iter() -// .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty()) -// .filter_map(|(buffer_handle, excerpt_visible_range, excerpt_id)| { -// let buffer = buffer_handle.read(cx); -// let language = buffer.language()?; -// if let Some(restrict_to_languages) = restrict_to_languages { -// if !restrict_to_languages.contains(language) { -// return None; -// } -// } -// Some(( -// excerpt_id, -// ( -// buffer_handle, -// buffer.version().clone(), -// excerpt_visible_range, -// ), -// )) -// }) -// .collect() -// } - -// pub fn text_layout_details(&self, cx: &WindowContext) -> TextLayoutDetails { -// TextLayoutDetails { -// font_cache: cx.font_cache().clone(), -// text_layout_cache: cx.text_layout_cache().clone(), -// editor_style: self.style(cx), -// } -// } - -// fn splice_inlay_hints( -// &self, -// to_remove: Vec, -// to_insert: Vec, -// cx: &mut ViewContext, -// ) { -// self.display_map.update(cx, |display_map, cx| { -// display_map.splice_inlays(to_remove, to_insert, cx); -// }); -// cx.notify(); -// } - -// fn trigger_on_type_formatting( -// &self, -// input: String, -// cx: &mut ViewContext, -// ) -> Option>> { -// if input.len() != 1 { -// return None; -// } - -// let project = self.project.as_ref()?; -// let position = self.selections.newest_anchor().head(); -// let (buffer, buffer_position) = self -// .buffer -// .read(cx) -// .text_anchor_for_position(position.clone(), cx)?; - -// // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances, -// // hence we do LSP request & edit on host side only — add formats to host's history. -// let push_to_lsp_host_history = true; -// // If this is not the host, append its history with new edits. -// let push_to_client_history = project.read(cx).is_remote(); - -// let on_type_formatting = project.update(cx, |project, cx| { -// project.on_type_format( -// buffer.clone(), -// buffer_position, -// input, -// push_to_lsp_host_history, -// cx, -// ) -// }); -// Some(cx.spawn(|editor, mut cx| async move { -// if let Some(transaction) = on_type_formatting.await? { -// if push_to_client_history { -// buffer.update(&mut cx, |buffer, _| { -// buffer.push_transaction(transaction, Instant::now()); -// }); -// } -// editor.update(&mut cx, |editor, cx| { -// editor.refresh_document_highlights(cx); -// })?; -// } -// Ok(()) -// })) -// } - -// fn show_completions(&mut self, _: &ShowCompletions, cx: &mut ViewContext) { -// if self.pending_rename.is_some() { -// return; -// } - -// let project = if let Some(project) = self.project.clone() { -// project -// } else { -// return; -// }; - -// let position = self.selections.newest_anchor().head(); -// let (buffer, buffer_position) = if let Some(output) = self -// .buffer -// .read(cx) -// .text_anchor_for_position(position.clone(), cx) -// { -// output -// } else { -// return; -// }; - -// let query = Self::completion_query(&self.buffer.read(cx).read(cx), position.clone()); -// let completions = project.update(cx, |project, cx| { -// project.completions(&buffer, buffer_position, cx) -// }); - -// let id = post_inc(&mut self.next_completion_id); -// let task = cx.spawn(|this, mut cx| { -// async move { -// let menu = if let Some(completions) = completions.await.log_err() { -// let mut menu = CompletionsMenu { -// id, -// initial_position: position, -// match_candidates: completions -// .iter() -// .enumerate() -// .map(|(id, completion)| { -// StringMatchCandidate::new( -// id, -// completion.label.text[completion.label.filter_range.clone()] -// .into(), -// ) -// }) -// .collect(), -// buffer, -// completions: Arc::new(RwLock::new(completions.into())), -// matches: Vec::new().into(), -// selected_item: 0, -// list: Default::default(), -// }; -// menu.filter(query.as_deref(), cx.background()).await; -// if menu.matches.is_empty() { -// None -// } else { -// _ = this.update(&mut cx, |editor, cx| { -// menu.pre_resolve_completion_documentation(editor.project.clone(), cx); -// }); -// Some(menu) -// } -// } else { -// None -// }; - -// this.update(&mut cx, |this, cx| { -// this.completion_tasks.retain(|(task_id, _)| *task_id > id); - -// let mut context_menu = this.context_menu.write(); -// match context_menu.as_ref() { -// None => {} - -// Some(ContextMenu::Completions(prev_menu)) => { -// if prev_menu.id > id { -// return; -// } -// } - -// _ => return, -// } - -// if this.focused && menu.is_some() { -// let menu = menu.unwrap(); -// *context_menu = Some(ContextMenu::Completions(menu)); -// drop(context_menu); -// this.discard_copilot_suggestion(cx); -// cx.notify(); -// } else if this.completion_tasks.is_empty() { -// // If there are no more completion tasks and the last menu was -// // empty, we should hide it. If it was already hidden, we should -// // also show the copilot suggestion when available. -// drop(context_menu); -// if this.hide_context_menu(cx).is_none() { -// this.update_visible_copilot_suggestion(cx); -// } -// } -// })?; - -// Ok::<_, anyhow::Error>(()) -// } -// .log_err() -// }); -// self.completion_tasks.push((id, task)); -// } - -// pub fn confirm_completion( -// &mut self, -// action: &ConfirmCompletion, -// cx: &mut ViewContext, -// ) -> Option>> { -// use language::ToOffset as _; - -// let completions_menu = if let ContextMenu::Completions(menu) = self.hide_context_menu(cx)? { -// menu -// } else { -// return None; -// }; - -// let mat = completions_menu -// .matches -// .get(action.item_ix.unwrap_or(completions_menu.selected_item))?; -// let buffer_handle = completions_menu.buffer; -// let completions = completions_menu.completions.read(); -// let completion = completions.get(mat.candidate_id)?; - -// let snippet; -// let text; -// if completion.is_snippet() { -// snippet = Some(Snippet::parse(&completion.new_text).log_err()?); -// text = snippet.as_ref().unwrap().text.clone(); -// } else { -// snippet = None; -// text = completion.new_text.clone(); -// }; -// let selections = self.selections.all::(cx); -// let buffer = buffer_handle.read(cx); -// let old_range = completion.old_range.to_offset(buffer); -// let old_text = buffer.text_for_range(old_range.clone()).collect::(); - -// let newest_selection = self.selections.newest_anchor(); -// if newest_selection.start.buffer_id != Some(buffer_handle.read(cx).remote_id()) { -// return None; -// } - -// let lookbehind = newest_selection -// .start -// .text_anchor -// .to_offset(buffer) -// .saturating_sub(old_range.start); -// let lookahead = old_range -// .end -// .saturating_sub(newest_selection.end.text_anchor.to_offset(buffer)); -// let mut common_prefix_len = old_text -// .bytes() -// .zip(text.bytes()) -// .take_while(|(a, b)| a == b) -// .count(); - -// let snapshot = self.buffer.read(cx).snapshot(cx); -// let mut range_to_replace: Option> = None; -// let mut ranges = Vec::new(); -// for selection in &selections { -// if snapshot.contains_str_at(selection.start.saturating_sub(lookbehind), &old_text) { -// let start = selection.start.saturating_sub(lookbehind); -// let end = selection.end + lookahead; -// if selection.id == newest_selection.id { -// range_to_replace = Some( -// ((start + common_prefix_len) as isize - selection.start as isize) -// ..(end as isize - selection.start as isize), -// ); -// } -// ranges.push(start + common_prefix_len..end); -// } else { -// common_prefix_len = 0; -// ranges.clear(); -// ranges.extend(selections.iter().map(|s| { -// if s.id == newest_selection.id { -// range_to_replace = Some( -// old_range.start.to_offset_utf16(&snapshot).0 as isize -// - selection.start as isize -// ..old_range.end.to_offset_utf16(&snapshot).0 as isize -// - selection.start as isize, -// ); -// old_range.clone() -// } else { -// s.start..s.end -// } -// })); -// break; -// } -// } -// let text = &text[common_prefix_len..]; - -// cx.emit(Event::InputHandled { -// utf16_range_to_replace: range_to_replace, -// text: text.into(), -// }); - -// self.transact(cx, |this, cx| { -// if let Some(mut snippet) = snippet { -// snippet.text = text.to_string(); -// for tabstop in snippet.tabstops.iter_mut().flatten() { -// tabstop.start -= common_prefix_len as isize; -// tabstop.end -= common_prefix_len as isize; -// } - -// this.insert_snippet(&ranges, snippet, cx).log_err(); -// } else { -// this.buffer.update(cx, |buffer, cx| { -// buffer.edit( -// ranges.iter().map(|range| (range.clone(), text)), -// this.autoindent_mode.clone(), -// cx, -// ); -// }); -// } - -// this.refresh_copilot_suggestions(true, cx); -// }); - -// let project = self.project.clone()?; -// let apply_edits = project.update(cx, |project, cx| { -// project.apply_additional_edits_for_completion( -// buffer_handle, -// completion.clone(), -// true, -// cx, -// ) -// }); -// Some(cx.foreground().spawn(async move { -// apply_edits.await?; -// Ok(()) -// })) -// } - -// pub fn toggle_code_actions(&mut self, action: &ToggleCodeActions, cx: &mut ViewContext) { -// let mut context_menu = self.context_menu.write(); -// if matches!(context_menu.as_ref(), Some(ContextMenu::CodeActions(_))) { -// *context_menu = None; -// cx.notify(); -// return; -// } -// drop(context_menu); - -// let deployed_from_indicator = action.deployed_from_indicator; -// let mut task = self.code_actions_task.take(); -// cx.spawn(|this, mut cx| async move { -// while let Some(prev_task) = task { -// prev_task.await; -// task = this.update(&mut cx, |this, _| this.code_actions_task.take())?; -// } - -// this.update(&mut cx, |this, cx| { -// if this.focused { -// if let Some((buffer, actions)) = this.available_code_actions.clone() { -// this.completion_tasks.clear(); -// this.discard_copilot_suggestion(cx); -// *this.context_menu.write() = -// Some(ContextMenu::CodeActions(CodeActionsMenu { -// buffer, -// actions, -// selected_item: Default::default(), -// list: Default::default(), -// deployed_from_indicator, -// })); -// } -// } -// })?; - -// Ok::<_, anyhow::Error>(()) -// }) -// .detach_and_log_err(cx); -// } - -// pub fn confirm_code_action( -// workspace: &mut Workspace, -// action: &ConfirmCodeAction, -// cx: &mut ViewContext, -// ) -> Option>> { -// let editor = workspace.active_item(cx)?.act_as::(cx)?; -// let actions_menu = if let ContextMenu::CodeActions(menu) = -// editor.update(cx, |editor, cx| editor.hide_context_menu(cx))? -// { -// menu -// } else { -// return None; -// }; -// let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item); -// let action = actions_menu.actions.get(action_ix)?.clone(); -// let title = action.lsp_action.title.clone(); -// let buffer = actions_menu.buffer; - -// let apply_code_actions = workspace.project().clone().update(cx, |project, cx| { -// project.apply_code_action(buffer, action, true, cx) -// }); -// let editor = editor.downgrade(); -// Some(cx.spawn(|workspace, cx| async move { -// let project_transaction = apply_code_actions.await?; -// Self::open_project_transaction(&editor, workspace, project_transaction, title, cx).await -// })) -// } - -// async fn open_project_transaction( -// this: &WeakViewHandle Result<()> { -// let replica_id = this.read_with(&cx, |this, cx| this.replica_id(cx))?; - -// let mut entries = transaction.0.into_iter().collect::>(); -// entries.sort_unstable_by_key(|(buffer, _)| { -// buffer.read_with(&cx, |buffer, _| buffer.file().map(|f| f.path().clone())) -// }); - -// // If the project transaction's edits are all contained within this editor, then -// // avoid opening a new editor to display them. - -// if let Some((buffer, transaction)) = entries.first() { -// if entries.len() == 1 { -// let excerpt = this.read_with(&cx, |editor, cx| { -// editor -// .buffer() -// .read(cx) -// .excerpt_containing(editor.selections.newest_anchor().head(), cx) -// })?; -// if let Some((_, excerpted_buffer, excerpt_range)) = excerpt { -// if excerpted_buffer == *buffer { -// let all_edits_within_excerpt = buffer.read_with(&cx, |buffer, _| { -// let excerpt_range = excerpt_range.to_offset(buffer); -// buffer -// .edited_ranges_for_transaction::(transaction) -// .all(|range| { -// excerpt_range.start <= range.start -// && excerpt_range.end >= range.end -// }) -// }); - -// if all_edits_within_excerpt { -// return Ok(()); -// } -// } -// } -// } -// } else { -// return Ok(()); -// } - -// let mut ranges_to_highlight = Vec::new(); -// let excerpt_buffer = cx.add_model(|cx| { -// let mut multibuffer = MultiBuffer::new(replica_id).with_title(title); -// for (buffer_handle, transaction) in &entries { -// let buffer = buffer_handle.read(cx); -// ranges_to_highlight.extend( -// multibuffer.push_excerpts_with_context_lines( -// buffer_handle.clone(), -// buffer -// .edited_ranges_for_transaction::(transaction) -// .collect(), -// 1, -// cx, -// ), -// ); -// } -// multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx); -// multibuffer -// }); - -// workspace.update(&mut cx, |workspace, cx| { -// let project = workspace.project().clone(); -// let editor = -// cx.add_view(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), cx)); -// workspace.add_item(Box::new(editor.clone()), cx); -// editor.update(cx, |editor, cx| { -// editor.highlight_background::( -// ranges_to_highlight, -// |theme| theme.editor.highlighted_line_background, -// cx, -// ); -// }); -// })?; - -// Ok(()) -// } - -// fn refresh_code_actions(&mut self, cx: &mut ViewContext) -> Option<()> { -// let project = self.project.clone()?; -// let buffer = self.buffer.read(cx); -// let newest_selection = self.selections.newest_anchor().clone(); -// let (start_buffer, start) = buffer.text_anchor_for_position(newest_selection.start, cx)?; -// let (end_buffer, end) = buffer.text_anchor_for_position(newest_selection.end, cx)?; -// if start_buffer != end_buffer { -// return None; -// } - -// self.code_actions_task = Some(cx.spawn(|this, mut cx| async move { -// cx.background().timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT).await; - -// let actions = project -// .update(&mut cx, |project, cx| { -// project.code_actions(&start_buffer, start..end, cx) -// }) -// .await; - -// this.update(&mut cx, |this, cx| { -// this.available_code_actions = actions.log_err().and_then(|actions| { -// if actions.is_empty() { -// None -// } else { -// Some((start_buffer, actions.into())) -// } -// }); -// cx.notify(); -// }) -// .log_err(); -// })); -// None -// } - -// fn refresh_document_highlights(&mut self, cx: &mut ViewContext) -> Option<()> { -// if self.pending_rename.is_some() { -// return None; -// } - -// let project = self.project.clone()?; -// let buffer = self.buffer.read(cx); -// let newest_selection = self.selections.newest_anchor().clone(); -// let cursor_position = newest_selection.head(); -// let (cursor_buffer, cursor_buffer_position) = -// buffer.text_anchor_for_position(cursor_position.clone(), cx)?; -// let (tail_buffer, _) = buffer.text_anchor_for_position(newest_selection.tail(), cx)?; -// if cursor_buffer != tail_buffer { -// return None; -// } - -// self.document_highlights_task = Some(cx.spawn(|this, mut cx| async move { -// cx.background() -// .timer(DOCUMENT_HIGHLIGHTS_DEBOUNCE_TIMEOUT) -// .await; - -// let highlights = project -// .update(&mut cx, |project, cx| { -// project.document_highlights(&cursor_buffer, cursor_buffer_position, cx) -// }) -// .await -// .log_err(); - -// if let Some(highlights) = highlights { -// this.update(&mut cx, |this, cx| { -// if this.pending_rename.is_some() { -// return; -// } - -// let buffer_id = cursor_position.buffer_id; -// let buffer = this.buffer.read(cx); -// if !buffer -// .text_anchor_for_position(cursor_position, cx) -// .map_or(false, |(buffer, _)| buffer == cursor_buffer) -// { -// return; -// } - -// let cursor_buffer_snapshot = cursor_buffer.read(cx); -// let mut write_ranges = Vec::new(); -// let mut read_ranges = Vec::new(); -// for highlight in highlights { -// for (excerpt_id, excerpt_range) in -// buffer.excerpts_for_buffer(&cursor_buffer, cx) -// { -// let start = highlight -// .range -// .start -// .max(&excerpt_range.context.start, cursor_buffer_snapshot); -// let end = highlight -// .range -// .end -// .min(&excerpt_range.context.end, cursor_buffer_snapshot); -// if start.cmp(&end, cursor_buffer_snapshot).is_ge() { -// continue; -// } - -// let range = Anchor { -// buffer_id, -// excerpt_id: excerpt_id.clone(), -// text_anchor: start, -// }..Anchor { -// buffer_id, -// excerpt_id, -// text_anchor: end, -// }; -// if highlight.kind == lsp::DocumentHighlightKind::WRITE { -// write_ranges.push(range); -// } else { -// read_ranges.push(range); -// } -// } -// } - -// this.highlight_background::( -// read_ranges, -// |theme| theme.editor.document_highlight_read_background, -// cx, -// ); -// this.highlight_background::( -// write_ranges, -// |theme| theme.editor.document_highlight_write_background, -// cx, -// ); -// cx.notify(); -// }) -// .log_err(); -// } -// })); -// None -// } - -// fn refresh_copilot_suggestions( -// &mut self, -// debounce: bool, -// cx: &mut ViewContext, -// ) -> Option<()> { -// let copilot = Copilot::global(cx)?; -// if self.mode != EditorMode::Full || !copilot.read(cx).status().is_authorized() { -// self.clear_copilot_suggestions(cx); -// return None; -// } -// self.update_visible_copilot_suggestion(cx); - -// let snapshot = self.buffer.read(cx).snapshot(cx); -// let cursor = self.selections.newest_anchor().head(); -// if !self.is_copilot_enabled_at(cursor, &snapshot, cx) { -// self.clear_copilot_suggestions(cx); -// return None; -// } - -// let (buffer, buffer_position) = -// self.buffer.read(cx).text_anchor_for_position(cursor, cx)?; -// self.copilot_state.pending_refresh = cx.spawn(|this, mut cx| async move { -// if debounce { -// cx.background().timer(COPILOT_DEBOUNCE_TIMEOUT).await; -// } - -// let completions = copilot -// .update(&mut cx, |copilot, cx| { -// copilot.completions(&buffer, buffer_position, cx) -// }) -// .await -// .log_err() -// .into_iter() -// .flatten() -// .collect_vec(); - -// this.update(&mut cx, |this, cx| { -// if !completions.is_empty() { -// this.copilot_state.cycled = false; -// this.copilot_state.pending_cycling_refresh = Task::ready(None); -// this.copilot_state.completions.clear(); -// this.copilot_state.active_completion_index = 0; -// this.copilot_state.excerpt_id = Some(cursor.excerpt_id); -// for completion in completions { -// this.copilot_state.push_completion(completion); -// } -// this.update_visible_copilot_suggestion(cx); -// } -// }) -// .log_err()?; -// Some(()) -// }); - -// Some(()) -// } - -// fn cycle_copilot_suggestions( -// &mut self, -// direction: Direction, -// cx: &mut ViewContext, -// ) -> Option<()> { -// let copilot = Copilot::global(cx)?; -// if self.mode != EditorMode::Full || !copilot.read(cx).status().is_authorized() { -// return None; -// } - -// if self.copilot_state.cycled { -// self.copilot_state.cycle_completions(direction); -// self.update_visible_copilot_suggestion(cx); -// } else { -// let cursor = self.selections.newest_anchor().head(); -// let (buffer, buffer_position) = -// self.buffer.read(cx).text_anchor_for_position(cursor, cx)?; -// self.copilot_state.pending_cycling_refresh = cx.spawn(|this, mut cx| async move { -// let completions = copilot -// .update(&mut cx, |copilot, cx| { -// copilot.completions_cycling(&buffer, buffer_position, cx) -// }) -// .await; - -// this.update(&mut cx, |this, cx| { -// this.copilot_state.cycled = true; -// for completion in completions.log_err().into_iter().flatten() { -// this.copilot_state.push_completion(completion); -// } -// this.copilot_state.cycle_completions(direction); -// this.update_visible_copilot_suggestion(cx); -// }) -// .log_err()?; - -// Some(()) -// }); -// } - -// Some(()) -// } - -// fn copilot_suggest(&mut self, _: &copilot::Suggest, cx: &mut ViewContext) { -// if !self.has_active_copilot_suggestion(cx) { -// self.refresh_copilot_suggestions(false, cx); -// return; -// } - -// self.update_visible_copilot_suggestion(cx); -// } - -// fn next_copilot_suggestion(&mut self, _: &copilot::NextSuggestion, cx: &mut ViewContext) { -// if self.has_active_copilot_suggestion(cx) { -// self.cycle_copilot_suggestions(Direction::Next, cx); -// } else { -// let is_copilot_disabled = self.refresh_copilot_suggestions(false, cx).is_none(); -// if is_copilot_disabled { -// cx.propagate_action(); -// } -// } -// } - -// fn previous_copilot_suggestion( -// &mut self, -// _: &copilot::PreviousSuggestion, -// cx: &mut ViewContext, -// ) { -// if self.has_active_copilot_suggestion(cx) { -// self.cycle_copilot_suggestions(Direction::Prev, cx); -// } else { -// let is_copilot_disabled = self.refresh_copilot_suggestions(false, cx).is_none(); -// if is_copilot_disabled { -// cx.propagate_action(); -// } -// } -// } - -// fn accept_copilot_suggestion(&mut self, cx: &mut ViewContext) -> bool { -// if let Some(suggestion) = self.take_active_copilot_suggestion(cx) { -// if let Some((copilot, completion)) = -// Copilot::global(cx).zip(self.copilot_state.active_completion()) -// { -// copilot -// .update(cx, |copilot, cx| copilot.accept_completion(completion, cx)) -// .detach_and_log_err(cx); - -// self.report_copilot_event(Some(completion.uuid.clone()), true, cx) -// } -// cx.emit(Event::InputHandled { -// utf16_range_to_replace: None, -// text: suggestion.text.to_string().into(), -// }); -// self.insert_with_autoindent_mode(&suggestion.text.to_string(), None, cx); -// cx.notify(); -// true -// } else { -// false -// } -// } - -// fn discard_copilot_suggestion(&mut self, cx: &mut ViewContext) -> bool { -// if let Some(suggestion) = self.take_active_copilot_suggestion(cx) { -// if let Some(copilot) = Copilot::global(cx) { -// copilot -// .update(cx, |copilot, cx| { -// copilot.discard_completions(&self.copilot_state.completions, cx) -// }) -// .detach_and_log_err(cx); - -// self.report_copilot_event(None, false, cx) -// } - -// self.display_map.update(cx, |map, cx| { -// map.splice_inlays(vec![suggestion.id], Vec::new(), cx) -// }); -// cx.notify(); -// true -// } else { -// false -// } -// } - -// fn is_copilot_enabled_at( -// &self, -// location: Anchor, -// snapshot: &MultiBufferSnapshot, -// cx: &mut ViewContext, -// ) -> bool { -// let file = snapshot.file_at(location); -// let language = snapshot.language_at(location); -// let settings = all_language_settings(file, cx); -// settings.copilot_enabled(language, file.map(|f| f.path().as_ref())) -// } - -// fn has_active_copilot_suggestion(&self, cx: &AppContext) -> bool { -// if let Some(suggestion) = self.copilot_state.suggestion.as_ref() { -// let buffer = self.buffer.read(cx).read(cx); -// suggestion.position.is_valid(&buffer) -// } else { -// false -// } -// } - -// fn take_active_copilot_suggestion(&mut self, cx: &mut ViewContext) -> Option { -// let suggestion = self.copilot_state.suggestion.take()?; -// self.display_map.update(cx, |map, cx| { -// map.splice_inlays(vec![suggestion.id], Default::default(), cx); -// }); -// let buffer = self.buffer.read(cx).read(cx); - -// if suggestion.position.is_valid(&buffer) { -// Some(suggestion) -// } else { -// None -// } -// } - -// fn update_visible_copilot_suggestion(&mut self, cx: &mut ViewContext) { -// let snapshot = self.buffer.read(cx).snapshot(cx); -// let selection = self.selections.newest_anchor(); -// let cursor = selection.head(); - -// if self.context_menu.read().is_some() -// || !self.completion_tasks.is_empty() -// || selection.start != selection.end -// { -// self.discard_copilot_suggestion(cx); -// } else if let Some(text) = self -// .copilot_state -// .text_for_active_completion(cursor, &snapshot) -// { -// let text = Rope::from(text); -// let mut to_remove = Vec::new(); -// if let Some(suggestion) = self.copilot_state.suggestion.take() { -// to_remove.push(suggestion.id); -// } - -// let suggestion_inlay = -// Inlay::suggestion(post_inc(&mut self.next_inlay_id), cursor, text); -// self.copilot_state.suggestion = Some(suggestion_inlay.clone()); -// self.display_map.update(cx, move |map, cx| { -// map.splice_inlays(to_remove, vec![suggestion_inlay], cx) -// }); -// cx.notify(); -// } else { -// self.discard_copilot_suggestion(cx); -// } -// } - -// fn clear_copilot_suggestions(&mut self, cx: &mut ViewContext) { -// self.copilot_state = Default::default(); -// self.discard_copilot_suggestion(cx); -// } - -// pub fn render_code_actions_indicator( -// &self, -// style: &EditorStyle, -// is_active: bool, -// cx: &mut ViewContext, -// ) -> Option> { -// if self.available_code_actions.is_some() { -// enum CodeActions {} -// Some( -// MouseEventHandler::new::(0, cx, |state, _| { -// Svg::new("icons/bolt.svg").with_color( -// style -// .code_actions -// .indicator -// .in_state(is_active) -// .style_for(state) -// .color, -// ) -// }) -// .with_cursor_style(CursorStyle::PointingHand) -// .with_padding(Padding::uniform(3.)) -// .on_down(MouseButton::Left, |_, this, cx| { -// this.toggle_code_actions( -// &ToggleCodeActions { -// deployed_from_indicator: true, -// }, -// cx, -// ); -// }) -// .into_any(), -// ) -// } else { -// None -// } -// } - -// pub fn render_fold_indicators( -// &self, -// fold_data: Vec>, -// style: &EditorStyle, -// gutter_hovered: bool, -// line_height: f32, -// gutter_margin: f32, -// cx: &mut ViewContext, -// ) -> Vec>> { -// enum FoldIndicators {} - -// let style = style.folds.clone(); - -// fold_data -// .iter() -// .enumerate() -// .map(|(ix, fold_data)| { -// fold_data -// .map(|(fold_status, buffer_row, active)| { -// (active || gutter_hovered || fold_status == FoldStatus::Folded).then(|| { -// MouseEventHandler::new::( -// ix as usize, -// cx, -// |mouse_state, _| { -// Svg::new(match fold_status { -// FoldStatus::Folded => style.folded_icon.clone(), -// FoldStatus::Foldable => style.foldable_icon.clone(), -// }) -// .with_color( -// style -// .indicator -// .in_state(fold_status == FoldStatus::Folded) -// .style_for(mouse_state) -// .color, -// ) -// .constrained() -// .with_width(gutter_margin * style.icon_margin_scale) -// .aligned() -// .constrained() -// .with_height(line_height) -// .with_width(gutter_margin) -// .aligned() -// }, -// ) -// .with_cursor_style(CursorStyle::PointingHand) -// .with_padding(Padding::uniform(3.)) -// .on_click(MouseButton::Left, { -// move |_, editor, cx| match fold_status { -// FoldStatus::Folded => { -// editor.unfold_at(&UnfoldAt { buffer_row }, cx); -// } -// FoldStatus::Foldable => { -// editor.fold_at(&FoldAt { buffer_row }, cx); -// } -// } -// }) -// .into_any() -// }) -// }) -// .flatten() -// }) -// .collect() -// } - -// pub fn context_menu_visible(&self) -> bool { -// self.context_menu -// .read() -// .as_ref() -// .map_or(false, |menu| menu.visible()) -// } - -// pub fn render_context_menu( -// &self, -// cursor_position: DisplayPoint, -// style: EditorStyle, -// cx: &mut ViewContext, -// ) -> Option<(DisplayPoint, AnyElement)> { -// self.context_menu.read().as_ref().map(|menu| { -// menu.render( -// cursor_position, -// style, -// self.workspace.as_ref().map(|(w, _)| w.clone()), -// cx, -// ) -// }) -// } - -// fn hide_context_menu(&mut self, cx: &mut ViewContext) -> Option { -// cx.notify(); -// self.completion_tasks.clear(); -// let context_menu = self.context_menu.write().take(); -// if context_menu.is_some() { -// self.update_visible_copilot_suggestion(cx); -// } -// context_menu -// } - -// pub fn insert_snippet( -// &mut self, -// insertion_ranges: &[Range], -// snippet: Snippet, -// cx: &mut ViewContext, -// ) -> Result<()> { -// let tabstops = self.buffer.update(cx, |buffer, cx| { -// let snippet_text: Arc = snippet.text.clone().into(); -// buffer.edit( -// insertion_ranges -// .iter() -// .cloned() -// .map(|range| (range, snippet_text.clone())), -// Some(AutoindentMode::EachLine), -// cx, -// ); - -// let snapshot = &*buffer.read(cx); -// let snippet = &snippet; -// snippet -// .tabstops -// .iter() -// .map(|tabstop| { -// let mut tabstop_ranges = tabstop -// .iter() -// .flat_map(|tabstop_range| { -// let mut delta = 0_isize; -// insertion_ranges.iter().map(move |insertion_range| { -// let insertion_start = insertion_range.start as isize + delta; -// delta += -// snippet.text.len() as isize - insertion_range.len() as isize; - -// let start = snapshot.anchor_before( -// (insertion_start + tabstop_range.start) as usize, -// ); -// let end = snapshot -// .anchor_after((insertion_start + tabstop_range.end) as usize); -// start..end -// }) -// }) -// .collect::>(); -// tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot)); -// tabstop_ranges -// }) -// .collect::>() -// }); - -// if let Some(tabstop) = tabstops.first() { -// self.change_selections(Some(Autoscroll::fit()), cx, |s| { -// s.select_ranges(tabstop.iter().cloned()); -// }); -// self.snippet_stack.push(SnippetState { -// active_index: 0, -// ranges: tabstops, -// }); -// } - -// Ok(()) -// } - -// pub fn move_to_next_snippet_tabstop(&mut self, cx: &mut ViewContext) -> bool { -// self.move_to_snippet_tabstop(Bias::Right, cx) -// } - -// pub fn move_to_prev_snippet_tabstop(&mut self, cx: &mut ViewContext) -> bool { -// self.move_to_snippet_tabstop(Bias::Left, cx) -// } - -// pub fn move_to_snippet_tabstop(&mut self, bias: Bias, cx: &mut ViewContext) -> bool { -// if let Some(mut snippet) = self.snippet_stack.pop() { -// match bias { -// Bias::Left => { -// if snippet.active_index > 0 { -// snippet.active_index -= 1; -// } else { -// self.snippet_stack.push(snippet); -// return false; -// } -// } -// Bias::Right => { -// if snippet.active_index + 1 < snippet.ranges.len() { -// snippet.active_index += 1; -// } else { -// self.snippet_stack.push(snippet); -// return false; -// } -// } -// } -// if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) { -// self.change_selections(Some(Autoscroll::fit()), cx, |s| { -// s.select_anchor_ranges(current_ranges.iter().cloned()) -// }); -// // If snippet state is not at the last tabstop, push it back on the stack -// if snippet.active_index + 1 < snippet.ranges.len() { -// self.snippet_stack.push(snippet); -// } -// return true; -// } -// } - -// false -// } - -// pub fn clear(&mut self, cx: &mut ViewContext) { -// self.transact(cx, |this, cx| { -// this.select_all(&SelectAll, cx); -// this.insert("", cx); -// }); -// } - -// pub fn backspace(&mut self, _: &Backspace, cx: &mut ViewContext) { -// self.transact(cx, |this, cx| { -// this.select_autoclose_pair(cx); -// let mut selections = this.selections.all::(cx); -// if !this.selections.line_mode { -// let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx)); -// for selection in &mut selections { -// if selection.is_empty() { -// let old_head = selection.head(); -// let mut new_head = -// movement::left(&display_map, old_head.to_display_point(&display_map)) -// .to_point(&display_map); -// if let Some((buffer, line_buffer_range)) = display_map -// .buffer_snapshot -// .buffer_line_for_row(old_head.row) -// { -// let indent_size = -// buffer.indent_size_for_line(line_buffer_range.start.row); -// let indent_len = match indent_size.kind { -// IndentKind::Space => { -// buffer.settings_at(line_buffer_range.start, cx).tab_size -// } -// IndentKind::Tab => NonZeroU32::new(1).unwrap(), -// }; -// if old_head.column <= indent_size.len && old_head.column > 0 { -// let indent_len = indent_len.get(); -// new_head = cmp::min( -// new_head, -// Point::new( -// old_head.row, -// ((old_head.column - 1) / indent_len) * indent_len, -// ), -// ); -// } -// } - -// selection.set_head(new_head, SelectionGoal::None); -// } -// } -// } - -// this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections)); -// this.insert("", cx); -// this.refresh_copilot_suggestions(true, cx); -// }); -// } - -// pub fn delete(&mut self, _: &Delete, cx: &mut ViewContext) { -// self.transact(cx, |this, cx| { -// this.change_selections(Some(Autoscroll::fit()), cx, |s| { -// let line_mode = s.line_mode; -// s.move_with(|map, selection| { -// if selection.is_empty() && !line_mode { -// let cursor = movement::right(map, selection.head()); -// selection.end = cursor; -// selection.reversed = true; -// selection.goal = SelectionGoal::None; -// } -// }) -// }); -// this.insert("", cx); -// this.refresh_copilot_suggestions(true, cx); -// }); -// } - -// pub fn tab_prev(&mut self, _: &TabPrev, cx: &mut ViewContext) { -// if self.move_to_prev_snippet_tabstop(cx) { -// return; -// } - -// self.outdent(&Outdent, cx); -// } - -// pub fn tab(&mut self, _: &Tab, cx: &mut ViewContext) { -// if self.move_to_next_snippet_tabstop(cx) { -// return; -// } - -// let mut selections = self.selections.all_adjusted(cx); -// let buffer = self.buffer.read(cx); -// let snapshot = buffer.snapshot(cx); -// let rows_iter = selections.iter().map(|s| s.head().row); -// let suggested_indents = snapshot.suggested_indents(rows_iter, cx); - -// let mut edits = Vec::new(); -// let mut prev_edited_row = 0; -// let mut row_delta = 0; -// for selection in &mut selections { -// if selection.start.row != prev_edited_row { -// row_delta = 0; -// } -// prev_edited_row = selection.end.row; - -// // If the selection is non-empty, then increase the indentation of the selected lines. -// if !selection.is_empty() { -// row_delta = -// Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx); -// continue; -// } - -// // If the selection is empty and the cursor is in the leading whitespace before the -// // suggested indentation, then auto-indent the line. -// let cursor = selection.head(); -// let current_indent = snapshot.indent_size_for_line(cursor.row); -// if let Some(suggested_indent) = suggested_indents.get(&cursor.row).copied() { -// if cursor.column < suggested_indent.len -// && cursor.column <= current_indent.len -// && current_indent.len <= suggested_indent.len -// { -// selection.start = Point::new(cursor.row, suggested_indent.len); -// selection.end = selection.start; -// if row_delta == 0 { -// edits.extend(Buffer::edit_for_indent_size_adjustment( -// cursor.row, -// current_indent, -// suggested_indent, -// )); -// row_delta = suggested_indent.len - current_indent.len; -// } -// continue; -// } -// } - -// // Accept copilot suggestion if there is only one selection and the cursor is not -// // in the leading whitespace. -// if self.selections.count() == 1 -// && cursor.column >= current_indent.len -// && self.has_active_copilot_suggestion(cx) -// { -// self.accept_copilot_suggestion(cx); -// return; -// } - -// // Otherwise, insert a hard or soft tab. -// let settings = buffer.settings_at(cursor, cx); -// let tab_size = if settings.hard_tabs { -// IndentSize::tab() -// } else { -// let tab_size = settings.tab_size.get(); -// let char_column = snapshot -// .text_for_range(Point::new(cursor.row, 0)..cursor) -// .flat_map(str::chars) -// .count() -// + row_delta as usize; -// let chars_to_next_tab_stop = tab_size - (char_column as u32 % tab_size); -// IndentSize::spaces(chars_to_next_tab_stop) -// }; -// selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len); -// selection.end = selection.start; -// edits.push((cursor..cursor, tab_size.chars().collect::())); -// row_delta += tab_size.len; -// } - -// self.transact(cx, |this, cx| { -// this.buffer.update(cx, |b, cx| b.edit(edits, None, cx)); -// this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections)); -// this.refresh_copilot_suggestions(true, cx); -// }); -// } - -// pub fn indent(&mut self, _: &Indent, cx: &mut ViewContext) { -// let mut selections = self.selections.all::(cx); -// let mut prev_edited_row = 0; -// let mut row_delta = 0; -// let mut edits = Vec::new(); -// let buffer = self.buffer.read(cx); -// let snapshot = buffer.snapshot(cx); -// for selection in &mut selections { -// if selection.start.row != prev_edited_row { -// row_delta = 0; -// } -// prev_edited_row = selection.end.row; - -// row_delta = -// Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx); -// } - -// self.transact(cx, |this, cx| { -// this.buffer.update(cx, |b, cx| b.edit(edits, None, cx)); -// this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections)); -// }); -// } - -// fn indent_selection( -// buffer: &MultiBuffer, -// snapshot: &MultiBufferSnapshot, -// selection: &mut Selection, -// edits: &mut Vec<(Range, String)>, -// delta_for_start_row: u32, -// cx: &AppContext, -// ) -> u32 { -// let settings = buffer.settings_at(selection.start, cx); -// let tab_size = settings.tab_size.get(); -// let indent_kind = if settings.hard_tabs { -// IndentKind::Tab -// } else { -// IndentKind::Space -// }; -// let mut start_row = selection.start.row; -// let mut end_row = selection.end.row + 1; - -// // If a selection ends at the beginning of a line, don't indent -// // that last line. -// if selection.end.column == 0 { -// end_row -= 1; -// } - -// // Avoid re-indenting a row that has already been indented by a -// // previous selection, but still update this selection's column -// // to reflect that indentation. -// if delta_for_start_row > 0 { -// start_row += 1; -// selection.start.column += delta_for_start_row; -// if selection.end.row == selection.start.row { -// selection.end.column += delta_for_start_row; -// } -// } - -// let mut delta_for_end_row = 0; -// for row in start_row..end_row { -// let current_indent = snapshot.indent_size_for_line(row); -// let indent_delta = match (current_indent.kind, indent_kind) { -// (IndentKind::Space, IndentKind::Space) => { -// let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size); -// IndentSize::spaces(columns_to_next_tab_stop) -// } -// (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size), -// (_, IndentKind::Tab) => IndentSize::tab(), -// }; - -// let row_start = Point::new(row, 0); -// edits.push(( -// row_start..row_start, -// indent_delta.chars().collect::(), -// )); - -// // Update this selection's endpoints to reflect the indentation. -// if row == selection.start.row { -// selection.start.column += indent_delta.len; -// } -// if row == selection.end.row { -// selection.end.column += indent_delta.len; -// delta_for_end_row = indent_delta.len; -// } -// } - -// if selection.start.row == selection.end.row { -// delta_for_start_row + delta_for_end_row -// } else { -// delta_for_end_row -// } -// } - -// pub fn outdent(&mut self, _: &Outdent, cx: &mut ViewContext) { -// let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); -// let selections = self.selections.all::(cx); -// let mut deletion_ranges = Vec::new(); -// let mut last_outdent = None; -// { -// let buffer = self.buffer.read(cx); -// let snapshot = buffer.snapshot(cx); -// for selection in &selections { -// let settings = buffer.settings_at(selection.start, cx); -// let tab_size = settings.tab_size.get(); -// let mut rows = selection.spanned_rows(false, &display_map); - -// // Avoid re-outdenting a row that has already been outdented by a -// // previous selection. -// if let Some(last_row) = last_outdent { -// if last_row == rows.start { -// rows.start += 1; -// } -// } - -// for row in rows { -// let indent_size = snapshot.indent_size_for_line(row); -// if indent_size.len > 0 { -// let deletion_len = match indent_size.kind { -// IndentKind::Space => { -// let columns_to_prev_tab_stop = indent_size.len % tab_size; -// if columns_to_prev_tab_stop == 0 { -// tab_size -// } else { -// columns_to_prev_tab_stop -// } -// } -// IndentKind::Tab => 1, -// }; -// deletion_ranges.push(Point::new(row, 0)..Point::new(row, deletion_len)); -// last_outdent = Some(row); -// } -// } -// } -// } - -// self.transact(cx, |this, cx| { -// this.buffer.update(cx, |buffer, cx| { -// let empty_str: Arc = "".into(); -// buffer.edit( -// deletion_ranges -// .into_iter() -// .map(|range| (range, empty_str.clone())), -// None, -// cx, -// ); -// }); -// let selections = this.selections.all::(cx); -// this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections)); -// }); -// } - -// pub fn delete_line(&mut self, _: &DeleteLine, cx: &mut ViewContext) { -// let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); -// let selections = self.selections.all::(cx); - -// let mut new_cursors = Vec::new(); -// let mut edit_ranges = Vec::new(); -// let mut selections = selections.iter().peekable(); -// while let Some(selection) = selections.next() { -// let mut rows = selection.spanned_rows(false, &display_map); -// let goal_display_column = selection.head().to_display_point(&display_map).column(); - -// // Accumulate contiguous regions of rows that we want to delete. -// while let Some(next_selection) = selections.peek() { -// let next_rows = next_selection.spanned_rows(false, &display_map); -// if next_rows.start <= rows.end { -// rows.end = next_rows.end; -// selections.next().unwrap(); -// } else { -// break; -// } -// } - -// let buffer = &display_map.buffer_snapshot; -// let mut edit_start = Point::new(rows.start, 0).to_offset(buffer); -// let edit_end; -// let cursor_buffer_row; -// if buffer.max_point().row >= rows.end { -// // If there's a line after the range, delete the \n from the end of the row range -// // and position the cursor on the next line. -// edit_end = Point::new(rows.end, 0).to_offset(buffer); -// cursor_buffer_row = rows.end; -// } else { -// // If there isn't a line after the range, delete the \n from the line before the -// // start of the row range and position the cursor there. -// edit_start = edit_start.saturating_sub(1); -// edit_end = buffer.len(); -// cursor_buffer_row = rows.start.saturating_sub(1); -// } - -// let mut cursor = Point::new(cursor_buffer_row, 0).to_display_point(&display_map); -// *cursor.column_mut() = -// cmp::min(goal_display_column, display_map.line_len(cursor.row())); - -// new_cursors.push(( -// selection.id, -// buffer.anchor_after(cursor.to_point(&display_map)), -// )); -// edit_ranges.push(edit_start..edit_end); -// } - -// self.transact(cx, |this, cx| { -// let buffer = this.buffer.update(cx, |buffer, cx| { -// let empty_str: Arc = "".into(); -// buffer.edit( -// edit_ranges -// .into_iter() -// .map(|range| (range, empty_str.clone())), -// None, -// cx, -// ); -// buffer.snapshot(cx) -// }); -// let new_selections = new_cursors -// .into_iter() -// .map(|(id, cursor)| { -// let cursor = cursor.to_point(&buffer); -// Selection { -// id, -// start: cursor, -// end: cursor, -// reversed: false, -// goal: SelectionGoal::None, -// } -// }) -// .collect(); - -// this.change_selections(Some(Autoscroll::fit()), cx, |s| { -// s.select(new_selections); -// }); -// }); -// } - -// pub fn join_lines(&mut self, _: &JoinLines, cx: &mut ViewContext) { -// let mut row_ranges = Vec::>::new(); -// for selection in self.selections.all::(cx) { -// let start = selection.start.row; -// let end = if selection.start.row == selection.end.row { -// selection.start.row + 1 -// } else { -// selection.end.row -// }; - -// if let Some(last_row_range) = row_ranges.last_mut() { -// if start <= last_row_range.end { -// last_row_range.end = end; -// continue; -// } -// } -// row_ranges.push(start..end); -// } - -// let snapshot = self.buffer.read(cx).snapshot(cx); -// let mut cursor_positions = Vec::new(); -// for row_range in &row_ranges { -// let anchor = snapshot.anchor_before(Point::new( -// row_range.end - 1, -// snapshot.line_len(row_range.end - 1), -// )); -// cursor_positions.push(anchor.clone()..anchor); -// } - -// self.transact(cx, |this, cx| { -// for row_range in row_ranges.into_iter().rev() { -// for row in row_range.rev() { -// let end_of_line = Point::new(row, snapshot.line_len(row)); -// let indent = snapshot.indent_size_for_line(row + 1); -// let start_of_next_line = Point::new(row + 1, indent.len); - -// let replace = if snapshot.line_len(row + 1) > indent.len { -// " " -// } else { -// "" -// }; - -// this.buffer.update(cx, |buffer, cx| { -// buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx) -// }); -// } -// } - -// this.change_selections(Some(Autoscroll::fit()), cx, |s| { -// s.select_anchor_ranges(cursor_positions) -// }); -// }); -// } - -// pub fn sort_lines_case_sensitive( -// &mut self, -// _: &SortLinesCaseSensitive, -// cx: &mut ViewContext, -// ) { -// self.manipulate_lines(cx, |lines| lines.sort()) -// } - -// pub fn sort_lines_case_insensitive( -// &mut self, -// _: &SortLinesCaseInsensitive, -// cx: &mut ViewContext, -// ) { -// self.manipulate_lines(cx, |lines| lines.sort_by_key(|line| line.to_lowercase())) -// } - -// pub fn reverse_lines(&mut self, _: &ReverseLines, cx: &mut ViewContext) { -// self.manipulate_lines(cx, |lines| lines.reverse()) -// } - -// pub fn shuffle_lines(&mut self, _: &ShuffleLines, cx: &mut ViewContext) { -// self.manipulate_lines(cx, |lines| lines.shuffle(&mut thread_rng())) -// } - -// fn manipulate_lines(&mut self, cx: &mut ViewContext, mut callback: Fn) -// where -// Fn: FnMut(&mut [&str]), -// { -// let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); -// let buffer = self.buffer.read(cx).snapshot(cx); - -// let mut edits = Vec::new(); - -// let selections = self.selections.all::(cx); -// let mut selections = selections.iter().peekable(); -// let mut contiguous_row_selections = Vec::new(); -// let mut new_selections = Vec::new(); - -// while let Some(selection) = selections.next() { -// let (start_row, end_row) = consume_contiguous_rows( -// &mut contiguous_row_selections, -// selection, -// &display_map, -// &mut selections, -// ); - -// let start_point = Point::new(start_row, 0); -// let end_point = Point::new(end_row - 1, buffer.line_len(end_row - 1)); -// let text = buffer -// .text_for_range(start_point..end_point) -// .collect::(); -// let mut lines = text.split("\n").collect_vec(); - -// let lines_len = lines.len(); -// callback(&mut lines); - -// // This is a current limitation with selections. -// // If we wanted to support removing or adding lines, we'd need to fix the logic associated with selections. -// debug_assert!( -// lines.len() == lines_len, -// "callback should not change the number of lines" -// ); - -// edits.push((start_point..end_point, lines.join("\n"))); -// let start_anchor = buffer.anchor_after(start_point); -// let end_anchor = buffer.anchor_before(end_point); - -// // Make selection and push -// new_selections.push(Selection { -// id: selection.id, -// start: start_anchor.to_offset(&buffer), -// end: end_anchor.to_offset(&buffer), -// goal: SelectionGoal::None, -// reversed: selection.reversed, -// }); -// } - -// self.transact(cx, |this, cx| { -// this.buffer.update(cx, |buffer, cx| { -// buffer.edit(edits, None, cx); -// }); - -// this.change_selections(Some(Autoscroll::fit()), cx, |s| { -// s.select(new_selections); -// }); - -// this.request_autoscroll(Autoscroll::fit(), cx); -// }); -// } - -// pub fn convert_to_upper_case(&mut self, _: &ConvertToUpperCase, cx: &mut ViewContext) { -// self.manipulate_text(cx, |text| text.to_uppercase()) -// } - -// pub fn convert_to_lower_case(&mut self, _: &ConvertToLowerCase, cx: &mut ViewContext) { -// self.manipulate_text(cx, |text| text.to_lowercase()) -// } - -// pub fn convert_to_title_case(&mut self, _: &ConvertToTitleCase, cx: &mut ViewContext) { -// self.manipulate_text(cx, |text| { -// // Hack to get around the fact that to_case crate doesn't support '\n' as a word boundary -// // https://github.com/rutrum/convert-case/issues/16 -// text.split("\n") -// .map(|line| line.to_case(Case::Title)) -// .join("\n") -// }) -// } - -// pub fn convert_to_snake_case(&mut self, _: &ConvertToSnakeCase, cx: &mut ViewContext) { -// self.manipulate_text(cx, |text| text.to_case(Case::Snake)) -// } - -// pub fn convert_to_kebab_case(&mut self, _: &ConvertToKebabCase, cx: &mut ViewContext) { -// self.manipulate_text(cx, |text| text.to_case(Case::Kebab)) -// } - -// pub fn convert_to_upper_camel_case( -// &mut self, -// _: &ConvertToUpperCamelCase, -// cx: &mut ViewContext, -// ) { -// self.manipulate_text(cx, |text| { -// // Hack to get around the fact that to_case crate doesn't support '\n' as a word boundary -// // https://github.com/rutrum/convert-case/issues/16 -// text.split("\n") -// .map(|line| line.to_case(Case::UpperCamel)) -// .join("\n") -// }) -// } - -// pub fn convert_to_lower_camel_case( -// &mut self, -// _: &ConvertToLowerCamelCase, -// cx: &mut ViewContext, -// ) { -// self.manipulate_text(cx, |text| text.to_case(Case::Camel)) -// } - -// fn manipulate_text(&mut self, cx: &mut ViewContext, mut callback: Fn) -// where -// Fn: FnMut(&str) -> String, -// { -// let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); -// let buffer = self.buffer.read(cx).snapshot(cx); - -// let mut new_selections = Vec::new(); -// let mut edits = Vec::new(); -// let mut selection_adjustment = 0i32; - -// for selection in self.selections.all::(cx) { -// let selection_is_empty = selection.is_empty(); - -// let (start, end) = if selection_is_empty { -// let word_range = movement::surrounding_word( -// &display_map, -// selection.start.to_display_point(&display_map), -// ); -// let start = word_range.start.to_offset(&display_map, Bias::Left); -// let end = word_range.end.to_offset(&display_map, Bias::Left); -// (start, end) -// } else { -// (selection.start, selection.end) -// }; - -// let text = buffer.text_for_range(start..end).collect::(); -// let old_length = text.len() as i32; -// let text = callback(&text); - -// new_selections.push(Selection { -// start: (start as i32 - selection_adjustment) as usize, -// end: ((start + text.len()) as i32 - selection_adjustment) as usize, -// goal: SelectionGoal::None, -// ..selection -// }); - -// selection_adjustment += old_length - text.len() as i32; - -// edits.push((start..end, text)); -// } - -// self.transact(cx, |this, cx| { -// this.buffer.update(cx, |buffer, cx| { -// buffer.edit(edits, None, cx); -// }); - -// this.change_selections(Some(Autoscroll::fit()), cx, |s| { -// s.select(new_selections); -// }); - -// this.request_autoscroll(Autoscroll::fit(), cx); -// }); -// } - -// pub fn duplicate_line(&mut self, _: &DuplicateLine, cx: &mut ViewContext) { -// let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); -// let buffer = &display_map.buffer_snapshot; -// let selections = self.selections.all::(cx); - -// let mut edits = Vec::new(); -// let mut selections_iter = selections.iter().peekable(); -// while let Some(selection) = selections_iter.next() { -// // Avoid duplicating the same lines twice. -// let mut rows = selection.spanned_rows(false, &display_map); - -// while let Some(next_selection) = selections_iter.peek() { -// let next_rows = next_selection.spanned_rows(false, &display_map); -// if next_rows.start < rows.end { -// rows.end = next_rows.end; -// selections_iter.next().unwrap(); -// } else { -// break; -// } -// } - -// // Copy the text from the selected row region and splice it at the start of the region. -// let start = Point::new(rows.start, 0); -// let end = Point::new(rows.end - 1, buffer.line_len(rows.end - 1)); -// let text = buffer -// .text_for_range(start..end) -// .chain(Some("\n")) -// .collect::(); -// edits.push((start..start, text)); -// } - -// self.transact(cx, |this, cx| { -// this.buffer.update(cx, |buffer, cx| { -// buffer.edit(edits, None, cx); -// }); - -// this.request_autoscroll(Autoscroll::fit(), cx); -// }); -// } - -// pub fn move_line_up(&mut self, _: &MoveLineUp, cx: &mut ViewContext) { -// let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); -// let buffer = self.buffer.read(cx).snapshot(cx); - -// let mut edits = Vec::new(); -// let mut unfold_ranges = Vec::new(); -// let mut refold_ranges = Vec::new(); - -// let selections = self.selections.all::(cx); -// let mut selections = selections.iter().peekable(); -// let mut contiguous_row_selections = Vec::new(); -// let mut new_selections = Vec::new(); - -// while let Some(selection) = selections.next() { -// // Find all the selections that span a contiguous row range -// let (start_row, end_row) = consume_contiguous_rows( -// &mut contiguous_row_selections, -// selection, -// &display_map, -// &mut selections, -// ); - -// // Move the text spanned by the row range to be before the line preceding the row range -// if start_row > 0 { -// let range_to_move = Point::new(start_row - 1, buffer.line_len(start_row - 1)) -// ..Point::new(end_row - 1, buffer.line_len(end_row - 1)); -// let insertion_point = display_map -// .prev_line_boundary(Point::new(start_row - 1, 0)) -// .0; - -// // Don't move lines across excerpts -// if buffer -// .excerpt_boundaries_in_range(( -// Bound::Excluded(insertion_point), -// Bound::Included(range_to_move.end), -// )) -// .next() -// .is_none() -// { -// let text = buffer -// .text_for_range(range_to_move.clone()) -// .flat_map(|s| s.chars()) -// .skip(1) -// .chain(['\n']) -// .collect::(); - -// edits.push(( -// buffer.anchor_after(range_to_move.start) -// ..buffer.anchor_before(range_to_move.end), -// String::new(), -// )); -// let insertion_anchor = buffer.anchor_after(insertion_point); -// edits.push((insertion_anchor..insertion_anchor, text)); - -// let row_delta = range_to_move.start.row - insertion_point.row + 1; - -// // Move selections up -// new_selections.extend(contiguous_row_selections.drain(..).map( -// |mut selection| { -// selection.start.row -= row_delta; -// selection.end.row -= row_delta; -// selection -// }, -// )); - -// // Move folds up -// unfold_ranges.push(range_to_move.clone()); -// for fold in display_map.folds_in_range( -// buffer.anchor_before(range_to_move.start) -// ..buffer.anchor_after(range_to_move.end), -// ) { -// let mut start = fold.start.to_point(&buffer); -// let mut end = fold.end.to_point(&buffer); -// start.row -= row_delta; -// end.row -= row_delta; -// refold_ranges.push(start..end); -// } -// } -// } - -// // If we didn't move line(s), preserve the existing selections -// new_selections.append(&mut contiguous_row_selections); -// } - -// self.transact(cx, |this, cx| { -// this.unfold_ranges(unfold_ranges, true, true, cx); -// this.buffer.update(cx, |buffer, cx| { -// for (range, text) in edits { -// buffer.edit([(range, text)], None, cx); -// } -// }); -// this.fold_ranges(refold_ranges, true, cx); -// this.change_selections(Some(Autoscroll::fit()), cx, |s| { -// s.select(new_selections); -// }) -// }); -// } - -// pub fn move_line_down(&mut self, _: &MoveLineDown, cx: &mut ViewContext) { -// let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); -// let buffer = self.buffer.read(cx).snapshot(cx); - -// let mut edits = Vec::new(); -// let mut unfold_ranges = Vec::new(); -// let mut refold_ranges = Vec::new(); - -// let selections = self.selections.all::(cx); -// let mut selections = selections.iter().peekable(); -// let mut contiguous_row_selections = Vec::new(); -// let mut new_selections = Vec::new(); - -// while let Some(selection) = selections.next() { -// // Find all the selections that span a contiguous row range -// let (start_row, end_row) = consume_contiguous_rows( -// &mut contiguous_row_selections, -// selection, -// &display_map, -// &mut selections, -// ); - -// // Move the text spanned by the row range to be after the last line of the row range -// if end_row <= buffer.max_point().row { -// let range_to_move = Point::new(start_row, 0)..Point::new(end_row, 0); -// let insertion_point = display_map.next_line_boundary(Point::new(end_row, 0)).0; - -// // Don't move lines across excerpt boundaries -// if buffer -// .excerpt_boundaries_in_range(( -// Bound::Excluded(range_to_move.start), -// Bound::Included(insertion_point), -// )) -// .next() -// .is_none() -// { -// let mut text = String::from("\n"); -// text.extend(buffer.text_for_range(range_to_move.clone())); -// text.pop(); // Drop trailing newline -// edits.push(( -// buffer.anchor_after(range_to_move.start) -// ..buffer.anchor_before(range_to_move.end), -// String::new(), -// )); -// let insertion_anchor = buffer.anchor_after(insertion_point); -// edits.push((insertion_anchor..insertion_anchor, text)); - -// let row_delta = insertion_point.row - range_to_move.end.row + 1; - -// // Move selections down -// new_selections.extend(contiguous_row_selections.drain(..).map( -// |mut selection| { -// selection.start.row += row_delta; -// selection.end.row += row_delta; -// selection -// }, -// )); - -// // Move folds down -// unfold_ranges.push(range_to_move.clone()); -// for fold in display_map.folds_in_range( -// buffer.anchor_before(range_to_move.start) -// ..buffer.anchor_after(range_to_move.end), -// ) { -// let mut start = fold.start.to_point(&buffer); -// let mut end = fold.end.to_point(&buffer); -// start.row += row_delta; -// end.row += row_delta; -// refold_ranges.push(start..end); -// } -// } -// } - -// // If we didn't move line(s), preserve the existing selections -// new_selections.append(&mut contiguous_row_selections); -// } - -// self.transact(cx, |this, cx| { -// this.unfold_ranges(unfold_ranges, true, true, cx); -// this.buffer.update(cx, |buffer, cx| { -// for (range, text) in edits { -// buffer.edit([(range, text)], None, cx); -// } -// }); -// this.fold_ranges(refold_ranges, true, cx); -// this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(new_selections)); -// }); -// } - -// pub fn transpose(&mut self, _: &Transpose, cx: &mut ViewContext) { -// let text_layout_details = &self.text_layout_details(cx); -// self.transact(cx, |this, cx| { -// let edits = this.change_selections(Some(Autoscroll::fit()), cx, |s| { -// let mut edits: Vec<(Range, String)> = Default::default(); -// let line_mode = s.line_mode; -// s.move_with(|display_map, selection| { -// if !selection.is_empty() || line_mode { -// return; -// } - -// let mut head = selection.head(); -// let mut transpose_offset = head.to_offset(display_map, Bias::Right); -// if head.column() == display_map.line_len(head.row()) { -// transpose_offset = display_map -// .buffer_snapshot -// .clip_offset(transpose_offset.saturating_sub(1), Bias::Left); -// } - -// if transpose_offset == 0 { -// return; -// } - -// *head.column_mut() += 1; -// head = display_map.clip_point(head, Bias::Right); -// let goal = SelectionGoal::HorizontalPosition( -// display_map.x_for_point(head, &text_layout_details), -// ); -// selection.collapse_to(head, goal); - -// let transpose_start = display_map -// .buffer_snapshot -// .clip_offset(transpose_offset.saturating_sub(1), Bias::Left); -// if edits.last().map_or(true, |e| e.0.end <= transpose_start) { -// let transpose_end = display_map -// .buffer_snapshot -// .clip_offset(transpose_offset + 1, Bias::Right); -// if let Some(ch) = -// display_map.buffer_snapshot.chars_at(transpose_start).next() -// { -// edits.push((transpose_start..transpose_offset, String::new())); -// edits.push((transpose_end..transpose_end, ch.to_string())); -// } -// } -// }); -// edits -// }); -// this.buffer -// .update(cx, |buffer, cx| buffer.edit(edits, None, cx)); -// let selections = this.selections.all::(cx); -// this.change_selections(Some(Autoscroll::fit()), cx, |s| { -// s.select(selections); -// }); -// }); -// } - -// pub fn cut(&mut self, _: &Cut, cx: &mut ViewContext) { -// let mut text = String::new(); -// let buffer = self.buffer.read(cx).snapshot(cx); -// let mut selections = self.selections.all::(cx); -// let mut clipboard_selections = Vec::with_capacity(selections.len()); -// { -// let max_point = buffer.max_point(); -// let mut is_first = true; -// for selection in &mut selections { -// let is_entire_line = selection.is_empty() || self.selections.line_mode; -// if is_entire_line { -// selection.start = Point::new(selection.start.row, 0); -// selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0)); -// selection.goal = SelectionGoal::None; -// } -// if is_first { -// is_first = false; -// } else { -// text += "\n"; -// } -// let mut len = 0; -// for chunk in buffer.text_for_range(selection.start..selection.end) { -// text.push_str(chunk); -// len += chunk.len(); -// } -// clipboard_selections.push(ClipboardSelection { -// len, -// is_entire_line, -// first_line_indent: buffer.indent_size_for_line(selection.start.row).len, -// }); -// } -// } - -// self.transact(cx, |this, cx| { -// this.change_selections(Some(Autoscroll::fit()), cx, |s| { -// s.select(selections); -// }); -// this.insert("", cx); -// cx.write_to_clipboard(ClipboardItem::new(text).with_metadata(clipboard_selections)); -// }); -// } - -// pub fn copy(&mut self, _: &Copy, cx: &mut ViewContext) { -// let selections = self.selections.all::(cx); -// let buffer = self.buffer.read(cx).read(cx); -// let mut text = String::new(); - -// let mut clipboard_selections = Vec::with_capacity(selections.len()); -// { -// let max_point = buffer.max_point(); -// let mut is_first = true; -// for selection in selections.iter() { -// let mut start = selection.start; -// let mut end = selection.end; -// let is_entire_line = selection.is_empty() || self.selections.line_mode; -// if is_entire_line { -// start = Point::new(start.row, 0); -// end = cmp::min(max_point, Point::new(end.row + 1, 0)); -// } -// if is_first { -// is_first = false; -// } else { -// text += "\n"; -// } -// let mut len = 0; -// for chunk in buffer.text_for_range(start..end) { -// text.push_str(chunk); -// len += chunk.len(); -// } -// clipboard_selections.push(ClipboardSelection { -// len, -// is_entire_line, -// first_line_indent: buffer.indent_size_for_line(start.row).len, -// }); -// } -// } - -// cx.write_to_clipboard(ClipboardItem::new(text).with_metadata(clipboard_selections)); -// } - -// pub fn paste(&mut self, _: &Paste, cx: &mut ViewContext) { -// self.transact(cx, |this, cx| { -// if let Some(item) = cx.read_from_clipboard() { -// let clipboard_text = Cow::Borrowed(item.text()); -// if let Some(mut clipboard_selections) = item.metadata::>() { -// let old_selections = this.selections.all::(cx); -// let all_selections_were_entire_line = -// clipboard_selections.iter().all(|s| s.is_entire_line); -// let first_selection_indent_column = -// clipboard_selections.first().map(|s| s.first_line_indent); -// if clipboard_selections.len() != old_selections.len() { -// clipboard_selections.drain(..); -// } - -// this.buffer.update(cx, |buffer, cx| { -// let snapshot = buffer.read(cx); -// let mut start_offset = 0; -// let mut edits = Vec::new(); -// let mut original_indent_columns = Vec::new(); -// let line_mode = this.selections.line_mode; -// for (ix, selection) in old_selections.iter().enumerate() { -// let to_insert; -// let entire_line; -// let original_indent_column; -// if let Some(clipboard_selection) = clipboard_selections.get(ix) { -// let end_offset = start_offset + clipboard_selection.len; -// to_insert = &clipboard_text[start_offset..end_offset]; -// entire_line = clipboard_selection.is_entire_line; -// start_offset = end_offset + 1; -// original_indent_column = -// Some(clipboard_selection.first_line_indent); -// } else { -// to_insert = clipboard_text.as_str(); -// entire_line = all_selections_were_entire_line; -// original_indent_column = first_selection_indent_column -// } - -// // If the corresponding selection was empty when this slice of the -// // clipboard text was written, then the entire line containing the -// // selection was copied. If this selection is also currently empty, -// // then paste the line before the current line of the buffer. -// let range = if selection.is_empty() && !line_mode && entire_line { -// let column = selection.start.to_point(&snapshot).column as usize; -// let line_start = selection.start - column; -// line_start..line_start -// } else { -// selection.range() -// }; - -// edits.push((range, to_insert)); -// original_indent_columns.extend(original_indent_column); -// } -// drop(snapshot); - -// buffer.edit( -// edits, -// Some(AutoindentMode::Block { -// original_indent_columns, -// }), -// cx, -// ); -// }); - -// let selections = this.selections.all::(cx); -// this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections)); -// } else { -// this.insert(&clipboard_text, cx); -// } -// } -// }); -// } - -// pub fn undo(&mut self, _: &Undo, cx: &mut ViewContext) { -// if let Some(tx_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) { -// if let Some((selections, _)) = self.selection_history.transaction(tx_id).cloned() { -// self.change_selections(None, cx, |s| { -// s.select_anchors(selections.to_vec()); -// }); -// } -// self.request_autoscroll(Autoscroll::fit(), cx); -// self.unmark_text(cx); -// self.refresh_copilot_suggestions(true, cx); -// cx.emit(Event::Edited); -// } -// } - -// pub fn redo(&mut self, _: &Redo, cx: &mut ViewContext) { -// if let Some(tx_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) { -// if let Some((_, Some(selections))) = self.selection_history.transaction(tx_id).cloned() -// { -// self.change_selections(None, cx, |s| { -// s.select_anchors(selections.to_vec()); -// }); -// } -// self.request_autoscroll(Autoscroll::fit(), cx); -// self.unmark_text(cx); -// self.refresh_copilot_suggestions(true, cx); -// cx.emit(Event::Edited); -// } -// } - -// pub fn finalize_last_transaction(&mut self, cx: &mut ViewContext) { -// self.buffer -// .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx)); -// } - -// pub fn move_left(&mut self, _: &MoveLeft, cx: &mut ViewContext) { -// self.change_selections(Some(Autoscroll::fit()), cx, |s| { -// let line_mode = s.line_mode; -// s.move_with(|map, selection| { -// let cursor = if selection.is_empty() && !line_mode { -// movement::left(map, selection.start) -// } else { -// selection.start -// }; -// selection.collapse_to(cursor, SelectionGoal::None); -// }); -// }) -// } - -// pub fn select_left(&mut self, _: &SelectLeft, cx: &mut ViewContext) { -// self.change_selections(Some(Autoscroll::fit()), cx, |s| { -// s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None)); -// }) -// } - -// pub fn move_right(&mut self, _: &MoveRight, cx: &mut ViewContext) { -// self.change_selections(Some(Autoscroll::fit()), cx, |s| { -// let line_mode = s.line_mode; -// s.move_with(|map, selection| { -// let cursor = if selection.is_empty() && !line_mode { -// movement::right(map, selection.end) -// } else { -// selection.end -// }; -// selection.collapse_to(cursor, SelectionGoal::None) -// }); -// }) -// } - -// pub fn select_right(&mut self, _: &SelectRight, cx: &mut ViewContext) { -// self.change_selections(Some(Autoscroll::fit()), cx, |s| { -// s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None)); -// }) -// } - -// pub fn move_up(&mut self, _: &MoveUp, cx: &mut ViewContext) { -// if self.take_rename(true, cx).is_some() { -// return; -// } - -// if matches!(self.mode, EditorMode::SingleLine) { -// cx.propagate_action(); -// return; -// } - -// let text_layout_details = &self.text_layout_details(cx); - -// self.change_selections(Some(Autoscroll::fit()), cx, |s| { -// let line_mode = s.line_mode; -// s.move_with(|map, selection| { -// if !selection.is_empty() && !line_mode { -// selection.goal = SelectionGoal::None; -// } -// let (cursor, goal) = movement::up( -// map, -// selection.start, -// selection.goal, -// false, -// &text_layout_details, -// ); -// selection.collapse_to(cursor, goal); -// }); -// }) -// } - -// pub fn move_page_up(&mut self, action: &MovePageUp, cx: &mut ViewContext) { -// if self.take_rename(true, cx).is_some() { -// return; -// } - -// if matches!(self.mode, EditorMode::SingleLine) { -// cx.propagate_action(); -// return; -// } - -// let row_count = if let Some(row_count) = self.visible_line_count() { -// row_count as u32 - 1 -// } else { -// return; -// }; - -// let autoscroll = if action.center_cursor { -// Autoscroll::center() -// } else { -// Autoscroll::fit() -// }; - -// let text_layout_details = &self.text_layout_details(cx); - -// self.change_selections(Some(autoscroll), cx, |s| { -// let line_mode = s.line_mode; -// s.move_with(|map, selection| { -// if !selection.is_empty() && !line_mode { -// selection.goal = SelectionGoal::None; -// } -// let (cursor, goal) = movement::up_by_rows( -// map, -// selection.end, -// row_count, -// selection.goal, -// false, -// &text_layout_details, -// ); -// selection.collapse_to(cursor, goal); -// }); -// }); -// } - -// pub fn select_up(&mut self, _: &SelectUp, cx: &mut ViewContext) { -// let text_layout_details = &self.text_layout_details(cx); -// self.change_selections(Some(Autoscroll::fit()), cx, |s| { -// s.move_heads_with(|map, head, goal| { -// movement::up(map, head, goal, false, &text_layout_details) -// }) -// }) -// } - -// pub fn move_down(&mut self, _: &MoveDown, cx: &mut ViewContext) { -// self.take_rename(true, cx); - -// if self.mode == EditorMode::SingleLine { -// cx.propagate_action(); -// return; -// } - -// let text_layout_details = &self.text_layout_details(cx); -// self.change_selections(Some(Autoscroll::fit()), cx, |s| { -// let line_mode = s.line_mode; -// s.move_with(|map, selection| { -// if !selection.is_empty() && !line_mode { -// selection.goal = SelectionGoal::None; -// } -// let (cursor, goal) = movement::down( -// map, -// selection.end, -// selection.goal, -// false, -// &text_layout_details, -// ); -// selection.collapse_to(cursor, goal); -// }); -// }); -// } - -// pub fn move_page_down(&mut self, action: &MovePageDown, cx: &mut ViewContext) { -// if self.take_rename(true, cx).is_some() { -// return; -// } - -// if self -// .context_menu -// .write() -// .as_mut() -// .map(|menu| menu.select_last(self.project.as_ref(), cx)) -// .unwrap_or(false) -// { -// return; -// } - -// if matches!(self.mode, EditorMode::SingleLine) { -// cx.propagate_action(); -// return; -// } - -// let row_count = if let Some(row_count) = self.visible_line_count() { -// row_count as u32 - 1 -// } else { -// return; -// }; - -// let autoscroll = if action.center_cursor { -// Autoscroll::center() -// } else { -// Autoscroll::fit() -// }; - -// let text_layout_details = &self.text_layout_details(cx); -// self.change_selections(Some(autoscroll), cx, |s| { -// let line_mode = s.line_mode; -// s.move_with(|map, selection| { -// if !selection.is_empty() && !line_mode { -// selection.goal = SelectionGoal::None; -// } -// let (cursor, goal) = movement::down_by_rows( -// map, -// selection.end, -// row_count, -// selection.goal, -// false, -// &text_layout_details, -// ); -// selection.collapse_to(cursor, goal); -// }); -// }); -// } - -// pub fn select_down(&mut self, _: &SelectDown, cx: &mut ViewContext) { -// let text_layout_details = &self.text_layout_details(cx); -// self.change_selections(Some(Autoscroll::fit()), cx, |s| { -// s.move_heads_with(|map, head, goal| { -// movement::down(map, head, goal, false, &text_layout_details) -// }) -// }); -// } - -// pub fn context_menu_first(&mut self, _: &ContextMenuFirst, cx: &mut ViewContext) { -// if let Some(context_menu) = self.context_menu.write().as_mut() { -// context_menu.select_first(self.project.as_ref(), cx); -// } -// } - -// pub fn context_menu_prev(&mut self, _: &ContextMenuPrev, cx: &mut ViewContext) { -// if let Some(context_menu) = self.context_menu.write().as_mut() { -// context_menu.select_prev(self.project.as_ref(), cx); -// } -// } - -// pub fn context_menu_next(&mut self, _: &ContextMenuNext, cx: &mut ViewContext) { -// if let Some(context_menu) = self.context_menu.write().as_mut() { -// context_menu.select_next(self.project.as_ref(), cx); -// } -// } - -// pub fn context_menu_last(&mut self, _: &ContextMenuLast, cx: &mut ViewContext) { -// if let Some(context_menu) = self.context_menu.write().as_mut() { -// context_menu.select_last(self.project.as_ref(), cx); -// } -// } - -// pub fn move_to_previous_word_start( -// &mut self, -// _: &MoveToPreviousWordStart, -// cx: &mut ViewContext, -// ) { -// self.change_selections(Some(Autoscroll::fit()), cx, |s| { -// s.move_cursors_with(|map, head, _| { -// ( -// movement::previous_word_start(map, head), -// SelectionGoal::None, -// ) -// }); -// }) -// } - -// pub fn move_to_previous_subword_start( -// &mut self, -// _: &MoveToPreviousSubwordStart, -// cx: &mut ViewContext, -// ) { -// self.change_selections(Some(Autoscroll::fit()), cx, |s| { -// s.move_cursors_with(|map, head, _| { -// ( -// movement::previous_subword_start(map, head), -// SelectionGoal::None, -// ) -// }); -// }) -// } - -// pub fn select_to_previous_word_start( -// &mut self, -// _: &SelectToPreviousWordStart, -// cx: &mut ViewContext, -// ) { -// self.change_selections(Some(Autoscroll::fit()), cx, |s| { -// s.move_heads_with(|map, head, _| { -// ( -// movement::previous_word_start(map, head), -// SelectionGoal::None, -// ) -// }); -// }) -// } - -// pub fn select_to_previous_subword_start( -// &mut self, -// _: &SelectToPreviousSubwordStart, -// cx: &mut ViewContext, -// ) { -// self.change_selections(Some(Autoscroll::fit()), cx, |s| { -// s.move_heads_with(|map, head, _| { -// ( -// movement::previous_subword_start(map, head), -// SelectionGoal::None, -// ) -// }); -// }) -// } - -// pub fn delete_to_previous_word_start( -// &mut self, -// _: &DeleteToPreviousWordStart, -// cx: &mut ViewContext, -// ) { -// self.transact(cx, |this, cx| { -// this.select_autoclose_pair(cx); -// this.change_selections(Some(Autoscroll::fit()), cx, |s| { -// let line_mode = s.line_mode; -// s.move_with(|map, selection| { -// if selection.is_empty() && !line_mode { -// let cursor = movement::previous_word_start(map, selection.head()); -// selection.set_head(cursor, SelectionGoal::None); -// } -// }); -// }); -// this.insert("", cx); -// }); -// } - -// pub fn delete_to_previous_subword_start( -// &mut self, -// _: &DeleteToPreviousSubwordStart, -// cx: &mut ViewContext, -// ) { -// self.transact(cx, |this, cx| { -// this.select_autoclose_pair(cx); -// this.change_selections(Some(Autoscroll::fit()), cx, |s| { -// let line_mode = s.line_mode; -// s.move_with(|map, selection| { -// if selection.is_empty() && !line_mode { -// let cursor = movement::previous_subword_start(map, selection.head()); -// selection.set_head(cursor, SelectionGoal::None); -// } -// }); -// }); -// this.insert("", cx); -// }); -// } - -// pub fn move_to_next_word_end(&mut self, _: &MoveToNextWordEnd, cx: &mut ViewContext) { -// self.change_selections(Some(Autoscroll::fit()), cx, |s| { -// s.move_cursors_with(|map, head, _| { -// (movement::next_word_end(map, head), SelectionGoal::None) -// }); -// }) -// } - -// pub fn move_to_next_subword_end( -// &mut self, -// _: &MoveToNextSubwordEnd, -// cx: &mut ViewContext, -// ) { -// self.change_selections(Some(Autoscroll::fit()), cx, |s| { -// s.move_cursors_with(|map, head, _| { -// (movement::next_subword_end(map, head), SelectionGoal::None) -// }); -// }) -// } - -// pub fn select_to_next_word_end(&mut self, _: &SelectToNextWordEnd, cx: &mut ViewContext) { -// self.change_selections(Some(Autoscroll::fit()), cx, |s| { -// s.move_heads_with(|map, head, _| { -// (movement::next_word_end(map, head), SelectionGoal::None) -// }); -// }) -// } - -// pub fn select_to_next_subword_end( -// &mut self, -// _: &SelectToNextSubwordEnd, -// cx: &mut ViewContext, -// ) { -// self.change_selections(Some(Autoscroll::fit()), cx, |s| { -// s.move_heads_with(|map, head, _| { -// (movement::next_subword_end(map, head), SelectionGoal::None) -// }); -// }) -// } - -// pub fn delete_to_next_word_end(&mut self, _: &DeleteToNextWordEnd, cx: &mut ViewContext) { -// self.transact(cx, |this, cx| { -// this.change_selections(Some(Autoscroll::fit()), cx, |s| { -// let line_mode = s.line_mode; -// s.move_with(|map, selection| { -// if selection.is_empty() && !line_mode { -// let cursor = movement::next_word_end(map, selection.head()); -// selection.set_head(cursor, SelectionGoal::None); -// } -// }); -// }); -// this.insert("", cx); -// }); -// } - -// pub fn delete_to_next_subword_end( -// &mut self, -// _: &DeleteToNextSubwordEnd, -// cx: &mut ViewContext, -// ) { -// self.transact(cx, |this, cx| { -// this.change_selections(Some(Autoscroll::fit()), cx, |s| { -// s.move_with(|map, selection| { -// if selection.is_empty() { -// let cursor = movement::next_subword_end(map, selection.head()); -// selection.set_head(cursor, SelectionGoal::None); -// } -// }); -// }); -// this.insert("", cx); -// }); -// } - -// pub fn move_to_beginning_of_line( -// &mut self, -// _: &MoveToBeginningOfLine, -// cx: &mut ViewContext, -// ) { -// self.change_selections(Some(Autoscroll::fit()), cx, |s| { -// s.move_cursors_with(|map, head, _| { -// ( -// movement::indented_line_beginning(map, head, true), -// SelectionGoal::None, -// ) -// }); -// }) -// } - -// pub fn select_to_beginning_of_line( -// &mut self, -// action: &SelectToBeginningOfLine, -// cx: &mut ViewContext, -// ) { -// self.change_selections(Some(Autoscroll::fit()), cx, |s| { -// s.move_heads_with(|map, head, _| { -// ( -// movement::indented_line_beginning(map, head, action.stop_at_soft_wraps), -// SelectionGoal::None, -// ) -// }); -// }); -// } - -// pub fn delete_to_beginning_of_line( -// &mut self, -// _: &DeleteToBeginningOfLine, -// cx: &mut ViewContext, -// ) { -// self.transact(cx, |this, cx| { -// this.change_selections(Some(Autoscroll::fit()), cx, |s| { -// s.move_with(|_, selection| { -// selection.reversed = true; -// }); -// }); - -// this.select_to_beginning_of_line( -// &SelectToBeginningOfLine { -// stop_at_soft_wraps: false, -// }, -// cx, -// ); -// this.backspace(&Backspace, cx); -// }); -// } - -// pub fn move_to_end_of_line(&mut self, _: &MoveToEndOfLine, cx: &mut ViewContext) { -// self.change_selections(Some(Autoscroll::fit()), cx, |s| { -// s.move_cursors_with(|map, head, _| { -// (movement::line_end(map, head, true), SelectionGoal::None) -// }); -// }) -// } - -// pub fn select_to_end_of_line( -// &mut self, -// action: &SelectToEndOfLine, -// cx: &mut ViewContext, -// ) { -// self.change_selections(Some(Autoscroll::fit()), cx, |s| { -// s.move_heads_with(|map, head, _| { -// ( -// movement::line_end(map, head, action.stop_at_soft_wraps), -// SelectionGoal::None, -// ) -// }); -// }) -// } - -// pub fn delete_to_end_of_line(&mut self, _: &DeleteToEndOfLine, cx: &mut ViewContext) { -// self.transact(cx, |this, cx| { -// this.select_to_end_of_line( -// &SelectToEndOfLine { -// stop_at_soft_wraps: false, -// }, -// cx, -// ); -// this.delete(&Delete, cx); -// }); -// } - -// pub fn cut_to_end_of_line(&mut self, _: &CutToEndOfLine, cx: &mut ViewContext) { -// self.transact(cx, |this, cx| { -// this.select_to_end_of_line( -// &SelectToEndOfLine { -// stop_at_soft_wraps: false, -// }, -// cx, -// ); -// this.cut(&Cut, cx); -// }); -// } - -// pub fn move_to_start_of_paragraph( -// &mut self, -// _: &MoveToStartOfParagraph, -// cx: &mut ViewContext, -// ) { -// if matches!(self.mode, EditorMode::SingleLine) { -// cx.propagate_action(); -// return; -// } - -// self.change_selections(Some(Autoscroll::fit()), cx, |s| { -// s.move_with(|map, selection| { -// selection.collapse_to( -// movement::start_of_paragraph(map, selection.head(), 1), -// SelectionGoal::None, -// ) -// }); -// }) -// } - -// pub fn move_to_end_of_paragraph( -// &mut self, -// _: &MoveToEndOfParagraph, -// cx: &mut ViewContext, -// ) { -// if matches!(self.mode, EditorMode::SingleLine) { -// cx.propagate_action(); -// return; -// } - -// self.change_selections(Some(Autoscroll::fit()), cx, |s| { -// s.move_with(|map, selection| { -// selection.collapse_to( -// movement::end_of_paragraph(map, selection.head(), 1), -// SelectionGoal::None, -// ) -// }); -// }) -// } - -// pub fn select_to_start_of_paragraph( -// &mut self, -// _: &SelectToStartOfParagraph, -// cx: &mut ViewContext, -// ) { -// if matches!(self.mode, EditorMode::SingleLine) { -// cx.propagate_action(); -// return; -// } - -// self.change_selections(Some(Autoscroll::fit()), cx, |s| { -// s.move_heads_with(|map, head, _| { -// ( -// movement::start_of_paragraph(map, head, 1), -// SelectionGoal::None, -// ) -// }); -// }) -// } - -// pub fn select_to_end_of_paragraph( -// &mut self, -// _: &SelectToEndOfParagraph, -// cx: &mut ViewContext, -// ) { -// if matches!(self.mode, EditorMode::SingleLine) { -// cx.propagate_action(); -// return; -// } - -// self.change_selections(Some(Autoscroll::fit()), cx, |s| { -// s.move_heads_with(|map, head, _| { -// ( -// movement::end_of_paragraph(map, head, 1), -// SelectionGoal::None, -// ) -// }); -// }) -// } - -// pub fn move_to_beginning(&mut self, _: &MoveToBeginning, cx: &mut ViewContext) { -// if matches!(self.mode, EditorMode::SingleLine) { -// cx.propagate_action(); -// return; -// } - -// self.change_selections(Some(Autoscroll::fit()), cx, |s| { -// s.select_ranges(vec![0..0]); -// }); -// } - -// pub fn select_to_beginning(&mut self, _: &SelectToBeginning, cx: &mut ViewContext) { -// let mut selection = self.selections.last::(cx); -// selection.set_head(Point::zero(), SelectionGoal::None); - -// self.change_selections(Some(Autoscroll::fit()), cx, |s| { -// s.select(vec![selection]); -// }); -// } - -// pub fn move_to_end(&mut self, _: &MoveToEnd, cx: &mut ViewContext) { -// if matches!(self.mode, EditorMode::SingleLine) { -// cx.propagate_action(); -// return; -// } - -// let cursor = self.buffer.read(cx).read(cx).len(); -// self.change_selections(Some(Autoscroll::fit()), cx, |s| { -// s.select_ranges(vec![cursor..cursor]) -// }); -// } - -// pub fn set_nav_history(&mut self, nav_history: Option) { -// self.nav_history = nav_history; -// } - -// pub fn nav_history(&self) -> Option<&ItemNavHistory> { -// self.nav_history.as_ref() -// } - -// fn push_to_nav_history( -// &mut self, -// cursor_anchor: Anchor, -// new_position: Option, -// cx: &mut ViewContext, -// ) { -// if let Some(nav_history) = self.nav_history.as_mut() { -// let buffer = self.buffer.read(cx).read(cx); -// let cursor_position = cursor_anchor.to_point(&buffer); -// let scroll_state = self.scroll_manager.anchor(); -// let scroll_top_row = scroll_state.top_row(&buffer); -// drop(buffer); - -// if let Some(new_position) = new_position { -// let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs(); -// if row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA { -// return; -// } -// } - -// nav_history.push( -// Some(NavigationData { -// cursor_anchor, -// cursor_position, -// scroll_anchor: scroll_state, -// scroll_top_row, -// }), -// cx, -// ); -// } -// } - -// pub fn select_to_end(&mut self, _: &SelectToEnd, cx: &mut ViewContext) { -// let buffer = self.buffer.read(cx).snapshot(cx); -// let mut selection = self.selections.first::(cx); -// selection.set_head(buffer.len(), SelectionGoal::None); -// self.change_selections(Some(Autoscroll::fit()), cx, |s| { -// s.select(vec![selection]); -// }); -// } - -// pub fn select_all(&mut self, _: &SelectAll, cx: &mut ViewContext) { -// let end = self.buffer.read(cx).read(cx).len(); -// self.change_selections(None, cx, |s| { -// s.select_ranges(vec![0..end]); -// }); -// } - -// pub fn select_line(&mut self, _: &SelectLine, cx: &mut ViewContext) { -// let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); -// let mut selections = self.selections.all::(cx); -// let max_point = display_map.buffer_snapshot.max_point(); -// for selection in &mut selections { -// let rows = selection.spanned_rows(true, &display_map); -// selection.start = Point::new(rows.start, 0); -// selection.end = cmp::min(max_point, Point::new(rows.end, 0)); -// selection.reversed = false; -// } -// self.change_selections(Some(Autoscroll::fit()), cx, |s| { -// s.select(selections); -// }); -// } - -// pub fn split_selection_into_lines( -// &mut self, -// _: &SplitSelectionIntoLines, -// cx: &mut ViewContext, -// ) { -// let mut to_unfold = Vec::new(); -// let mut new_selection_ranges = Vec::new(); -// { -// let selections = self.selections.all::(cx); -// let buffer = self.buffer.read(cx).read(cx); -// for selection in selections { -// for row in selection.start.row..selection.end.row { -// let cursor = Point::new(row, buffer.line_len(row)); -// new_selection_ranges.push(cursor..cursor); -// } -// new_selection_ranges.push(selection.end..selection.end); -// to_unfold.push(selection.start..selection.end); -// } -// } -// self.unfold_ranges(to_unfold, true, true, cx); -// self.change_selections(Some(Autoscroll::fit()), cx, |s| { -// s.select_ranges(new_selection_ranges); -// }); -// } - -// pub fn add_selection_above(&mut self, _: &AddSelectionAbove, cx: &mut ViewContext) { -// self.add_selection(true, cx); -// } - -// pub fn add_selection_below(&mut self, _: &AddSelectionBelow, cx: &mut ViewContext) { -// self.add_selection(false, cx); -// } - -// fn add_selection(&mut self, above: bool, cx: &mut ViewContext) { -// let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); -// let mut selections = self.selections.all::(cx); -// let text_layout_details = self.text_layout_details(cx); -// let mut state = self.add_selections_state.take().unwrap_or_else(|| { -// let oldest_selection = selections.iter().min_by_key(|s| s.id).unwrap().clone(); -// let range = oldest_selection.display_range(&display_map).sorted(); - -// let start_x = display_map.x_for_point(range.start, &text_layout_details); -// let end_x = display_map.x_for_point(range.end, &text_layout_details); -// let positions = start_x.min(end_x)..start_x.max(end_x); - -// selections.clear(); -// let mut stack = Vec::new(); -// for row in range.start.row()..=range.end.row() { -// if let Some(selection) = self.selections.build_columnar_selection( -// &display_map, -// row, -// &positions, -// oldest_selection.reversed, -// &text_layout_details, -// ) { -// stack.push(selection.id); -// selections.push(selection); -// } -// } - -// if above { -// stack.reverse(); -// } - -// AddSelectionsState { above, stack } -// }); - -// let last_added_selection = *state.stack.last().unwrap(); -// let mut new_selections = Vec::new(); -// if above == state.above { -// let end_row = if above { -// 0 -// } else { -// display_map.max_point().row() -// }; - -// 'outer: for selection in selections { -// if selection.id == last_added_selection { -// let range = selection.display_range(&display_map).sorted(); -// debug_assert_eq!(range.start.row(), range.end.row()); -// let mut row = range.start.row(); -// let positions = if let SelectionGoal::HorizontalRange { start, end } = -// selection.goal -// { -// start..end -// } else { -// let start_x = display_map.x_for_point(range.start, &text_layout_details); -// let end_x = display_map.x_for_point(range.end, &text_layout_details); - -// start_x.min(end_x)..start_x.max(end_x) -// }; - -// while row != end_row { -// if above { -// row -= 1; -// } else { -// row += 1; -// } - -// if let Some(new_selection) = self.selections.build_columnar_selection( -// &display_map, -// row, -// &positions, -// selection.reversed, -// &text_layout_details, -// ) { -// state.stack.push(new_selection.id); -// if above { -// new_selections.push(new_selection); -// new_selections.push(selection); -// } else { -// new_selections.push(selection); -// new_selections.push(new_selection); -// } - -// continue 'outer; -// } -// } -// } - -// new_selections.push(selection); -// } -// } else { -// new_selections = selections; -// new_selections.retain(|s| s.id != last_added_selection); -// state.stack.pop(); -// } - -// self.change_selections(Some(Autoscroll::fit()), cx, |s| { -// s.select(new_selections); -// }); -// if state.stack.len() > 1 { -// self.add_selections_state = Some(state); -// } -// } - -// pub fn select_next_match_internal( -// &mut self, -// display_map: &DisplaySnapshot, -// replace_newest: bool, -// autoscroll: Option, -// cx: &mut ViewContext, -// ) -> Result<()> { -// fn select_next_match_ranges( -// this: &mut Editor, -// range: Range, -// replace_newest: bool, -// auto_scroll: Option, -// cx: &mut ViewContext, -// ) { -// this.unfold_ranges([range.clone()], false, true, cx); -// this.change_selections(auto_scroll, cx, |s| { -// if replace_newest { -// s.delete(s.newest_anchor().id); -// } -// s.insert_range(range.clone()); -// }); -// } - -// let buffer = &display_map.buffer_snapshot; -// let mut selections = self.selections.all::(cx); -// if let Some(mut select_next_state) = self.select_next_state.take() { -// let query = &select_next_state.query; -// if !select_next_state.done { -// let first_selection = selections.iter().min_by_key(|s| s.id).unwrap(); -// let last_selection = selections.iter().max_by_key(|s| s.id).unwrap(); -// let mut next_selected_range = None; - -// let bytes_after_last_selection = -// buffer.bytes_in_range(last_selection.end..buffer.len()); -// let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start); -// let query_matches = query -// .stream_find_iter(bytes_after_last_selection) -// .map(|result| (last_selection.end, result)) -// .chain( -// query -// .stream_find_iter(bytes_before_first_selection) -// .map(|result| (0, result)), -// ); - -// for (start_offset, query_match) in query_matches { -// let query_match = query_match.unwrap(); // can only fail due to I/O -// let offset_range = -// start_offset + query_match.start()..start_offset + query_match.end(); -// let display_range = offset_range.start.to_display_point(&display_map) -// ..offset_range.end.to_display_point(&display_map); - -// if !select_next_state.wordwise -// || (!movement::is_inside_word(&display_map, display_range.start) -// && !movement::is_inside_word(&display_map, display_range.end)) -// { -// if selections -// .iter() -// .find(|selection| selection.range().overlaps(&offset_range)) -// .is_none() -// { -// next_selected_range = Some(offset_range); -// break; -// } -// } -// } - -// if let Some(next_selected_range) = next_selected_range { -// select_next_match_ranges( -// self, -// next_selected_range, -// replace_newest, -// autoscroll, -// cx, -// ); -// } else { -// select_next_state.done = true; -// } -// } - -// self.select_next_state = Some(select_next_state); -// } else if selections.len() == 1 { -// let selection = selections.last_mut().unwrap(); -// if selection.start == selection.end { -// let word_range = movement::surrounding_word( -// &display_map, -// selection.start.to_display_point(&display_map), -// ); -// selection.start = word_range.start.to_offset(&display_map, Bias::Left); -// selection.end = word_range.end.to_offset(&display_map, Bias::Left); -// selection.goal = SelectionGoal::None; -// selection.reversed = false; - -// let query = buffer -// .text_for_range(selection.start..selection.end) -// .collect::(); - -// let is_empty = query.is_empty(); -// let select_state = SelectNextState { -// query: AhoCorasick::new(&[query])?, -// wordwise: true, -// done: is_empty, -// }; -// select_next_match_ranges( -// self, -// selection.start..selection.end, -// replace_newest, -// autoscroll, -// cx, -// ); -// self.select_next_state = Some(select_state); -// } else { -// let query = buffer -// .text_for_range(selection.start..selection.end) -// .collect::(); -// self.select_next_state = Some(SelectNextState { -// query: AhoCorasick::new(&[query])?, -// wordwise: false, -// done: false, -// }); -// self.select_next_match_internal(display_map, replace_newest, autoscroll, cx)?; -// } -// } -// Ok(()) -// } - -// pub fn select_all_matches( -// &mut self, -// action: &SelectAllMatches, -// cx: &mut ViewContext, -// ) -> Result<()> { -// self.push_to_selection_history(); -// let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); - -// loop { -// self.select_next_match_internal(&display_map, action.replace_newest, None, cx)?; - -// if self -// .select_next_state -// .as_ref() -// .map(|selection_state| selection_state.done) -// .unwrap_or(true) -// { -// break; -// } -// } - -// Ok(()) -// } - -// pub fn select_next(&mut self, action: &SelectNext, cx: &mut ViewContext) -> Result<()> { -// self.push_to_selection_history(); -// let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); -// self.select_next_match_internal( -// &display_map, -// action.replace_newest, -// Some(Autoscroll::newest()), -// cx, -// )?; -// Ok(()) -// } - -// pub fn select_previous( -// &mut self, -// action: &SelectPrevious, -// cx: &mut ViewContext, -// ) -> Result<()> { -// self.push_to_selection_history(); -// let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); -// let buffer = &display_map.buffer_snapshot; -// let mut selections = self.selections.all::(cx); -// if let Some(mut select_prev_state) = self.select_prev_state.take() { -// let query = &select_prev_state.query; -// if !select_prev_state.done { -// let first_selection = selections.iter().min_by_key(|s| s.id).unwrap(); -// let last_selection = selections.iter().max_by_key(|s| s.id).unwrap(); -// let mut next_selected_range = None; -// // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer. -// let bytes_before_last_selection = -// buffer.reversed_bytes_in_range(0..last_selection.start); -// let bytes_after_first_selection = -// buffer.reversed_bytes_in_range(first_selection.end..buffer.len()); -// let query_matches = query -// .stream_find_iter(bytes_before_last_selection) -// .map(|result| (last_selection.start, result)) -// .chain( -// query -// .stream_find_iter(bytes_after_first_selection) -// .map(|result| (buffer.len(), result)), -// ); -// for (end_offset, query_match) in query_matches { -// let query_match = query_match.unwrap(); // can only fail due to I/O -// let offset_range = -// end_offset - query_match.end()..end_offset - query_match.start(); -// let display_range = offset_range.start.to_display_point(&display_map) -// ..offset_range.end.to_display_point(&display_map); - -// if !select_prev_state.wordwise -// || (!movement::is_inside_word(&display_map, display_range.start) -// && !movement::is_inside_word(&display_map, display_range.end)) -// { -// next_selected_range = Some(offset_range); -// break; -// } -// } - -// if let Some(next_selected_range) = next_selected_range { -// self.unfold_ranges([next_selected_range.clone()], false, true, cx); -// self.change_selections(Some(Autoscroll::newest()), cx, |s| { -// if action.replace_newest { -// s.delete(s.newest_anchor().id); -// } -// s.insert_range(next_selected_range); -// }); -// } else { -// select_prev_state.done = true; -// } -// } - -// self.select_prev_state = Some(select_prev_state); -// } else if selections.len() == 1 { -// let selection = selections.last_mut().unwrap(); -// if selection.start == selection.end { -// let word_range = movement::surrounding_word( -// &display_map, -// selection.start.to_display_point(&display_map), -// ); -// selection.start = word_range.start.to_offset(&display_map, Bias::Left); -// selection.end = word_range.end.to_offset(&display_map, Bias::Left); -// selection.goal = SelectionGoal::None; -// selection.reversed = false; - -// let query = buffer -// .text_for_range(selection.start..selection.end) -// .collect::(); -// let query = query.chars().rev().collect::(); -// let select_state = SelectNextState { -// query: AhoCorasick::new(&[query])?, -// wordwise: true, -// done: false, -// }; -// self.unfold_ranges([selection.start..selection.end], false, true, cx); -// self.change_selections(Some(Autoscroll::newest()), cx, |s| { -// s.select(selections); -// }); -// self.select_prev_state = Some(select_state); -// } else { -// let query = buffer -// .text_for_range(selection.start..selection.end) -// .collect::(); -// let query = query.chars().rev().collect::(); -// self.select_prev_state = Some(SelectNextState { -// query: AhoCorasick::new(&[query])?, -// wordwise: false, -// done: false, -// }); -// self.select_previous(action, cx)?; -// } -// } -// Ok(()) -// } - -// pub fn toggle_comments(&mut self, action: &ToggleComments, cx: &mut ViewContext) { -// let text_layout_details = &self.text_layout_details(cx); -// self.transact(cx, |this, cx| { -// let mut selections = this.selections.all::(cx); -// let mut edits = Vec::new(); -// let mut selection_edit_ranges = Vec::new(); -// let mut last_toggled_row = None; -// let snapshot = this.buffer.read(cx).read(cx); -// let empty_str: Arc = "".into(); -// let mut suffixes_inserted = Vec::new(); - -// fn comment_prefix_range( -// snapshot: &MultiBufferSnapshot, -// row: u32, -// comment_prefix: &str, -// comment_prefix_whitespace: &str, -// ) -> Range { -// let start = Point::new(row, snapshot.indent_size_for_line(row).len); - -// let mut line_bytes = snapshot -// .bytes_in_range(start..snapshot.max_point()) -// .flatten() -// .copied(); - -// // If this line currently begins with the line comment prefix, then record -// // the range containing the prefix. -// if line_bytes -// .by_ref() -// .take(comment_prefix.len()) -// .eq(comment_prefix.bytes()) -// { -// // Include any whitespace that matches the comment prefix. -// let matching_whitespace_len = line_bytes -// .zip(comment_prefix_whitespace.bytes()) -// .take_while(|(a, b)| a == b) -// .count() as u32; -// let end = Point::new( -// start.row, -// start.column + comment_prefix.len() as u32 + matching_whitespace_len, -// ); -// start..end -// } else { -// start..start -// } -// } - -// fn comment_suffix_range( -// snapshot: &MultiBufferSnapshot, -// row: u32, -// comment_suffix: &str, -// comment_suffix_has_leading_space: bool, -// ) -> Range { -// let end = Point::new(row, snapshot.line_len(row)); -// let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32); - -// let mut line_end_bytes = snapshot -// .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end) -// .flatten() -// .copied(); - -// let leading_space_len = if suffix_start_column > 0 -// && line_end_bytes.next() == Some(b' ') -// && comment_suffix_has_leading_space -// { -// 1 -// } else { -// 0 -// }; - -// // If this line currently begins with the line comment prefix, then record -// // the range containing the prefix. -// if line_end_bytes.by_ref().eq(comment_suffix.bytes()) { -// let start = Point::new(end.row, suffix_start_column - leading_space_len); -// start..end -// } else { -// end..end -// } -// } - -// // TODO: Handle selections that cross excerpts -// for selection in &mut selections { -// let start_column = snapshot.indent_size_for_line(selection.start.row).len; -// let language = if let Some(language) = -// snapshot.language_scope_at(Point::new(selection.start.row, start_column)) -// { -// language -// } else { -// continue; -// }; - -// selection_edit_ranges.clear(); - -// // If multiple selections contain a given row, avoid processing that -// // row more than once. -// let mut start_row = selection.start.row; -// if last_toggled_row == Some(start_row) { -// start_row += 1; -// } -// let end_row = -// if selection.end.row > selection.start.row && selection.end.column == 0 { -// selection.end.row - 1 -// } else { -// selection.end.row -// }; -// last_toggled_row = Some(end_row); - -// if start_row > end_row { -// continue; -// } - -// // If the language has line comments, toggle those. -// if let Some(full_comment_prefix) = language.line_comment_prefix() { -// // Split the comment prefix's trailing whitespace into a separate string, -// // as that portion won't be used for detecting if a line is a comment. -// let comment_prefix = full_comment_prefix.trim_end_matches(' '); -// let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..]; -// let mut all_selection_lines_are_comments = true; - -// for row in start_row..=end_row { -// if snapshot.is_line_blank(row) && start_row < end_row { -// continue; -// } - -// let prefix_range = comment_prefix_range( -// snapshot.deref(), -// row, -// comment_prefix, -// comment_prefix_whitespace, -// ); -// if prefix_range.is_empty() { -// all_selection_lines_are_comments = false; -// } -// selection_edit_ranges.push(prefix_range); -// } - -// if all_selection_lines_are_comments { -// edits.extend( -// selection_edit_ranges -// .iter() -// .cloned() -// .map(|range| (range, empty_str.clone())), -// ); -// } else { -// let min_column = selection_edit_ranges -// .iter() -// .map(|r| r.start.column) -// .min() -// .unwrap_or(0); -// edits.extend(selection_edit_ranges.iter().map(|range| { -// let position = Point::new(range.start.row, min_column); -// (position..position, full_comment_prefix.clone()) -// })); -// } -// } else if let Some((full_comment_prefix, comment_suffix)) = -// language.block_comment_delimiters() -// { -// let comment_prefix = full_comment_prefix.trim_end_matches(' '); -// let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..]; -// let prefix_range = comment_prefix_range( -// snapshot.deref(), -// start_row, -// comment_prefix, -// comment_prefix_whitespace, -// ); -// let suffix_range = comment_suffix_range( -// snapshot.deref(), -// end_row, -// comment_suffix.trim_start_matches(' '), -// comment_suffix.starts_with(' '), -// ); - -// if prefix_range.is_empty() || suffix_range.is_empty() { -// edits.push(( -// prefix_range.start..prefix_range.start, -// full_comment_prefix.clone(), -// )); -// edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone())); -// suffixes_inserted.push((end_row, comment_suffix.len())); -// } else { -// edits.push((prefix_range, empty_str.clone())); -// edits.push((suffix_range, empty_str.clone())); -// } -// } else { -// continue; -// } -// } - -// drop(snapshot); -// this.buffer.update(cx, |buffer, cx| { -// buffer.edit(edits, None, cx); -// }); - -// // Adjust selections so that they end before any comment suffixes that -// // were inserted. -// let mut suffixes_inserted = suffixes_inserted.into_iter().peekable(); -// let mut selections = this.selections.all::(cx); -// let snapshot = this.buffer.read(cx).read(cx); -// for selection in &mut selections { -// while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() { -// match row.cmp(&selection.end.row) { -// Ordering::Less => { -// suffixes_inserted.next(); -// continue; -// } -// Ordering::Greater => break, -// Ordering::Equal => { -// if selection.end.column == snapshot.line_len(row) { -// if selection.is_empty() { -// selection.start.column -= suffix_len as u32; -// } -// selection.end.column -= suffix_len as u32; -// } -// break; -// } -// } -// } -// } - -// drop(snapshot); -// this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections)); - -// let selections = this.selections.all::(cx); -// let selections_on_single_row = selections.windows(2).all(|selections| { -// selections[0].start.row == selections[1].start.row -// && selections[0].end.row == selections[1].end.row -// && selections[0].start.row == selections[0].end.row -// }); -// let selections_selecting = selections -// .iter() -// .any(|selection| selection.start != selection.end); -// let advance_downwards = action.advance_downwards -// && selections_on_single_row -// && !selections_selecting -// && this.mode != EditorMode::SingleLine; - -// if advance_downwards { -// let snapshot = this.buffer.read(cx).snapshot(cx); - -// this.change_selections(Some(Autoscroll::fit()), cx, |s| { -// s.move_cursors_with(|display_snapshot, display_point, _| { -// let mut point = display_point.to_point(display_snapshot); -// point.row += 1; -// point = snapshot.clip_point(point, Bias::Left); -// let display_point = point.to_display_point(display_snapshot); -// let goal = SelectionGoal::HorizontalPosition( -// display_snapshot.x_for_point(display_point, &text_layout_details), -// ); -// (display_point, goal) -// }) -// }); -// } -// }); -// } - -// pub fn select_larger_syntax_node( -// &mut self, -// _: &SelectLargerSyntaxNode, -// cx: &mut ViewContext, -// ) { -// let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); -// let buffer = self.buffer.read(cx).snapshot(cx); -// let old_selections = self.selections.all::(cx).into_boxed_slice(); - -// let mut stack = mem::take(&mut self.select_larger_syntax_node_stack); -// let mut selected_larger_node = false; -// let new_selections = old_selections -// .iter() -// .map(|selection| { -// let old_range = selection.start..selection.end; -// let mut new_range = old_range.clone(); -// while let Some(containing_range) = -// buffer.range_for_syntax_ancestor(new_range.clone()) -// { -// new_range = containing_range; -// if !display_map.intersects_fold(new_range.start) -// && !display_map.intersects_fold(new_range.end) -// { -// break; -// } -// } - -// selected_larger_node |= new_range != old_range; -// Selection { -// id: selection.id, -// start: new_range.start, -// end: new_range.end, -// goal: SelectionGoal::None, -// reversed: selection.reversed, -// } -// }) -// .collect::>(); - -// if selected_larger_node { -// stack.push(old_selections); -// self.change_selections(Some(Autoscroll::fit()), cx, |s| { -// s.select(new_selections); -// }); -// } -// self.select_larger_syntax_node_stack = stack; -// } - -// pub fn select_smaller_syntax_node( -// &mut self, -// _: &SelectSmallerSyntaxNode, -// cx: &mut ViewContext, -// ) { -// let mut stack = mem::take(&mut self.select_larger_syntax_node_stack); -// if let Some(selections) = stack.pop() { -// self.change_selections(Some(Autoscroll::fit()), cx, |s| { -// s.select(selections.to_vec()); -// }); -// } -// self.select_larger_syntax_node_stack = stack; -// } - -// pub fn move_to_enclosing_bracket( -// &mut self, -// _: &MoveToEnclosingBracket, -// cx: &mut ViewContext, -// ) { -// self.change_selections(Some(Autoscroll::fit()), cx, |s| { -// s.move_offsets_with(|snapshot, selection| { -// let Some(enclosing_bracket_ranges) = -// snapshot.enclosing_bracket_ranges(selection.start..selection.end) -// else { -// return; -// }; - -// let mut best_length = usize::MAX; -// let mut best_inside = false; -// let mut best_in_bracket_range = false; -// let mut best_destination = None; -// for (open, close) in enclosing_bracket_ranges { -// let close = close.to_inclusive(); -// let length = close.end() - open.start; -// let inside = selection.start >= open.end && selection.end <= *close.start(); -// let in_bracket_range = open.to_inclusive().contains(&selection.head()) -// || close.contains(&selection.head()); - -// // If best is next to a bracket and current isn't, skip -// if !in_bracket_range && best_in_bracket_range { -// continue; -// } - -// // Prefer smaller lengths unless best is inside and current isn't -// if length > best_length && (best_inside || !inside) { -// continue; -// } - -// best_length = length; -// best_inside = inside; -// best_in_bracket_range = in_bracket_range; -// best_destination = Some( -// if close.contains(&selection.start) && close.contains(&selection.end) { -// if inside { -// open.end -// } else { -// open.start -// } -// } else { -// if inside { -// *close.start() -// } else { -// *close.end() -// } -// }, -// ); -// } - -// if let Some(destination) = best_destination { -// selection.collapse_to(destination, SelectionGoal::None); -// } -// }) -// }); -// } - -// pub fn undo_selection(&mut self, _: &UndoSelection, cx: &mut ViewContext) { -// self.end_selection(cx); -// self.selection_history.mode = SelectionHistoryMode::Undoing; -// if let Some(entry) = self.selection_history.undo_stack.pop_back() { -// self.change_selections(None, cx, |s| s.select_anchors(entry.selections.to_vec())); -// self.select_next_state = entry.select_next_state; -// self.select_prev_state = entry.select_prev_state; -// self.add_selections_state = entry.add_selections_state; -// self.request_autoscroll(Autoscroll::newest(), cx); -// } -// self.selection_history.mode = SelectionHistoryMode::Normal; -// } - -// pub fn redo_selection(&mut self, _: &RedoSelection, cx: &mut ViewContext) { -// self.end_selection(cx); -// self.selection_history.mode = SelectionHistoryMode::Redoing; -// if let Some(entry) = self.selection_history.redo_stack.pop_back() { -// self.change_selections(None, cx, |s| s.select_anchors(entry.selections.to_vec())); -// self.select_next_state = entry.select_next_state; -// self.select_prev_state = entry.select_prev_state; -// self.add_selections_state = entry.add_selections_state; -// self.request_autoscroll(Autoscroll::newest(), cx); -// } -// self.selection_history.mode = SelectionHistoryMode::Normal; -// } - -// fn go_to_diagnostic(&mut self, _: &GoToDiagnostic, cx: &mut ViewContext) { -// self.go_to_diagnostic_impl(Direction::Next, cx) -// } - -// fn go_to_prev_diagnostic(&mut self, _: &GoToPrevDiagnostic, cx: &mut ViewContext) { -// self.go_to_diagnostic_impl(Direction::Prev, cx) -// } - -// pub fn go_to_diagnostic_impl(&mut self, direction: Direction, cx: &mut ViewContext) { -// let buffer = self.buffer.read(cx).snapshot(cx); -// let selection = self.selections.newest::(cx); - -// // If there is an active Diagnostic Popover. Jump to it's diagnostic instead. -// if direction == Direction::Next { -// if let Some(popover) = self.hover_state.diagnostic_popover.as_ref() { -// let (group_id, jump_to) = popover.activation_info(); -// if self.activate_diagnostics(group_id, cx) { -// self.change_selections(Some(Autoscroll::fit()), cx, |s| { -// let mut new_selection = s.newest_anchor().clone(); -// new_selection.collapse_to(jump_to, SelectionGoal::None); -// s.select_anchors(vec![new_selection.clone()]); -// }); -// } -// return; -// } -// } - -// let mut active_primary_range = self.active_diagnostics.as_ref().map(|active_diagnostics| { -// active_diagnostics -// .primary_range -// .to_offset(&buffer) -// .to_inclusive() -// }); -// let mut search_start = if let Some(active_primary_range) = active_primary_range.as_ref() { -// if active_primary_range.contains(&selection.head()) { -// *active_primary_range.end() -// } else { -// selection.head() -// } -// } else { -// selection.head() -// }; - -// loop { -// let mut diagnostics = if direction == Direction::Prev { -// buffer.diagnostics_in_range::<_, usize>(0..search_start, true) -// } else { -// buffer.diagnostics_in_range::<_, usize>(search_start..buffer.len(), false) -// }; -// let group = diagnostics.find_map(|entry| { -// if entry.diagnostic.is_primary -// && entry.diagnostic.severity <= DiagnosticSeverity::WARNING -// && !entry.range.is_empty() -// && Some(entry.range.end) != active_primary_range.as_ref().map(|r| *r.end()) -// && !entry.range.contains(&search_start) -// { -// Some((entry.range, entry.diagnostic.group_id)) -// } else { -// None -// } -// }); - -// if let Some((primary_range, group_id)) = group { -// if self.activate_diagnostics(group_id, cx) { -// self.change_selections(Some(Autoscroll::fit()), cx, |s| { -// s.select(vec![Selection { -// id: selection.id, -// start: primary_range.start, -// end: primary_range.start, -// reversed: false, -// goal: SelectionGoal::None, -// }]); -// }); -// } -// break; -// } else { -// // Cycle around to the start of the buffer, potentially moving back to the start of -// // the currently active diagnostic. -// active_primary_range.take(); -// if direction == Direction::Prev { -// if search_start == buffer.len() { -// break; -// } else { -// search_start = buffer.len(); -// } -// } else if search_start == 0 { -// break; -// } else { -// search_start = 0; -// } -// } -// } -// } - -// fn go_to_hunk(&mut self, _: &GoToHunk, cx: &mut ViewContext) { -// let snapshot = self -// .display_map -// .update(cx, |display_map, cx| display_map.snapshot(cx)); -// let selection = self.selections.newest::(cx); - -// if !self.seek_in_direction( -// &snapshot, -// selection.head(), -// false, -// snapshot -// .buffer_snapshot -// .git_diff_hunks_in_range((selection.head().row + 1)..u32::MAX), -// cx, -// ) { -// let wrapped_point = Point::zero(); -// self.seek_in_direction( -// &snapshot, -// wrapped_point, -// true, -// snapshot -// .buffer_snapshot -// .git_diff_hunks_in_range((wrapped_point.row + 1)..u32::MAX), -// cx, -// ); -// } -// } - -// fn go_to_prev_hunk(&mut self, _: &GoToPrevHunk, cx: &mut ViewContext) { -// let snapshot = self -// .display_map -// .update(cx, |display_map, cx| display_map.snapshot(cx)); -// let selection = self.selections.newest::(cx); - -// if !self.seek_in_direction( -// &snapshot, -// selection.head(), -// false, -// snapshot -// .buffer_snapshot -// .git_diff_hunks_in_range_rev(0..selection.head().row), -// cx, -// ) { -// let wrapped_point = snapshot.buffer_snapshot.max_point(); -// self.seek_in_direction( -// &snapshot, -// wrapped_point, -// true, -// snapshot -// .buffer_snapshot -// .git_diff_hunks_in_range_rev(0..wrapped_point.row), -// cx, -// ); -// } -// } - -// fn seek_in_direction( -// &mut self, -// snapshot: &DisplaySnapshot, -// initial_point: Point, -// is_wrapped: bool, -// hunks: impl Iterator>, -// cx: &mut ViewContext, -// ) -> bool { -// let display_point = initial_point.to_display_point(snapshot); -// let mut hunks = hunks -// .map(|hunk| diff_hunk_to_display(hunk, &snapshot)) -// .filter(|hunk| { -// if is_wrapped { -// true -// } else { -// !hunk.contains_display_row(display_point.row()) -// } -// }) -// .dedup(); - -// if let Some(hunk) = hunks.next() { -// self.change_selections(Some(Autoscroll::fit()), cx, |s| { -// let row = hunk.start_display_row(); -// let point = DisplayPoint::new(row, 0); -// s.select_display_ranges([point..point]); -// }); - -// true -// } else { -// false -// } -// } - -// pub fn go_to_definition(&mut self, _: &GoToDefinition, cx: &mut ViewContext) { -// self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, cx); -// } - -// pub fn go_to_type_definition(&mut self, _: &GoToTypeDefinition, cx: &mut ViewContext) { -// self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, cx); -// } - -// pub fn go_to_definition_split(&mut self, _: &GoToDefinitionSplit, cx: &mut ViewContext) { -// self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, cx); -// } - -// pub fn go_to_type_definition_split( -// &mut self, -// _: &GoToTypeDefinitionSplit, -// cx: &mut ViewContext, -// ) { -// self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, cx); -// } - -// fn go_to_definition_of_kind( -// &mut self, -// kind: GotoDefinitionKind, -// split: bool, -// cx: &mut ViewContext, -// ) { -// let Some(workspace) = self.workspace(cx) else { -// return; -// }; -// let buffer = self.buffer.read(cx); -// let head = self.selections.newest::(cx).head(); -// let (buffer, head) = if let Some(text_anchor) = buffer.text_anchor_for_position(head, cx) { -// text_anchor -// } else { -// return; -// }; - -// let project = workspace.read(cx).project().clone(); -// let definitions = project.update(cx, |project, cx| match kind { -// GotoDefinitionKind::Symbol => project.definition(&buffer, head, cx), -// GotoDefinitionKind::Type => project.type_definition(&buffer, head, cx), -// }); - -// cx.spawn_labeled("Fetching Definition...", |editor, mut cx| async move { -// let definitions = definitions.await?; -// editor.update(&mut cx, |editor, cx| { -// editor.navigate_to_definitions( -// definitions -// .into_iter() -// .map(GoToDefinitionLink::Text) -// .collect(), -// split, -// cx, -// ); -// })?; -// Ok::<(), anyhow::Error>(()) -// }) -// .detach_and_log_err(cx); -// } - -// pub fn navigate_to_definitions( -// &mut self, -// mut definitions: Vec, -// split: bool, -// cx: &mut ViewContext, -// ) { -// let Some(workspace) = self.workspace(cx) else { -// return; -// }; -// let pane = workspace.read(cx).active_pane().clone(); -// // If there is one definition, just open it directly -// if definitions.len() == 1 { -// let definition = definitions.pop().unwrap(); -// let target_task = match definition { -// GoToDefinitionLink::Text(link) => Task::Ready(Some(Ok(Some(link.target)))), -// GoToDefinitionLink::InlayHint(lsp_location, server_id) => { -// self.compute_target_location(lsp_location, server_id, cx) -// } -// }; -// cx.spawn(|editor, mut cx| async move { -// let target = target_task.await.context("target resolution task")?; -// if let Some(target) = target { -// editor.update(&mut cx, |editor, cx| { -// let range = target.range.to_offset(target.buffer.read(cx)); -// let range = editor.range_for_match(&range); -// if Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref() { -// editor.change_selections(Some(Autoscroll::fit()), cx, |s| { -// s.select_ranges([range]); -// }); -// } else { -// cx.window_context().defer(move |cx| { -// let target_editor: ViewHandle = -// workspace.update(cx, |workspace, cx| { -// if split { -// workspace.split_project_item(target.buffer.clone(), cx) -// } else { -// workspace.open_project_item(target.buffer.clone(), cx) -// } -// }); -// target_editor.update(cx, |target_editor, cx| { -// // When selecting a definition in a different buffer, disable the nav history -// // to avoid creating a history entry at the previous cursor location. -// pane.update(cx, |pane, _| pane.disable_history()); -// target_editor.change_selections( -// Some(Autoscroll::fit()), -// cx, -// |s| { -// s.select_ranges([range]); -// }, -// ); -// pane.update(cx, |pane, _| pane.enable_history()); -// }); -// }); -// } -// }) -// } else { -// Ok(()) -// } -// }) -// .detach_and_log_err(cx); -// } else if !definitions.is_empty() { -// let replica_id = self.replica_id(cx); -// cx.spawn(|editor, mut cx| async move { -// let (title, location_tasks) = editor -// .update(&mut cx, |editor, cx| { -// let title = definitions -// .iter() -// .find_map(|definition| match definition { -// GoToDefinitionLink::Text(link) => { -// link.origin.as_ref().map(|origin| { -// let buffer = origin.buffer.read(cx); -// format!( -// "Definitions for {}", -// buffer -// .text_for_range(origin.range.clone()) -// .collect::() -// ) -// }) -// } -// GoToDefinitionLink::InlayHint(_, _) => None, -// }) -// .unwrap_or("Definitions".to_string()); -// let location_tasks = definitions -// .into_iter() -// .map(|definition| match definition { -// GoToDefinitionLink::Text(link) => { -// Task::Ready(Some(Ok(Some(link.target)))) -// } -// GoToDefinitionLink::InlayHint(lsp_location, server_id) => { -// editor.compute_target_location(lsp_location, server_id, cx) -// } -// }) -// .collect::>(); -// (title, location_tasks) -// }) -// .context("location tasks preparation")?; - -// let locations = futures::future::join_all(location_tasks) -// .await -// .into_iter() -// .filter_map(|location| location.transpose()) -// .collect::>() -// .context("location tasks")?; -// workspace.update(&mut cx, |workspace, cx| { -// Self::open_locations_in_multibuffer( -// workspace, locations, replica_id, title, split, cx, -// ) -// }); - -// anyhow::Ok(()) -// }) -// .detach_and_log_err(cx); -// } -// } - -// fn compute_target_location( -// &self, -// lsp_location: lsp::Location, -// server_id: LanguageServerId, -// cx: &mut ViewContext, -// ) -> Task>> { -// let Some(project) = self.project.clone() else { -// return Task::Ready(Some(Ok(None))); -// }; - -// cx.spawn(move |editor, mut cx| async move { -// let location_task = editor.update(&mut cx, |editor, cx| { -// project.update(cx, |project, cx| { -// let language_server_name = -// editor.buffer.read(cx).as_singleton().and_then(|buffer| { -// project -// .language_server_for_buffer(buffer.read(cx), server_id, cx) -// .map(|(_, lsp_adapter)| { -// LanguageServerName(Arc::from(lsp_adapter.name())) -// }) -// }); -// language_server_name.map(|language_server_name| { -// project.open_local_buffer_via_lsp( -// lsp_location.uri.clone(), -// server_id, -// language_server_name, -// cx, -// ) -// }) -// }) -// })?; -// let location = match location_task { -// Some(task) => Some({ -// let target_buffer_handle = task.await.context("open local buffer")?; -// let range = { -// target_buffer_handle.update(&mut cx, |target_buffer, _| { -// let target_start = target_buffer.clip_point_utf16( -// point_from_lsp(lsp_location.range.start), -// Bias::Left, -// ); -// let target_end = target_buffer.clip_point_utf16( -// point_from_lsp(lsp_location.range.end), -// Bias::Left, -// ); -// target_buffer.anchor_after(target_start) -// ..target_buffer.anchor_before(target_end) -// }) -// }; -// Location { -// buffer: target_buffer_handle, -// range, -// } -// }), -// None => None, -// }; -// Ok(location) -// }) -// } - -// pub fn find_all_references( -// workspace: &mut Workspace, -// _: &FindAllReferences, -// cx: &mut ViewContext, -// ) -> Option>> { -// let active_item = workspace.active_item(cx)?; -// let editor_handle = active_item.act_as::(cx)?; - -// let editor = editor_handle.read(cx); -// let buffer = editor.buffer.read(cx); -// let head = editor.selections.newest::(cx).head(); -// let (buffer, head) = buffer.text_anchor_for_position(head, cx)?; -// let replica_id = editor.replica_id(cx); - -// let project = workspace.project().clone(); -// let references = project.update(cx, |project, cx| project.references(&buffer, head, cx)); -// Some(cx.spawn_labeled( -// "Finding All References...", -// |workspace, mut cx| async move { -// let locations = references.await?; -// if locations.is_empty() { -// return Ok(()); -// } - -// workspace.update(&mut cx, |workspace, cx| { -// let title = locations -// .first() -// .as_ref() -// .map(|location| { -// let buffer = location.buffer.read(cx); -// format!( -// "References to `{}`", -// buffer -// .text_for_range(location.range.clone()) -// .collect::() -// ) -// }) -// .unwrap(); -// Self::open_locations_in_multibuffer( -// workspace, locations, replica_id, title, false, cx, -// ); -// })?; - -// Ok(()) -// }, -// )) -// } - -// /// Opens a multibuffer with the given project locations in it -// pub fn open_locations_in_multibuffer( -// workspace: &mut Workspace, -// mut locations: Vec, -// replica_id: ReplicaId, -// title: String, -// split: bool, -// cx: &mut ViewContext, -// ) { -// // If there are multiple definitions, open them in a multibuffer -// locations.sort_by_key(|location| location.buffer.read(cx).remote_id()); -// let mut locations = locations.into_iter().peekable(); -// let mut ranges_to_highlight = Vec::new(); - -// let excerpt_buffer = cx.add_model(|cx| { -// let mut multibuffer = MultiBuffer::new(replica_id); -// while let Some(location) = locations.next() { -// let buffer = location.buffer.read(cx); -// let mut ranges_for_buffer = Vec::new(); -// let range = location.range.to_offset(buffer); -// ranges_for_buffer.push(range.clone()); - -// while let Some(next_location) = locations.peek() { -// if next_location.buffer == location.buffer { -// ranges_for_buffer.push(next_location.range.to_offset(buffer)); -// locations.next(); -// } else { -// break; -// } -// } - -// ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end))); -// ranges_to_highlight.extend(multibuffer.push_excerpts_with_context_lines( -// location.buffer.clone(), -// ranges_for_buffer, -// 1, -// cx, -// )) -// } - -// multibuffer.with_title(title) -// }); - -// let editor = cx.add_view(|cx| { -// Editor::for_multibuffer(excerpt_buffer, Some(workspace.project().clone()), cx) -// }); -// editor.update(cx, |editor, cx| { -// editor.highlight_background::( -// ranges_to_highlight, -// |theme| theme.editor.highlighted_line_background, -// cx, -// ); -// }); -// if split { -// workspace.split_item(SplitDirection::Right, Box::new(editor), cx); -// } else { -// workspace.add_item(Box::new(editor), cx); -// } -// } - -// pub fn rename(&mut self, _: &Rename, cx: &mut ViewContext) -> Option>> { -// use language::ToOffset as _; - -// let project = self.project.clone()?; -// let selection = self.selections.newest_anchor().clone(); -// let (cursor_buffer, cursor_buffer_position) = self -// .buffer -// .read(cx) -// .text_anchor_for_position(selection.head(), cx)?; -// let (tail_buffer, _) = self -// .buffer -// .read(cx) -// .text_anchor_for_position(selection.tail(), cx)?; -// if tail_buffer != cursor_buffer { -// return None; -// } - -// let snapshot = cursor_buffer.read(cx).snapshot(); -// let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot); -// let prepare_rename = project.update(cx, |project, cx| { -// project.prepare_rename(cursor_buffer, cursor_buffer_offset, cx) -// }); - -// Some(cx.spawn(|this, mut cx| async move { -// let rename_range = if let Some(range) = prepare_rename.await? { -// Some(range) -// } else { -// this.update(&mut cx, |this, cx| { -// let buffer = this.buffer.read(cx).snapshot(cx); -// let mut buffer_highlights = this -// .document_highlights_for_position(selection.head(), &buffer) -// .filter(|highlight| { -// highlight.start.excerpt_id == selection.head().excerpt_id -// && highlight.end.excerpt_id == selection.head().excerpt_id -// }); -// buffer_highlights -// .next() -// .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor) -// })? -// }; -// if let Some(rename_range) = rename_range { -// let rename_buffer_range = rename_range.to_offset(&snapshot); -// let cursor_offset_in_rename_range = -// cursor_buffer_offset.saturating_sub(rename_buffer_range.start); - -// this.update(&mut cx, |this, cx| { -// this.take_rename(false, cx); -// let style = this.style(cx); -// let buffer = this.buffer.read(cx).read(cx); -// let cursor_offset = selection.head().to_offset(&buffer); -// let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range); -// let rename_end = rename_start + rename_buffer_range.len(); -// let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end); -// let mut old_highlight_id = None; -// let old_name: Arc = buffer -// .chunks(rename_start..rename_end, true) -// .map(|chunk| { -// if old_highlight_id.is_none() { -// old_highlight_id = chunk.syntax_highlight_id; -// } -// chunk.text -// }) -// .collect::() -// .into(); - -// drop(buffer); - -// // Position the selection in the rename editor so that it matches the current selection. -// this.show_local_selections = false; -// let rename_editor = cx.add_view(|cx| { -// let mut editor = Editor::single_line(None, cx); -// if let Some(old_highlight_id) = old_highlight_id { -// editor.override_text_style = -// Some(Box::new(move |style| old_highlight_id.style(&style.syntax))); -// } -// editor.buffer.update(cx, |buffer, cx| { -// buffer.edit([(0..0, old_name.clone())], None, cx) -// }); -// editor.select_all(&SelectAll, cx); -// editor -// }); - -// let ranges = this -// .clear_background_highlights::(cx) -// .into_iter() -// .flat_map(|(_, ranges)| ranges.into_iter()) -// .chain( -// this.clear_background_highlights::(cx) -// .into_iter() -// .flat_map(|(_, ranges)| ranges.into_iter()), -// ) -// .collect(); - -// this.highlight_text::( -// ranges, -// HighlightStyle { -// fade_out: Some(style.rename_fade), -// ..Default::default() -// }, -// cx, -// ); -// cx.focus(&rename_editor); -// let block_id = this.insert_blocks( -// [BlockProperties { -// style: BlockStyle::Flex, -// position: range.start.clone(), -// height: 1, -// render: Arc::new({ -// let editor = rename_editor.clone(); -// move |cx: &mut BlockContext| { -// ChildView::new(&editor, cx) -// .contained() -// .with_padding_left(cx.anchor_x) -// .into_any() -// } -// }), -// disposition: BlockDisposition::Below, -// }], -// Some(Autoscroll::fit()), -// cx, -// )[0]; -// this.pending_rename = Some(RenameState { -// range, -// old_name, -// editor: rename_editor, -// block_id, -// }); -// })?; -// } - -// Ok(()) -// })) -// } - -// pub fn confirm_rename( -// workspace: &mut Workspace, -// _: &ConfirmRename, -// cx: &mut ViewContext, -// ) -> Option>> { -// let editor = workspace.active_item(cx)?.act_as::(cx)?; - -// let (buffer, range, old_name, new_name) = editor.update(cx, |editor, cx| { -// let rename = editor.take_rename(false, cx)?; -// let buffer = editor.buffer.read(cx); -// let (start_buffer, start) = -// buffer.text_anchor_for_position(rename.range.start.clone(), cx)?; -// let (end_buffer, end) = -// buffer.text_anchor_for_position(rename.range.end.clone(), cx)?; -// if start_buffer == end_buffer { -// let new_name = rename.editor.read(cx).text(cx); -// Some((start_buffer, start..end, rename.old_name, new_name)) -// } else { -// None -// } -// })?; - -// let rename = workspace.project().clone().update(cx, |project, cx| { -// project.perform_rename(buffer.clone(), range.start, new_name.clone(), true, cx) -// }); - -// let editor = editor.downgrade(); -// Some(cx.spawn(|workspace, mut cx| async move { -// let project_transaction = rename.await?; -// Self::open_project_transaction( -// &editor, -// workspace, -// project_transaction, -// format!("Rename: {} → {}", old_name, new_name), -// cx.clone(), -// ) -// .await?; - -// editor.update(&mut cx, |editor, cx| { -// editor.refresh_document_highlights(cx); -// })?; -// Ok(()) -// })) -// } - -// fn take_rename( -// &mut self, -// moving_cursor: bool, -// cx: &mut ViewContext, -// ) -> Option { -// let rename = self.pending_rename.take()?; -// self.remove_blocks( -// [rename.block_id].into_iter().collect(), -// Some(Autoscroll::fit()), -// cx, -// ); -// self.clear_highlights::(cx); -// self.show_local_selections = true; - -// if moving_cursor { -// let rename_editor = rename.editor.read(cx); -// let cursor_in_rename_editor = rename_editor.selections.newest::(cx).head(); - -// // Update the selection to match the position of the selection inside -// // the rename editor. -// let snapshot = self.buffer.read(cx).read(cx); -// let rename_range = rename.range.to_offset(&snapshot); -// let cursor_in_editor = snapshot -// .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left) -// .min(rename_range.end); -// drop(snapshot); - -// self.change_selections(None, cx, |s| { -// s.select_ranges(vec![cursor_in_editor..cursor_in_editor]) -// }); -// } else { -// self.refresh_document_highlights(cx); -// } - -// Some(rename) -// } - -// #[cfg(any(test, feature = "test-support"))] -// pub fn pending_rename(&self) -> Option<&RenameState> { -// self.pending_rename.as_ref() -// } - -// fn format(&mut self, _: &Format, cx: &mut ViewContext) -> Option>> { -// let project = match &self.project { -// Some(project) => project.clone(), -// None => return None, -// }; - -// Some(self.perform_format(project, FormatTrigger::Manual, cx)) -// } - -// fn perform_format( -// &mut self, -// project: Model, -// trigger: FormatTrigger, -// cx: &mut ViewContext, -// ) -> Task> { -// let buffer = self.buffer().clone(); -// let buffers = buffer.read(cx).all_buffers(); - -// let mut timeout = cx.background().timer(FORMAT_TIMEOUT).fuse(); -// let format = project.update(cx, |project, cx| project.format(buffers, true, trigger, cx)); - -// cx.spawn(|_, mut cx| async move { -// let transaction = futures::select_biased! { -// _ = timeout => { -// log::warn!("timed out waiting for formatting"); -// None -// } -// transaction = format.log_err().fuse() => transaction, -// }; - -// buffer.update(&mut cx, |buffer, cx| { -// if let Some(transaction) = transaction { -// if !buffer.is_singleton() { -// buffer.push_transaction(&transaction.0, cx); -// } -// } - -// cx.notify(); -// }); - -// Ok(()) -// }) -// } - -// fn restart_language_server(&mut self, _: &RestartLanguageServer, cx: &mut ViewContext) { -// if let Some(project) = self.project.clone() { -// self.buffer.update(cx, |multi_buffer, cx| { -// project.update(cx, |project, cx| { -// project.restart_language_servers_for_buffers(multi_buffer.all_buffers(), cx); -// }); -// }) -// } -// } - -// fn show_character_palette(&mut self, _: &ShowCharacterPalette, cx: &mut ViewContext) { -// cx.show_character_palette(); -// } - -// fn refresh_active_diagnostics(&mut self, cx: &mut ViewContext) { -// if let Some(active_diagnostics) = self.active_diagnostics.as_mut() { -// let buffer = self.buffer.read(cx).snapshot(cx); -// let primary_range_start = active_diagnostics.primary_range.start.to_offset(&buffer); -// let is_valid = buffer -// .diagnostics_in_range::<_, usize>(active_diagnostics.primary_range.clone(), false) -// .any(|entry| { -// entry.diagnostic.is_primary -// && !entry.range.is_empty() -// && entry.range.start == primary_range_start -// && entry.diagnostic.message == active_diagnostics.primary_message -// }); - -// if is_valid != active_diagnostics.is_valid { -// active_diagnostics.is_valid = is_valid; -// let mut new_styles = HashMap::default(); -// for (block_id, diagnostic) in &active_diagnostics.blocks { -// new_styles.insert( -// *block_id, -// diagnostic_block_renderer(diagnostic.clone(), is_valid), -// ); -// } -// self.display_map -// .update(cx, |display_map, _| display_map.replace_blocks(new_styles)); -// } -// } -// } - -// fn activate_diagnostics(&mut self, group_id: usize, cx: &mut ViewContext) -> bool { -// self.dismiss_diagnostics(cx); -// self.active_diagnostics = self.display_map.update(cx, |display_map, cx| { -// let buffer = self.buffer.read(cx).snapshot(cx); - -// let mut primary_range = None; -// let mut primary_message = None; -// let mut group_end = Point::zero(); -// let diagnostic_group = buffer -// .diagnostic_group::(group_id) -// .map(|entry| { -// if entry.range.end > group_end { -// group_end = entry.range.end; -// } -// if entry.diagnostic.is_primary { -// primary_range = Some(entry.range.clone()); -// primary_message = Some(entry.diagnostic.message.clone()); -// } -// entry -// }) -// .collect::>(); -// let primary_range = primary_range?; -// let primary_message = primary_message?; -// let primary_range = -// buffer.anchor_after(primary_range.start)..buffer.anchor_before(primary_range.end); - -// let blocks = display_map -// .insert_blocks( -// diagnostic_group.iter().map(|entry| { -// let diagnostic = entry.diagnostic.clone(); -// let message_height = diagnostic.message.lines().count() as u8; -// BlockProperties { -// style: BlockStyle::Fixed, -// position: buffer.anchor_after(entry.range.start), -// height: message_height, -// render: diagnostic_block_renderer(diagnostic, true), -// disposition: BlockDisposition::Below, -// } -// }), -// cx, -// ) -// .into_iter() -// .zip(diagnostic_group.into_iter().map(|entry| entry.diagnostic)) -// .collect(); - -// Some(ActiveDiagnosticGroup { -// primary_range, -// primary_message, -// blocks, -// is_valid: true, -// }) -// }); -// self.active_diagnostics.is_some() -// } - -// fn dismiss_diagnostics(&mut self, cx: &mut ViewContext) { -// if let Some(active_diagnostic_group) = self.active_diagnostics.take() { -// self.display_map.update(cx, |display_map, cx| { -// display_map.remove_blocks(active_diagnostic_group.blocks.into_keys().collect(), cx); -// }); -// cx.notify(); -// } -// } - -// pub fn set_selections_from_remote( -// &mut self, -// selections: Vec>, -// pending_selection: Option>, -// cx: &mut ViewContext, -// ) { -// let old_cursor_position = self.selections.newest_anchor().head(); -// self.selections.change_with(cx, |s| { -// s.select_anchors(selections); -// if let Some(pending_selection) = pending_selection { -// s.set_pending(pending_selection, SelectMode::Character); -// } else { -// s.clear_pending(); -// } -// }); -// self.selections_did_change(false, &old_cursor_position, cx); -// } - -// fn push_to_selection_history(&mut self) { -// self.selection_history.push(SelectionHistoryEntry { -// selections: self.selections.disjoint_anchors(), -// select_next_state: self.select_next_state.clone(), -// select_prev_state: self.select_prev_state.clone(), -// add_selections_state: self.add_selections_state.clone(), -// }); -// } - -// pub fn transact( -// &mut self, -// cx: &mut ViewContext, -// update: impl FnOnce(&mut Self, &mut ViewContext), -// ) -> Option { -// self.start_transaction_at(Instant::now(), cx); -// update(self, cx); -// self.end_transaction_at(Instant::now(), cx) -// } - -// fn start_transaction_at(&mut self, now: Instant, cx: &mut ViewContext) { -// self.end_selection(cx); -// if let Some(tx_id) = self -// .buffer -// .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx)) -// { -// self.selection_history -// .insert_transaction(tx_id, self.selections.disjoint_anchors()); -// } -// } - -// fn end_transaction_at( -// &mut self, -// now: Instant, -// cx: &mut ViewContext, -// ) -> Option { -// if let Some(tx_id) = self -// .buffer -// .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx)) -// { -// if let Some((_, end_selections)) = self.selection_history.transaction_mut(tx_id) { -// *end_selections = Some(self.selections.disjoint_anchors()); -// } else { -// error!("unexpectedly ended a transaction that wasn't started by this editor"); -// } - -// cx.emit(Event::Edited); -// Some(tx_id) -// } else { -// None -// } -// } - -// pub fn fold(&mut self, _: &Fold, cx: &mut ViewContext) { -// let mut fold_ranges = Vec::new(); - -// let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); - -// let selections = self.selections.all_adjusted(cx); -// for selection in selections { -// let range = selection.range().sorted(); -// let buffer_start_row = range.start.row; - -// for row in (0..=range.end.row).rev() { -// let fold_range = display_map.foldable_range(row); - -// if let Some(fold_range) = fold_range { -// if fold_range.end.row >= buffer_start_row { -// fold_ranges.push(fold_range); -// if row <= range.start.row { -// break; -// } -// } -// } -// } -// } - -// self.fold_ranges(fold_ranges, true, cx); -// } - -// pub fn fold_at(&mut self, fold_at: &FoldAt, cx: &mut ViewContext) { -// let buffer_row = fold_at.buffer_row; -// let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); - -// if let Some(fold_range) = display_map.foldable_range(buffer_row) { -// let autoscroll = self -// .selections -// .all::(cx) -// .iter() -// .any(|selection| fold_range.overlaps(&selection.range())); - -// self.fold_ranges(std::iter::once(fold_range), autoscroll, cx); -// } -// } - -// pub fn unfold_lines(&mut self, _: &UnfoldLines, cx: &mut ViewContext) { -// let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); -// let buffer = &display_map.buffer_snapshot; -// let selections = self.selections.all::(cx); -// let ranges = selections -// .iter() -// .map(|s| { -// let range = s.display_range(&display_map).sorted(); -// let mut start = range.start.to_point(&display_map); -// let mut end = range.end.to_point(&display_map); -// start.column = 0; -// end.column = buffer.line_len(end.row); -// start..end -// }) -// .collect::>(); - -// self.unfold_ranges(ranges, true, true, cx); -// } - -// pub fn unfold_at(&mut self, unfold_at: &UnfoldAt, cx: &mut ViewContext) { -// let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); - -// let intersection_range = Point::new(unfold_at.buffer_row, 0) -// ..Point::new( -// unfold_at.buffer_row, -// display_map.buffer_snapshot.line_len(unfold_at.buffer_row), -// ); - -// let autoscroll = self -// .selections -// .all::(cx) -// .iter() -// .any(|selection| selection.range().overlaps(&intersection_range)); - -// self.unfold_ranges(std::iter::once(intersection_range), true, autoscroll, cx) -// } - -// pub fn fold_selected_ranges(&mut self, _: &FoldSelectedRanges, cx: &mut ViewContext) { -// let selections = self.selections.all::(cx); -// let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); -// let line_mode = self.selections.line_mode; -// let ranges = selections.into_iter().map(|s| { -// if line_mode { -// let start = Point::new(s.start.row, 0); -// let end = Point::new(s.end.row, display_map.buffer_snapshot.line_len(s.end.row)); -// start..end -// } else { -// s.start..s.end -// } -// }); -// self.fold_ranges(ranges, true, cx); -// } - -// pub fn fold_ranges( -// &mut self, -// ranges: impl IntoIterator>, -// auto_scroll: bool, -// cx: &mut ViewContext, -// ) { -// let mut ranges = ranges.into_iter().peekable(); -// if ranges.peek().is_some() { -// self.display_map.update(cx, |map, cx| map.fold(ranges, cx)); - -// if auto_scroll { -// self.request_autoscroll(Autoscroll::fit(), cx); -// } - -// cx.notify(); -// } -// } - -// pub fn unfold_ranges( -// &mut self, -// ranges: impl IntoIterator>, -// inclusive: bool, -// auto_scroll: bool, -// cx: &mut ViewContext, -// ) { -// let mut ranges = ranges.into_iter().peekable(); -// if ranges.peek().is_some() { -// self.display_map -// .update(cx, |map, cx| map.unfold(ranges, inclusive, cx)); -// if auto_scroll { -// self.request_autoscroll(Autoscroll::fit(), cx); -// } - -// cx.notify(); -// } -// } - -// pub fn gutter_hover( -// &mut self, -// GutterHover { hovered }: &GutterHover, -// cx: &mut ViewContext, -// ) { -// self.gutter_hovered = *hovered; -// cx.notify(); -// } - -// pub fn insert_blocks( -// &mut self, -// blocks: impl IntoIterator>, -// autoscroll: Option, -// cx: &mut ViewContext, -// ) -> Vec { -// let blocks = self -// .display_map -// .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx)); -// if let Some(autoscroll) = autoscroll { -// self.request_autoscroll(autoscroll, cx); -// } -// blocks -// } - -// pub fn replace_blocks( -// &mut self, -// blocks: HashMap, -// autoscroll: Option, -// cx: &mut ViewContext, -// ) { -// self.display_map -// .update(cx, |display_map, _| display_map.replace_blocks(blocks)); -// if let Some(autoscroll) = autoscroll { -// self.request_autoscroll(autoscroll, cx); -// } -// } - -// pub fn remove_blocks( -// &mut self, -// block_ids: HashSet, -// autoscroll: Option, -// cx: &mut ViewContext, -// ) { -// self.display_map.update(cx, |display_map, cx| { -// display_map.remove_blocks(block_ids, cx) -// }); -// if let Some(autoscroll) = autoscroll { -// self.request_autoscroll(autoscroll, cx); -// } -// } - -// pub fn longest_row(&self, cx: &mut AppContext) -> u32 { -// self.display_map -// .update(cx, |map, cx| map.snapshot(cx)) -// .longest_row() -// } - -// pub fn max_point(&self, cx: &mut AppContext) -> DisplayPoint { -// self.display_map -// .update(cx, |map, cx| map.snapshot(cx)) -// .max_point() -// } - -// pub fn text(&self, cx: &AppContext) -> String { -// self.buffer.read(cx).read(cx).text() -// } - -// pub fn set_text(&mut self, text: impl Into>, cx: &mut ViewContext) { -// self.transact(cx, |this, cx| { -// this.buffer -// .read(cx) -// .as_singleton() -// .expect("you can only call set_text on editors for singleton buffers") -// .update(cx, |buffer, cx| buffer.set_text(text, cx)); -// }); -// } - -// pub fn display_text(&self, cx: &mut AppContext) -> String { -// self.display_map -// .update(cx, |map, cx| map.snapshot(cx)) -// .text() -// } - -// pub fn wrap_guides(&self, cx: &AppContext) -> SmallVec<[(usize, bool); 2]> { -// let mut wrap_guides = smallvec::smallvec![]; - -// if self.show_wrap_guides == Some(false) { -// return wrap_guides; -// } - -// let settings = self.buffer.read(cx).settings_at(0, cx); -// if settings.show_wrap_guides { -// if let SoftWrap::Column(soft_wrap) = self.soft_wrap_mode(cx) { -// wrap_guides.push((soft_wrap as usize, true)); -// } -// wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false))) -// } - -// wrap_guides -// } - -// pub fn soft_wrap_mode(&self, cx: &AppContext) -> SoftWrap { -// let settings = self.buffer.read(cx).settings_at(0, cx); -// let mode = self -// .soft_wrap_mode_override -// .unwrap_or_else(|| settings.soft_wrap); -// match mode { -// language_settings::SoftWrap::None => SoftWrap::None, -// language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth, -// language_settings::SoftWrap::PreferredLineLength => { -// SoftWrap::Column(settings.preferred_line_length) -// } -// } -// } - -// pub fn set_soft_wrap_mode( -// &mut self, -// mode: language_settings::SoftWrap, -// cx: &mut ViewContext, -// ) { -// self.soft_wrap_mode_override = Some(mode); -// cx.notify(); -// } - -// pub fn set_wrap_width(&self, width: Option, cx: &mut AppContext) -> bool { -// self.display_map -// .update(cx, |map, cx| map.set_wrap_width(width, cx)) -// } - -// pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, cx: &mut ViewContext) { -// if self.soft_wrap_mode_override.is_some() { -// self.soft_wrap_mode_override.take(); -// } else { -// let soft_wrap = match self.soft_wrap_mode(cx) { -// SoftWrap::None => language_settings::SoftWrap::EditorWidth, -// SoftWrap::EditorWidth | SoftWrap::Column(_) => language_settings::SoftWrap::None, -// }; -// self.soft_wrap_mode_override = Some(soft_wrap); -// } -// cx.notify(); -// } - -// pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut ViewContext) { -// self.show_gutter = show_gutter; -// cx.notify(); -// } - -// pub fn set_show_wrap_guides(&mut self, show_gutter: bool, cx: &mut ViewContext) { -// self.show_wrap_guides = Some(show_gutter); -// cx.notify(); -// } - -// pub fn reveal_in_finder(&mut self, _: &RevealInFinder, cx: &mut ViewContext) { -// if let Some(buffer) = self.buffer().read(cx).as_singleton() { -// if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) { -// cx.reveal_path(&file.abs_path(cx)); -// } -// } -// } - -// pub fn copy_path(&mut self, _: &CopyPath, cx: &mut ViewContext) { -// if let Some(buffer) = self.buffer().read(cx).as_singleton() { -// if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) { -// if let Some(path) = file.abs_path(cx).to_str() { -// cx.write_to_clipboard(ClipboardItem::new(path.to_string())); -// } -// } -// } -// } - -// pub fn copy_relative_path(&mut self, _: &CopyRelativePath, cx: &mut ViewContext) { -// if let Some(buffer) = self.buffer().read(cx).as_singleton() { -// if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) { -// if let Some(path) = file.path().to_str() { -// cx.write_to_clipboard(ClipboardItem::new(path.to_string())); -// } -// } -// } -// } - -// pub fn highlight_rows(&mut self, rows: Option>) { -// self.highlighted_rows = rows; -// } - -// pub fn highlighted_rows(&self) -> Option> { -// self.highlighted_rows.clone() -// } - -// pub fn highlight_background( -// &mut self, -// ranges: Vec>, -// color_fetcher: fn(&Theme) -> Color, -// cx: &mut ViewContext, -// ) { -// self.background_highlights -// .insert(TypeId::of::(), (color_fetcher, ranges)); -// cx.notify(); -// } - -// pub fn highlight_inlay_background( -// &mut self, -// ranges: Vec, -// color_fetcher: fn(&Theme) -> Color, -// cx: &mut ViewContext, -// ) { -// // TODO: no actual highlights happen for inlays currently, find a way to do that -// self.inlay_background_highlights -// .insert(Some(TypeId::of::()), (color_fetcher, ranges)); -// cx.notify(); -// } - -// pub fn clear_background_highlights( -// &mut self, -// cx: &mut ViewContext, -// ) -> Option { -// let text_highlights = self.background_highlights.remove(&TypeId::of::()); -// let inlay_highlights = self -// .inlay_background_highlights -// .remove(&Some(TypeId::of::())); -// if text_highlights.is_some() || inlay_highlights.is_some() { -// cx.notify(); -// } -// text_highlights -// } - -// #[cfg(feature = "test-support")] -// pub fn all_text_background_highlights( -// &mut self, -// cx: &mut ViewContext, -// ) -> Vec<(Range, Color)> { -// let snapshot = self.snapshot(cx); -// let buffer = &snapshot.buffer_snapshot; -// let start = buffer.anchor_before(0); -// let end = buffer.anchor_after(buffer.len()); -// let theme = theme::current(cx); -// self.background_highlights_in_range(start..end, &snapshot, theme.as_ref()) -// } - -// fn document_highlights_for_position<'a>( -// &'a self, -// position: Anchor, -// buffer: &'a MultiBufferSnapshot, -// ) -> impl 'a + Iterator> { -// let read_highlights = self -// .background_highlights -// .get(&TypeId::of::()) -// .map(|h| &h.1); -// let write_highlights = self -// .background_highlights -// .get(&TypeId::of::()) -// .map(|h| &h.1); -// let left_position = position.bias_left(buffer); -// let right_position = position.bias_right(buffer); -// read_highlights -// .into_iter() -// .chain(write_highlights) -// .flat_map(move |ranges| { -// let start_ix = match ranges.binary_search_by(|probe| { -// let cmp = probe.end.cmp(&left_position, buffer); -// if cmp.is_ge() { -// Ordering::Greater -// } else { -// Ordering::Less -// } -// }) { -// Ok(i) | Err(i) => i, -// }; - -// let right_position = right_position.clone(); -// ranges[start_ix..] -// .iter() -// .take_while(move |range| range.start.cmp(&right_position, buffer).is_le()) -// }) -// } - -// pub fn background_highlights_in_range( -// &self, -// search_range: Range, -// display_snapshot: &DisplaySnapshot, -// theme: &Theme, -// ) -> Vec<(Range, Color)> { -// let mut results = Vec::new(); -// for (color_fetcher, ranges) in self.background_highlights.values() { -// let color = color_fetcher(theme); -// let start_ix = match ranges.binary_search_by(|probe| { -// let cmp = probe -// .end -// .cmp(&search_range.start, &display_snapshot.buffer_snapshot); -// if cmp.is_gt() { -// Ordering::Greater -// } else { -// Ordering::Less -// } -// }) { -// Ok(i) | Err(i) => i, -// }; -// for range in &ranges[start_ix..] { -// if range -// .start -// .cmp(&search_range.end, &display_snapshot.buffer_snapshot) -// .is_ge() -// { -// break; -// } - -// let start = range.start.to_display_point(&display_snapshot); -// let end = range.end.to_display_point(&display_snapshot); -// results.push((start..end, color)) -// } -// } -// results -// } - -// pub fn background_highlight_row_ranges( -// &self, -// search_range: Range, -// display_snapshot: &DisplaySnapshot, -// count: usize, -// ) -> Vec> { -// let mut results = Vec::new(); -// let Some((_, ranges)) = self.background_highlights.get(&TypeId::of::()) else { -// return vec![]; -// }; - -// let start_ix = match ranges.binary_search_by(|probe| { -// let cmp = probe -// .end -// .cmp(&search_range.start, &display_snapshot.buffer_snapshot); -// if cmp.is_gt() { -// Ordering::Greater -// } else { -// Ordering::Less -// } -// }) { -// Ok(i) | Err(i) => i, -// }; -// let mut push_region = |start: Option, end: Option| { -// if let (Some(start_display), Some(end_display)) = (start, end) { -// results.push( -// start_display.to_display_point(display_snapshot) -// ..=end_display.to_display_point(display_snapshot), -// ); -// } -// }; -// let mut start_row: Option = None; -// let mut end_row: Option = None; -// if ranges.len() > count { -// return Vec::new(); -// } -// for range in &ranges[start_ix..] { -// if range -// .start -// .cmp(&search_range.end, &display_snapshot.buffer_snapshot) -// .is_ge() -// { -// break; -// } -// let end = range.end.to_point(&display_snapshot.buffer_snapshot); -// if let Some(current_row) = &end_row { -// if end.row == current_row.row { -// continue; -// } -// } -// let start = range.start.to_point(&display_snapshot.buffer_snapshot); -// if start_row.is_none() { -// assert_eq!(end_row, None); -// start_row = Some(start); -// end_row = Some(end); -// continue; -// } -// if let Some(current_end) = end_row.as_mut() { -// if start.row > current_end.row + 1 { -// push_region(start_row, end_row); -// start_row = Some(start); -// end_row = Some(end); -// } else { -// // Merge two hunks. -// *current_end = end; -// } -// } else { -// unreachable!(); -// } -// } -// // We might still have a hunk that was not rendered (if there was a search hit on the last line) -// push_region(start_row, end_row); -// results -// } - -// pub fn highlight_text( -// &mut self, -// ranges: Vec>, -// style: HighlightStyle, -// cx: &mut ViewContext, -// ) { -// self.display_map.update(cx, |map, _| { -// map.highlight_text(TypeId::of::(), ranges, style) -// }); -// cx.notify(); -// } - -// pub fn highlight_inlays( -// &mut self, -// highlights: Vec, -// style: HighlightStyle, -// cx: &mut ViewContext, -// ) { -// self.display_map.update(cx, |map, _| { -// map.highlight_inlays(TypeId::of::(), highlights, style) -// }); -// cx.notify(); -// } - -// pub fn text_highlights<'a, T: 'static>( -// &'a self, -// cx: &'a AppContext, -// ) -> Option<(HighlightStyle, &'a [Range])> { -// self.display_map.read(cx).text_highlights(TypeId::of::()) -// } - -// pub fn clear_highlights(&mut self, cx: &mut ViewContext) { -// let cleared = self -// .display_map -// .update(cx, |map, _| map.clear_highlights(TypeId::of::())); -// if cleared { -// cx.notify(); -// } -// } - -// pub fn show_local_cursors(&self, cx: &AppContext) -> bool { -// self.blink_manager.read(cx).visible() && self.focused -// } - -// fn on_buffer_changed(&mut self, _: Model, cx: &mut ViewContext) { -// cx.notify(); -// } - -// fn on_buffer_event( -// &mut self, -// multibuffer: Model, -// event: &multi_buffer::Event, -// cx: &mut ViewContext, -// ) { -// match event { -// multi_buffer::Event::Edited { -// sigleton_buffer_edited, -// } => { -// self.refresh_active_diagnostics(cx); -// self.refresh_code_actions(cx); -// if self.has_active_copilot_suggestion(cx) { -// self.update_visible_copilot_suggestion(cx); -// } -// cx.emit(Event::BufferEdited); - -// if *sigleton_buffer_edited { -// if let Some(project) = &self.project { -// let project = project.read(cx); -// let languages_affected = multibuffer -// .read(cx) -// .all_buffers() -// .into_iter() -// .filter_map(|buffer| { -// let buffer = buffer.read(cx); -// let language = buffer.language()?; -// if project.is_local() -// && project.language_servers_for_buffer(buffer, cx).count() == 0 -// { -// None -// } else { -// Some(language) -// } -// }) -// .cloned() -// .collect::>(); -// if !languages_affected.is_empty() { -// self.refresh_inlay_hints( -// InlayHintRefreshReason::BufferEdited(languages_affected), -// cx, -// ); -// } -// } -// } -// } -// multi_buffer::Event::ExcerptsAdded { -// buffer, -// predecessor, -// excerpts, -// } => { -// cx.emit(Event::ExcerptsAdded { -// buffer: buffer.clone(), -// predecessor: *predecessor, -// excerpts: excerpts.clone(), -// }); -// self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx); -// } -// multi_buffer::Event::ExcerptsRemoved { ids } => { -// self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx); -// cx.emit(Event::ExcerptsRemoved { ids: ids.clone() }) -// } -// multi_buffer::Event::Reparsed => cx.emit(Event::Reparsed), -// multi_buffer::Event::DirtyChanged => cx.emit(Event::DirtyChanged), -// multi_buffer::Event::Saved => cx.emit(Event::Saved), -// multi_buffer::Event::FileHandleChanged => cx.emit(Event::TitleChanged), -// multi_buffer::Event::Reloaded => cx.emit(Event::TitleChanged), -// multi_buffer::Event::DiffBaseChanged => cx.emit(Event::DiffBaseChanged), -// multi_buffer::Event::Closed => cx.emit(Event::Closed), -// multi_buffer::Event::DiagnosticsUpdated => { -// self.refresh_active_diagnostics(cx); -// } -// _ => {} -// }; -// } - -// fn on_display_map_changed(&mut self, _: Model, cx: &mut ViewContext) { -// cx.notify(); -// } - -// fn settings_changed(&mut self, cx: &mut ViewContext) { -// self.refresh_copilot_suggestions(true, cx); -// self.refresh_inlay_hints( -// InlayHintRefreshReason::SettingsChange(inlay_hint_settings( -// self.selections.newest_anchor().head(), -// &self.buffer.read(cx).snapshot(cx), -// cx, -// )), -// cx, -// ); -// } - -// pub fn set_searchable(&mut self, searchable: bool) { -// self.searchable = searchable; -// } - -// pub fn searchable(&self) -> bool { -// self.searchable -// } - -// fn open_excerpts(workspace: &mut Workspace, _: &OpenExcerpts, cx: &mut ViewContext) { -// let active_item = workspace.active_item(cx); -// let editor_handle = if let Some(editor) = active_item -// .as_ref() -// .and_then(|item| item.act_as::(cx)) -// { -// editor -// } else { -// cx.propagate_action(); -// return; -// }; - -// let editor = editor_handle.read(cx); -// let buffer = editor.buffer.read(cx); -// if buffer.is_singleton() { -// cx.propagate_action(); -// return; -// } - -// let mut new_selections_by_buffer = HashMap::default(); -// for selection in editor.selections.all::(cx) { -// for (buffer, mut range, _) in -// buffer.range_to_buffer_ranges(selection.start..selection.end, cx) -// { -// if selection.reversed { -// mem::swap(&mut range.start, &mut range.end); -// } -// new_selections_by_buffer -// .entry(buffer) -// .or_insert(Vec::new()) -// .push(range) -// } -// } - -// editor_handle.update(cx, |editor, cx| { -// editor.push_to_nav_history(editor.selections.newest_anchor().head(), None, cx); -// }); -// let pane = workspace.active_pane().clone(); -// pane.update(cx, |pane, _| pane.disable_history()); - -// // We defer the pane interaction because we ourselves are a workspace item -// // and activating a new item causes the pane to call a method on us reentrantly, -// // which panics if we're on the stack. -// cx.defer(move |workspace, cx| { -// for (buffer, ranges) in new_selections_by_buffer.into_iter() { -// let editor = workspace.open_project_item::(buffer, cx); -// editor.update(cx, |editor, cx| { -// editor.change_selections(Some(Autoscroll::newest()), cx, |s| { -// s.select_ranges(ranges); -// }); -// }); -// } - -// pane.update(cx, |pane, _| pane.enable_history()); -// }); -// } - -// fn jump( -// workspace: &mut Workspace, -// path: ProjectPath, -// position: Point, -// anchor: language::Anchor, -// cx: &mut ViewContext, -// ) { -// let editor = workspace.open_path(path, None, true, cx); -// cx.spawn(|_, mut cx| async move { -// let editor = editor -// .await? -// .downcast::() -// .ok_or_else(|| anyhow!("opened item was not an editor"))? -// .downgrade(); -// editor.update(&mut cx, |editor, cx| { -// let buffer = editor -// .buffer() -// .read(cx) -// .as_singleton() -// .ok_or_else(|| anyhow!("cannot jump in a multi-buffer"))?; -// let buffer = buffer.read(cx); -// let cursor = if buffer.can_resolve(&anchor) { -// language::ToPoint::to_point(&anchor, buffer) -// } else { -// buffer.clip_point(position, Bias::Left) -// }; - -// let nav_history = editor.nav_history.take(); -// editor.change_selections(Some(Autoscroll::newest()), cx, |s| { -// s.select_ranges([cursor..cursor]); -// }); -// editor.nav_history = nav_history; - -// anyhow::Ok(()) -// })??; - -// anyhow::Ok(()) -// }) -// .detach_and_log_err(cx); -// } - -// fn marked_text_ranges(&self, cx: &AppContext) -> Option>> { -// let snapshot = self.buffer.read(cx).read(cx); -// let (_, ranges) = self.text_highlights::(cx)?; -// Some( -// ranges -// .iter() -// .map(move |range| { -// range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot) -// }) -// .collect(), -// ) -// } - -// fn selection_replacement_ranges( -// &self, -// range: Range, -// cx: &AppContext, -// ) -> Vec> { -// let selections = self.selections.all::(cx); -// let newest_selection = selections -// .iter() -// .max_by_key(|selection| selection.id) -// .unwrap(); -// let start_delta = range.start.0 as isize - newest_selection.start.0 as isize; -// let end_delta = range.end.0 as isize - newest_selection.end.0 as isize; -// let snapshot = self.buffer.read(cx).read(cx); -// selections -// .into_iter() -// .map(|mut selection| { -// selection.start.0 = -// (selection.start.0 as isize).saturating_add(start_delta) as usize; -// selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize; -// snapshot.clip_offset_utf16(selection.start, Bias::Left) -// ..snapshot.clip_offset_utf16(selection.end, Bias::Right) -// }) -// .collect() -// } - -// fn report_copilot_event( -// &self, -// suggestion_id: Option, -// suggestion_accepted: bool, -// cx: &AppContext, -// ) { -// let Some(project) = &self.project else { return }; - -// // If None, we are either getting suggestions in a new, unsaved file, or in a file without an extension -// let file_extension = self -// .buffer -// .read(cx) -// .as_singleton() -// .and_then(|b| b.read(cx).file()) -// .and_then(|file| Path::new(file.file_name(cx)).extension()) -// .and_then(|e| e.to_str()) -// .map(|a| a.to_string()); - -// let telemetry = project.read(cx).client().telemetry().clone(); -// let telemetry_settings = *settings::get::(cx); - -// let event = ClickhouseEvent::Copilot { -// suggestion_id, -// suggestion_accepted, -// file_extension, -// }; -// telemetry.report_clickhouse_event(event, telemetry_settings); -// } - -// #[cfg(any(test, feature = "test-support"))] -// fn report_editor_event( -// &self, -// _operation: &'static str, -// _file_extension: Option, -// _cx: &AppContext, -// ) { -// } - -// #[cfg(not(any(test, feature = "test-support")))] -// fn report_editor_event( -// &self, -// operation: &'static str, -// file_extension: Option, -// cx: &AppContext, -// ) { -// let Some(project) = &self.project else { return }; - -// // If None, we are in a file without an extension -// let file = self -// .buffer -// .read(cx) -// .as_singleton() -// .and_then(|b| b.read(cx).file()); -// let file_extension = file_extension.or(file -// .as_ref() -// .and_then(|file| Path::new(file.file_name(cx)).extension()) -// .and_then(|e| e.to_str()) -// .map(|a| a.to_string())); - -// let vim_mode = cx -// .global::() -// .raw_user_settings() -// .get("vim_mode") -// == Some(&serde_json::Value::Bool(true)); -// let telemetry_settings = *settings::get::(cx); -// let copilot_enabled = all_language_settings(file, cx).copilot_enabled(None, None); -// let copilot_enabled_for_language = self -// .buffer -// .read(cx) -// .settings_at(0, cx) -// .show_copilot_suggestions; - -// let telemetry = project.read(cx).client().telemetry().clone(); -// let event = ClickhouseEvent::Editor { -// file_extension, -// vim_mode, -// operation, -// copilot_enabled, -// copilot_enabled_for_language, -// }; -// telemetry.report_clickhouse_event(event, telemetry_settings) -// } - -// /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines, -// /// with each line being an array of {text, highlight} objects. -// fn copy_highlight_json(&mut self, _: &CopyHighlightJson, cx: &mut ViewContext) { -// let Some(buffer) = self.buffer.read(cx).as_singleton() else { -// return; -// }; - -// #[derive(Serialize)] -// struct Chunk<'a> { -// text: String, -// highlight: Option<&'a str>, -// } - -// let snapshot = buffer.read(cx).snapshot(); -// let range = self -// .selected_text_range(cx) -// .and_then(|selected_range| { -// if selected_range.is_empty() { -// None -// } else { -// Some(selected_range) -// } -// }) -// .unwrap_or_else(|| 0..snapshot.len()); - -// let chunks = snapshot.chunks(range, true); -// let mut lines = Vec::new(); -// let mut line: VecDeque = VecDeque::new(); - -// let theme = &theme::current(cx).editor.syntax; - -// for chunk in chunks { -// let highlight = chunk.syntax_highlight_id.and_then(|id| id.name(theme)); -// let mut chunk_lines = chunk.text.split("\n").peekable(); -// while let Some(text) = chunk_lines.next() { -// let mut merged_with_last_token = false; -// if let Some(last_token) = line.back_mut() { -// if last_token.highlight == highlight { -// last_token.text.push_str(text); -// merged_with_last_token = true; -// } -// } - -// if !merged_with_last_token { -// line.push_back(Chunk { -// text: text.into(), -// highlight, -// }); -// } - -// if chunk_lines.peek().is_some() { -// if line.len() > 1 && line.front().unwrap().text.is_empty() { -// line.pop_front(); -// } -// if line.len() > 1 && line.back().unwrap().text.is_empty() { -// line.pop_back(); -// } - -// lines.push(mem::take(&mut line)); -// } -// } -// } - -// let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else { -// return; -// }; -// cx.write_to_clipboard(ClipboardItem::new(lines)); -// } - -// pub fn inlay_hint_cache(&self) -> &InlayHintCache { -// &self.inlay_hint_cache -// } - -// pub fn replay_insert_event( -// &mut self, -// text: &str, -// relative_utf16_range: Option>, -// cx: &mut ViewContext, -// ) { -// if !self.input_enabled { -// cx.emit(Event::InputIgnored { text: text.into() }); -// return; -// } -// if let Some(relative_utf16_range) = relative_utf16_range { -// let selections = self.selections.all::(cx); -// self.change_selections(None, cx, |s| { -// let new_ranges = selections.into_iter().map(|range| { -// let start = OffsetUtf16( -// range -// .head() -// .0 -// .saturating_add_signed(relative_utf16_range.start), -// ); -// let end = OffsetUtf16( -// range -// .head() -// .0 -// .saturating_add_signed(relative_utf16_range.end), -// ); -// start..end -// }); -// s.select_ranges(new_ranges); -// }); -// } - -// self.handle_input(text, cx); -// } - -// pub fn supports_inlay_hints(&self, cx: &AppContext) -> bool { -// let Some(project) = self.project.as_ref() else { -// return false; -// }; -// let project = project.read(cx); - -// let mut supports = false; -// self.buffer().read(cx).for_each_buffer(|buffer| { -// if !supports { -// supports = project -// .language_servers_for_buffer(buffer.read(cx), cx) -// .any( -// |(_, server)| match server.capabilities().inlay_hint_provider { -// Some(lsp::OneOf::Left(enabled)) => enabled, -// Some(lsp::OneOf::Right(_)) => true, -// None => false, -// }, -// ) -// } -// }); -// supports -// } -// } - pub trait CollaborationHub { fn collaborators<'a>(&self, cx: &'a AppContext) -> &'a HashMap; fn user_participant_indices<'a>( @@ -10033,7 +10012,6 @@ pub fn highlight_diagnostic_message( // runs // }) -// } pub fn split_words<'a>(text: &'a str) -> impl std::iter::Iterator + 'a { let mut index = 0; diff --git a/crates/editor2/src/items.rs b/crates/editor2/src/items.rs index 13d5dc4d1b..f01e6ab2b3 100644 --- a/crates/editor2/src/items.rs +++ b/crates/editor2/src/items.rs @@ -48,106 +48,108 @@ impl FollowableItem for Editor { state: &mut Option, cx: &mut AppContext, ) -> Option>>> { - let project = workspace.read(cx).project().to_owned(); - let Some(proto::view::Variant::Editor(_)) = state else { - return None; - }; - let Some(proto::view::Variant::Editor(state)) = state.take() else { - unreachable!() - }; - - let client = project.read(cx).client(); - let replica_id = project.read(cx).replica_id(); - let buffer_ids = state - .excerpts - .iter() - .map(|excerpt| excerpt.buffer_id) - .collect::>(); - let buffers = project.update(cx, |project, cx| { - buffer_ids - .iter() - .map(|id| project.open_buffer_by_id(*id, cx)) - .collect::>() - }); - - let pane = pane.downgrade(); - Some(cx.spawn(|mut cx| async move { - let mut buffers = futures::future::try_join_all(buffers).await?; - let editor = pane.read_with(&cx, |pane, cx| { - let mut editors = pane.items_of_type::(); - editors.find(|editor| { - let ids_match = editor.remote_id(&client, cx) == Some(remote_id); - let singleton_buffer_matches = state.singleton - && buffers.first() - == editor.read(cx).buffer.read(cx).as_singleton().as_ref(); - ids_match || singleton_buffer_matches - }) - })?; - - let editor = if let Some(editor) = editor { - editor - } else { - pane.update(&mut cx, |_, cx| { - let multibuffer = cx.add_model(|cx| { - let mut multibuffer; - if state.singleton && buffers.len() == 1 { - multibuffer = MultiBuffer::singleton(buffers.pop().unwrap(), cx) - } else { - multibuffer = MultiBuffer::new(replica_id); - let mut excerpts = state.excerpts.into_iter().peekable(); - while let Some(excerpt) = excerpts.peek() { - let buffer_id = excerpt.buffer_id; - let buffer_excerpts = iter::from_fn(|| { - let excerpt = excerpts.peek()?; - (excerpt.buffer_id == buffer_id) - .then(|| excerpts.next().unwrap()) - }); - let buffer = - buffers.iter().find(|b| b.read(cx).remote_id() == buffer_id); - if let Some(buffer) = buffer { - multibuffer.push_excerpts( - buffer.clone(), - buffer_excerpts.filter_map(deserialize_excerpt_range), - cx, - ); - } - } - }; - - if let Some(title) = &state.title { - multibuffer = multibuffer.with_title(title.clone()) - } - - multibuffer - }); - - cx.add_view(|cx| { - let mut editor = - Editor::for_multibuffer(multibuffer, Some(project.clone()), cx); - editor.remote_id = Some(remote_id); - editor - }) - })? - }; - - update_editor_from_message( - editor.downgrade(), - project, - proto::update_view::Editor { - selections: state.selections, - pending_selection: state.pending_selection, - scroll_top_anchor: state.scroll_top_anchor, - scroll_x: state.scroll_x, - scroll_y: state.scroll_y, - ..Default::default() - }, - &mut cx, - ) - .await?; - - Ok(editor) - })) + todo!() } + // let project = workspace.read(cx).project().to_owned(); + // let Some(proto::view::Variant::Editor(_)) = state else { + // return None; + // }; + // let Some(proto::view::Variant::Editor(state)) = state.take() else { + // unreachable!() + // }; + + // let client = project.read(cx).client(); + // let replica_id = project.read(cx).replica_id(); + // let buffer_ids = state + // .excerpts + // .iter() + // .map(|excerpt| excerpt.buffer_id) + // .collect::>(); + // let buffers = project.update(cx, |project, cx| { + // buffer_ids + // .iter() + // .map(|id| project.open_buffer_by_id(*id, cx)) + // .collect::>() + // }); + + // let pane = pane.downgrade(); + // Some(cx.spawn(|mut cx| async move { + // let mut buffers = futures::future::try_join_all(buffers).await?; + // let editor = pane.read_with(&cx, |pane, cx| { + // let mut editors = pane.items_of_type::(); + // editors.find(|editor| { + // let ids_match = editor.remote_id(&client, cx) == Some(remote_id); + // let singleton_buffer_matches = state.singleton + // && buffers.first() + // == editor.read(cx).buffer.read(cx).as_singleton().as_ref(); + // ids_match || singleton_buffer_matches + // }) + // })?; + + // let editor = if let Some(editor) = editor { + // editor + // } else { + // pane.update(&mut cx, |_, cx| { + // let multibuffer = cx.add_model(|cx| { + // let mut multibuffer; + // if state.singleton && buffers.len() == 1 { + // multibuffer = MultiBuffer::singleton(buffers.pop().unwrap(), cx) + // } else { + // multibuffer = MultiBuffer::new(replica_id); + // let mut excerpts = state.excerpts.into_iter().peekable(); + // while let Some(excerpt) = excerpts.peek() { + // let buffer_id = excerpt.buffer_id; + // let buffer_excerpts = iter::from_fn(|| { + // let excerpt = excerpts.peek()?; + // (excerpt.buffer_id == buffer_id) + // .then(|| excerpts.next().unwrap()) + // }); + // let buffer = + // buffers.iter().find(|b| b.read(cx).remote_id() == buffer_id); + // if let Some(buffer) = buffer { + // multibuffer.push_excerpts( + // buffer.clone(), + // buffer_excerpts.filter_map(deserialize_excerpt_range), + // cx, + // ); + // } + // } + // }; + + // if let Some(title) = &state.title { + // multibuffer = multibuffer.with_title(title.clone()) + // } + + // multibuffer + // }); + + // cx.add_view(|cx| { + // let mut editor = + // Editor::for_multibuffer(multibuffer, Some(project.clone()), cx); + // editor.remote_id = Some(remote_id); + // editor + // }) + // })? + // }; + + // update_editor_from_message( + // editor.downgrade(), + // project, + // proto::update_view::Editor { + // selections: state.selections, + // pending_selection: state.pending_selection, + // scroll_top_anchor: state.scroll_top_anchor, + // scroll_x: state.scroll_x, + // scroll_y: state.scroll_y, + // ..Default::default() + // }, + // &mut cx, + // ) + // .await?; + + // Ok(editor) + // })) + // } fn set_leader_peer_id(&mut self, leader_peer_id: Option, cx: &mut ViewContext) { self.leader_peer_id = leader_peer_id; @@ -197,8 +199,8 @@ impl FollowableItem for Editor { title: (!buffer.is_singleton()).then(|| buffer.title(cx).into()), excerpts, scroll_top_anchor: Some(serialize_anchor(&scroll_anchor.anchor)), - scroll_x: scroll_anchor.offset.x(), - scroll_y: scroll_anchor.offset.y(), + scroll_x: scroll_anchor.offset.x, + scroll_y: scroll_anchor.offset.y, selections: self .selections .disjoint_anchors() @@ -254,8 +256,8 @@ impl FollowableItem for Editor { Event::ScrollPositionChanged { .. } => { let scroll_anchor = self.scroll_manager.anchor(); update.scroll_top_anchor = Some(serialize_anchor(&scroll_anchor.anchor)); - update.scroll_x = scroll_anchor.offset.x(); - update.scroll_y = scroll_anchor.offset.y(); + update.scroll_x = scroll_anchor.offset.x; + update.scroll_y = scroll_anchor.offset.y; true } Event::SelectionsChanged { .. } => { @@ -561,8 +563,8 @@ impl Item for Editor { fn tab_description<'a>(&'a self, detail: usize, cx: &'a AppContext) -> Option { match path_for_buffer(&self.buffer, detail, true, cx)? { - Cow::Borrowed(path) => Some(path.to_string_lossy()), - Cow::Owned(path) => Some(path.to_string_lossy().to_string().into()), + Cow::Borrowed(path) => Some(path.to_string_lossy), + Cow::Owned(path) => Some(path.to_string_lossy.to_string().into()), } } @@ -598,7 +600,11 @@ impl Item for Editor { self.buffer.read(cx).is_singleton() } - fn clone_on_split(&self, _workspace_id: WorkspaceId, cx: &mut ViewContext) -> Option + fn clone_on_split( + &self, + _workspace_id: WorkspaceId, + cx: &mut ViewContext, + ) -> Option> where Self: Sized, { @@ -611,7 +617,8 @@ impl Item for Editor { fn deactivated(&mut self, cx: &mut ViewContext) { let selection = self.selections.newest_anchor(); - self.push_to_nav_history(selection.head(), None, cx); + todo!() + // self.push_to_nav_history(selection.head(), None, cx); } fn workspace_deactivated(&mut self, cx: &mut ViewContext) { @@ -652,7 +659,7 @@ impl Item for Editor { // we simulate saving by calling `Buffer::did_save`, so that language servers or // other downstream listeners of save events get notified. let (dirty_buffers, clean_buffers) = buffers.into_iter().partition(|buffer| { - buffer.read_with(&cx, |buffer, _| buffer.is_dirty() || buffer.has_conflict()) + buffer.read_with(&cx, |buffer, _| buffer.is_dirty || buffer.has_conflict()) }); project @@ -686,9 +693,7 @@ impl Item for Editor { .as_singleton() .expect("cannot call save_as on an excerpt list"); - let file_extension = abs_path - .extension() - .map(|a| a.to_string_lossy().to_string()); + let file_extension = abs_path.extension().map(|a| a.to_string_lossy.to_string()); self.report_editor_event("save", file_extension, cx); project.update(cx, |project, cx| { diff --git a/crates/editor2/src/movement.rs b/crates/editor2/src/movement.rs index 593f7a4831..0749c3f178 100644 --- a/crates/editor2/src/movement.rs +++ b/crates/editor2/src/movement.rs @@ -2,7 +2,7 @@ use super::{Bias, DisplayPoint, DisplaySnapshot, SelectionGoal, ToDisplayPoint}; use crate::{char_kind, CharKind, EditorStyle, ToOffset, ToPoint}; use gpui::TextSystem; use language::Point; -use std::{ops::Range, sync::Arc}; +use std::ops::Range; #[derive(Debug, PartialEq)] pub enum FindRange { @@ -444,483 +444,483 @@ pub fn split_display_range_by_lines( result } -#[cfg(test)] -mod tests { - use super::*; - use crate::{ - display_map::Inlay, - test::{editor_test_context::EditorTestContext, marked_display_snapshot}, - Buffer, DisplayMap, ExcerptRange, InlayId, MultiBuffer, - }; - use project::Project; - use settings::SettingsStore; - use util::post_inc; +// #[cfg(test)] +// mod tests { +// use super::*; +// use crate::{ +// display_map::Inlay, +// test::{}, +// Buffer, DisplayMap, ExcerptRange, InlayId, MultiBuffer, +// }; +// use project::Project; +// use settings::SettingsStore; +// use util::post_inc; - #[gpui::test] - fn test_previous_word_start(cx: &mut gpui::AppContext) { - init_test(cx); +// #[gpui::test] +// fn test_previous_word_start(cx: &mut gpui::AppContext) { +// init_test(cx); - fn assert(marked_text: &str, cx: &mut gpui::AppContext) { - let (snapshot, display_points) = marked_display_snapshot(marked_text, cx); - assert_eq!( - previous_word_start(&snapshot, display_points[1]), - display_points[0] - ); - } +// fn assert(marked_text: &str, cx: &mut gpui::AppContext) { +// let (snapshot, display_points) = marked_display_snapshot(marked_text, cx); +// assert_eq!( +// previous_word_start(&snapshot, display_points[1]), +// display_points[0] +// ); +// } - assert("\nˇ ˇlorem", cx); - assert("ˇ\nˇ lorem", cx); - assert(" ˇloremˇ", cx); - assert("ˇ ˇlorem", cx); - assert(" ˇlorˇem", cx); - assert("\nlorem\nˇ ˇipsum", cx); - assert("\n\nˇ\nˇ", cx); - assert(" ˇlorem ˇipsum", cx); - assert("loremˇ-ˇipsum", cx); - assert("loremˇ-#$@ˇipsum", cx); - assert("ˇlorem_ˇipsum", cx); - assert(" ˇdefγˇ", cx); - assert(" ˇbcΔˇ", cx); - assert(" abˇ——ˇcd", cx); - } +// assert("\nˇ ˇlorem", cx); +// assert("ˇ\nˇ lorem", cx); +// assert(" ˇloremˇ", cx); +// assert("ˇ ˇlorem", cx); +// assert(" ˇlorˇem", cx); +// assert("\nlorem\nˇ ˇipsum", cx); +// assert("\n\nˇ\nˇ", cx); +// assert(" ˇlorem ˇipsum", cx); +// assert("loremˇ-ˇipsum", cx); +// assert("loremˇ-#$@ˇipsum", cx); +// assert("ˇlorem_ˇipsum", cx); +// assert(" ˇdefγˇ", cx); +// assert(" ˇbcΔˇ", cx); +// assert(" abˇ——ˇcd", cx); +// } - #[gpui::test] - fn test_previous_subword_start(cx: &mut gpui::AppContext) { - init_test(cx); +// #[gpui::test] +// fn test_previous_subword_start(cx: &mut gpui::AppContext) { +// init_test(cx); - fn assert(marked_text: &str, cx: &mut gpui::AppContext) { - let (snapshot, display_points) = marked_display_snapshot(marked_text, cx); - assert_eq!( - previous_subword_start(&snapshot, display_points[1]), - display_points[0] - ); - } +// fn assert(marked_text: &str, cx: &mut gpui::AppContext) { +// let (snapshot, display_points) = marked_display_snapshot(marked_text, cx); +// assert_eq!( +// previous_subword_start(&snapshot, display_points[1]), +// display_points[0] +// ); +// } - // Subword boundaries are respected - assert("lorem_ˇipˇsum", cx); - assert("lorem_ˇipsumˇ", cx); - assert("ˇlorem_ˇipsum", cx); - assert("lorem_ˇipsum_ˇdolor", cx); - assert("loremˇIpˇsum", cx); - assert("loremˇIpsumˇ", cx); +// // Subword boundaries are respected +// assert("lorem_ˇipˇsum", cx); +// assert("lorem_ˇipsumˇ", cx); +// assert("ˇlorem_ˇipsum", cx); +// assert("lorem_ˇipsum_ˇdolor", cx); +// assert("loremˇIpˇsum", cx); +// assert("loremˇIpsumˇ", cx); - // Word boundaries are still respected - assert("\nˇ ˇlorem", cx); - assert(" ˇloremˇ", cx); - assert(" ˇlorˇem", cx); - assert("\nlorem\nˇ ˇipsum", cx); - assert("\n\nˇ\nˇ", cx); - assert(" ˇlorem ˇipsum", cx); - assert("loremˇ-ˇipsum", cx); - assert("loremˇ-#$@ˇipsum", cx); - assert(" ˇdefγˇ", cx); - assert(" bcˇΔˇ", cx); - assert(" ˇbcδˇ", cx); - assert(" abˇ——ˇcd", cx); - } +// // Word boundaries are still respected +// assert("\nˇ ˇlorem", cx); +// assert(" ˇloremˇ", cx); +// assert(" ˇlorˇem", cx); +// assert("\nlorem\nˇ ˇipsum", cx); +// assert("\n\nˇ\nˇ", cx); +// assert(" ˇlorem ˇipsum", cx); +// assert("loremˇ-ˇipsum", cx); +// assert("loremˇ-#$@ˇipsum", cx); +// assert(" ˇdefγˇ", cx); +// assert(" bcˇΔˇ", cx); +// assert(" ˇbcδˇ", cx); +// assert(" abˇ——ˇcd", cx); +// } - #[gpui::test] - fn test_find_preceding_boundary(cx: &mut gpui::AppContext) { - init_test(cx); +// #[gpui::test] +// fn test_find_preceding_boundary(cx: &mut gpui::AppContext) { +// init_test(cx); - fn assert( - marked_text: &str, - cx: &mut gpui::AppContext, - is_boundary: impl FnMut(char, char) -> bool, - ) { - let (snapshot, display_points) = marked_display_snapshot(marked_text, cx); - assert_eq!( - find_preceding_boundary( - &snapshot, - display_points[1], - FindRange::MultiLine, - is_boundary - ), - display_points[0] - ); - } +// fn assert( +// marked_text: &str, +// cx: &mut gpui::AppContext, +// is_boundary: impl FnMut(char, char) -> bool, +// ) { +// let (snapshot, display_points) = marked_display_snapshot(marked_text, cx); +// assert_eq!( +// find_preceding_boundary( +// &snapshot, +// display_points[1], +// FindRange::MultiLine, +// is_boundary +// ), +// display_points[0] +// ); +// } - assert("abcˇdef\ngh\nijˇk", cx, |left, right| { - left == 'c' && right == 'd' - }); - assert("abcdef\nˇgh\nijˇk", cx, |left, right| { - left == '\n' && right == 'g' - }); - let mut line_count = 0; - assert("abcdef\nˇgh\nijˇk", cx, |left, _| { - if left == '\n' { - line_count += 1; - line_count == 2 - } else { - false - } - }); - } +// assert("abcˇdef\ngh\nijˇk", cx, |left, right| { +// left == 'c' && right == 'd' +// }); +// assert("abcdef\nˇgh\nijˇk", cx, |left, right| { +// left == '\n' && right == 'g' +// }); +// let mut line_count = 0; +// assert("abcdef\nˇgh\nijˇk", cx, |left, _| { +// if left == '\n' { +// line_count += 1; +// line_count == 2 +// } else { +// false +// } +// }); +// } - #[gpui::test] - fn test_find_preceding_boundary_with_inlays(cx: &mut gpui::AppContext) { - init_test(cx); +// #[gpui::test] +// fn test_find_preceding_boundary_with_inlays(cx: &mut gpui::AppContext) { +// init_test(cx); - let input_text = "abcdefghijklmnopqrstuvwxys"; - let family_id = cx - .font_cache() - .load_family(&["Helvetica"], &Default::default()) - .unwrap(); - let font_id = cx - .font_cache() - .select_font(family_id, &Default::default()) - .unwrap(); - let font_size = 14.0; - let buffer = MultiBuffer::build_simple(input_text, cx); - let buffer_snapshot = buffer.read(cx).snapshot(cx); - let display_map = - cx.add_model(|cx| DisplayMap::new(buffer, font_id, font_size, None, 1, 1, cx)); +// let input_text = "abcdefghijklmnopqrstuvwxys"; +// let family_id = cx +// .font_cache() +// .load_family(&["Helvetica"], &Default::default()) +// .unwrap(); +// let font_id = cx +// .font_cache() +// .select_font(family_id, &Default::default()) +// .unwrap(); +// let font_size = 14.0; +// let buffer = MultiBuffer::build_simple(input_text, cx); +// let buffer_snapshot = buffer.read(cx).snapshot(cx); +// let display_map = +// cx.add_model(|cx| DisplayMap::new(buffer, font_id, font_size, None, 1, 1, cx)); - // add all kinds of inlays between two word boundaries: we should be able to cross them all, when looking for another boundary - let mut id = 0; - let inlays = (0..buffer_snapshot.len()) - .map(|offset| { - [ - Inlay { - id: InlayId::Suggestion(post_inc(&mut id)), - position: buffer_snapshot.anchor_at(offset, Bias::Left), - text: format!("test").into(), - }, - Inlay { - id: InlayId::Suggestion(post_inc(&mut id)), - position: buffer_snapshot.anchor_at(offset, Bias::Right), - text: format!("test").into(), - }, - Inlay { - id: InlayId::Hint(post_inc(&mut id)), - position: buffer_snapshot.anchor_at(offset, Bias::Left), - text: format!("test").into(), - }, - Inlay { - id: InlayId::Hint(post_inc(&mut id)), - position: buffer_snapshot.anchor_at(offset, Bias::Right), - text: format!("test").into(), - }, - ] - }) - .flatten() - .collect(); - let snapshot = display_map.update(cx, |map, cx| { - map.splice_inlays(Vec::new(), inlays, cx); - map.snapshot(cx) - }); +// // add all kinds of inlays between two word boundaries: we should be able to cross them all, when looking for another boundary +// let mut id = 0; +// let inlays = (0..buffer_snapshot.len()) +// .map(|offset| { +// [ +// Inlay { +// id: InlayId::Suggestion(post_inc(&mut id)), +// position: buffer_snapshot.anchor_at(offset, Bias::Left), +// text: format!("test").into(), +// }, +// Inlay { +// id: InlayId::Suggestion(post_inc(&mut id)), +// position: buffer_snapshot.anchor_at(offset, Bias::Right), +// text: format!("test").into(), +// }, +// Inlay { +// id: InlayId::Hint(post_inc(&mut id)), +// position: buffer_snapshot.anchor_at(offset, Bias::Left), +// text: format!("test").into(), +// }, +// Inlay { +// id: InlayId::Hint(post_inc(&mut id)), +// position: buffer_snapshot.anchor_at(offset, Bias::Right), +// text: format!("test").into(), +// }, +// ] +// }) +// .flatten() +// .collect(); +// let snapshot = display_map.update(cx, |map, cx| { +// map.splice_inlays(Vec::new(), inlays, cx); +// map.snapshot(cx) +// }); - assert_eq!( - find_preceding_boundary( - &snapshot, - buffer_snapshot.len().to_display_point(&snapshot), - FindRange::MultiLine, - |left, _| left == 'e', - ), - snapshot - .buffer_snapshot - .offset_to_point(5) - .to_display_point(&snapshot), - "Should not stop at inlays when looking for boundaries" - ); - } +// assert_eq!( +// find_preceding_boundary( +// &snapshot, +// buffer_snapshot.len().to_display_point(&snapshot), +// FindRange::MultiLine, +// |left, _| left == 'e', +// ), +// snapshot +// .buffer_snapshot +// .offset_to_point(5) +// .to_display_point(&snapshot), +// "Should not stop at inlays when looking for boundaries" +// ); +// } - #[gpui::test] - fn test_next_word_end(cx: &mut gpui::AppContext) { - init_test(cx); +// #[gpui::test] +// fn test_next_word_end(cx: &mut gpui::AppContext) { +// init_test(cx); - fn assert(marked_text: &str, cx: &mut gpui::AppContext) { - let (snapshot, display_points) = marked_display_snapshot(marked_text, cx); - assert_eq!( - next_word_end(&snapshot, display_points[0]), - display_points[1] - ); - } +// fn assert(marked_text: &str, cx: &mut gpui::AppContext) { +// let (snapshot, display_points) = marked_display_snapshot(marked_text, cx); +// assert_eq!( +// next_word_end(&snapshot, display_points[0]), +// display_points[1] +// ); +// } - assert("\nˇ loremˇ", cx); - assert(" ˇloremˇ", cx); - assert(" lorˇemˇ", cx); - assert(" loremˇ ˇ\nipsum\n", cx); - assert("\nˇ\nˇ\n\n", cx); - assert("loremˇ ipsumˇ ", cx); - assert("loremˇ-ˇipsum", cx); - assert("loremˇ#$@-ˇipsum", cx); - assert("loremˇ_ipsumˇ", cx); - assert(" ˇbcΔˇ", cx); - assert(" abˇ——ˇcd", cx); - } +// assert("\nˇ loremˇ", cx); +// assert(" ˇloremˇ", cx); +// assert(" lorˇemˇ", cx); +// assert(" loremˇ ˇ\nipsum\n", cx); +// assert("\nˇ\nˇ\n\n", cx); +// assert("loremˇ ipsumˇ ", cx); +// assert("loremˇ-ˇipsum", cx); +// assert("loremˇ#$@-ˇipsum", cx); +// assert("loremˇ_ipsumˇ", cx); +// assert(" ˇbcΔˇ", cx); +// assert(" abˇ——ˇcd", cx); +// } - #[gpui::test] - fn test_next_subword_end(cx: &mut gpui::AppContext) { - init_test(cx); +// #[gpui::test] +// fn test_next_subword_end(cx: &mut gpui::AppContext) { +// init_test(cx); - fn assert(marked_text: &str, cx: &mut gpui::AppContext) { - let (snapshot, display_points) = marked_display_snapshot(marked_text, cx); - assert_eq!( - next_subword_end(&snapshot, display_points[0]), - display_points[1] - ); - } +// fn assert(marked_text: &str, cx: &mut gpui::AppContext) { +// let (snapshot, display_points) = marked_display_snapshot(marked_text, cx); +// assert_eq!( +// next_subword_end(&snapshot, display_points[0]), +// display_points[1] +// ); +// } - // Subword boundaries are respected - assert("loˇremˇ_ipsum", cx); - assert("ˇloremˇ_ipsum", cx); - assert("loremˇ_ipsumˇ", cx); - assert("loremˇ_ipsumˇ_dolor", cx); - assert("loˇremˇIpsum", cx); - assert("loremˇIpsumˇDolor", cx); +// // Subword boundaries are respected +// assert("loˇremˇ_ipsum", cx); +// assert("ˇloremˇ_ipsum", cx); +// assert("loremˇ_ipsumˇ", cx); +// assert("loremˇ_ipsumˇ_dolor", cx); +// assert("loˇremˇIpsum", cx); +// assert("loremˇIpsumˇDolor", cx); - // Word boundaries are still respected - assert("\nˇ loremˇ", cx); - assert(" ˇloremˇ", cx); - assert(" lorˇemˇ", cx); - assert(" loremˇ ˇ\nipsum\n", cx); - assert("\nˇ\nˇ\n\n", cx); - assert("loremˇ ipsumˇ ", cx); - assert("loremˇ-ˇipsum", cx); - assert("loremˇ#$@-ˇipsum", cx); - assert("loremˇ_ipsumˇ", cx); - assert(" ˇbcˇΔ", cx); - assert(" abˇ——ˇcd", cx); - } +// // Word boundaries are still respected +// assert("\nˇ loremˇ", cx); +// assert(" ˇloremˇ", cx); +// assert(" lorˇemˇ", cx); +// assert(" loremˇ ˇ\nipsum\n", cx); +// assert("\nˇ\nˇ\n\n", cx); +// assert("loremˇ ipsumˇ ", cx); +// assert("loremˇ-ˇipsum", cx); +// assert("loremˇ#$@-ˇipsum", cx); +// assert("loremˇ_ipsumˇ", cx); +// assert(" ˇbcˇΔ", cx); +// assert(" abˇ——ˇcd", cx); +// } - #[gpui::test] - fn test_find_boundary(cx: &mut gpui::AppContext) { - init_test(cx); +// #[gpui::test] +// fn test_find_boundary(cx: &mut gpui::AppContext) { +// init_test(cx); - fn assert( - marked_text: &str, - cx: &mut gpui::AppContext, - is_boundary: impl FnMut(char, char) -> bool, - ) { - let (snapshot, display_points) = marked_display_snapshot(marked_text, cx); - assert_eq!( - find_boundary( - &snapshot, - display_points[0], - FindRange::MultiLine, - is_boundary - ), - display_points[1] - ); - } +// fn assert( +// marked_text: &str, +// cx: &mut gpui::AppContext, +// is_boundary: impl FnMut(char, char) -> bool, +// ) { +// let (snapshot, display_points) = marked_display_snapshot(marked_text, cx); +// assert_eq!( +// find_boundary( +// &snapshot, +// display_points[0], +// FindRange::MultiLine, +// is_boundary +// ), +// display_points[1] +// ); +// } - assert("abcˇdef\ngh\nijˇk", cx, |left, right| { - left == 'j' && right == 'k' - }); - assert("abˇcdef\ngh\nˇijk", cx, |left, right| { - left == '\n' && right == 'i' - }); - let mut line_count = 0; - assert("abcˇdef\ngh\nˇijk", cx, |left, _| { - if left == '\n' { - line_count += 1; - line_count == 2 - } else { - false - } - }); - } +// assert("abcˇdef\ngh\nijˇk", cx, |left, right| { +// left == 'j' && right == 'k' +// }); +// assert("abˇcdef\ngh\nˇijk", cx, |left, right| { +// left == '\n' && right == 'i' +// }); +// let mut line_count = 0; +// assert("abcˇdef\ngh\nˇijk", cx, |left, _| { +// if left == '\n' { +// line_count += 1; +// line_count == 2 +// } else { +// false +// } +// }); +// } - #[gpui::test] - fn test_surrounding_word(cx: &mut gpui::AppContext) { - init_test(cx); +// #[gpui::test] +// fn test_surrounding_word(cx: &mut gpui::AppContext) { +// init_test(cx); - fn assert(marked_text: &str, cx: &mut gpui::AppContext) { - let (snapshot, display_points) = marked_display_snapshot(marked_text, cx); - assert_eq!( - surrounding_word(&snapshot, display_points[1]), - display_points[0]..display_points[2], - "{}", - marked_text.to_string() - ); - } +// fn assert(marked_text: &str, cx: &mut gpui::AppContext) { +// let (snapshot, display_points) = marked_display_snapshot(marked_text, cx); +// assert_eq!( +// surrounding_word(&snapshot, display_points[1]), +// display_points[0]..display_points[2], +// "{}", +// marked_text.to_string() +// ); +// } - assert("ˇˇloremˇ ipsum", cx); - assert("ˇloˇremˇ ipsum", cx); - assert("ˇloremˇˇ ipsum", cx); - assert("loremˇ ˇ ˇipsum", cx); - assert("lorem\nˇˇˇ\nipsum", cx); - assert("lorem\nˇˇipsumˇ", cx); - assert("loremˇ,ˇˇ ipsum", cx); - assert("ˇloremˇˇ, ipsum", cx); - } +// assert("ˇˇloremˇ ipsum", cx); +// assert("ˇloˇremˇ ipsum", cx); +// assert("ˇloremˇˇ ipsum", cx); +// assert("loremˇ ˇ ˇipsum", cx); +// assert("lorem\nˇˇˇ\nipsum", cx); +// assert("lorem\nˇˇipsumˇ", cx); +// assert("loremˇ,ˇˇ ipsum", cx); +// assert("ˇloremˇˇ, ipsum", cx); +// } - #[gpui::test] - async fn test_move_up_and_down_with_excerpts(cx: &mut gpui::TestAppContext) { - cx.update(|cx| { - init_test(cx); - }); +// #[gpui::test] +// async fn test_move_up_and_down_with_excerpts(cx: &mut gpui::TestAppContext) { +// cx.update(|cx| { +// init_test(cx); +// }); - let mut cx = EditorTestContext::new(cx).await; - let editor = cx.editor.clone(); - let window = cx.window.clone(); - cx.update_window(window, |cx| { - let text_layout_details = - editor.read_with(cx, |editor, cx| editor.text_layout_details(cx)); +// let mut cx = EditorTestContext::new(cx).await; +// let editor = cx.editor.clone(); +// let window = cx.window.clone(); +// cx.update_window(window, |cx| { +// let text_layout_details = +// editor.read_with(cx, |editor, cx| editor.text_layout_details(cx)); - let family_id = cx - .font_cache() - .load_family(&["Helvetica"], &Default::default()) - .unwrap(); - let font_id = cx - .font_cache() - .select_font(family_id, &Default::default()) - .unwrap(); +// let family_id = cx +// .font_cache() +// .load_family(&["Helvetica"], &Default::default()) +// .unwrap(); +// let font_id = cx +// .font_cache() +// .select_font(family_id, &Default::default()) +// .unwrap(); - let buffer = - cx.add_model(|cx| Buffer::new(0, cx.model_id() as u64, "abc\ndefg\nhijkl\nmn")); - let multibuffer = cx.add_model(|cx| { - let mut multibuffer = MultiBuffer::new(0); - multibuffer.push_excerpts( - buffer.clone(), - [ - ExcerptRange { - context: Point::new(0, 0)..Point::new(1, 4), - primary: None, - }, - ExcerptRange { - context: Point::new(2, 0)..Point::new(3, 2), - primary: None, - }, - ], - cx, - ); - multibuffer - }); - let display_map = - cx.add_model(|cx| DisplayMap::new(multibuffer, font_id, 14.0, None, 2, 2, cx)); - let snapshot = display_map.update(cx, |map, cx| map.snapshot(cx)); +// let buffer = +// cx.add_model(|cx| Buffer::new(0, cx.model_id() as u64, "abc\ndefg\nhijkl\nmn")); +// let multibuffer = cx.add_model(|cx| { +// let mut multibuffer = MultiBuffer::new(0); +// multibuffer.push_excerpts( +// buffer.clone(), +// [ +// ExcerptRange { +// context: Point::new(0, 0)..Point::new(1, 4), +// primary: None, +// }, +// ExcerptRange { +// context: Point::new(2, 0)..Point::new(3, 2), +// primary: None, +// }, +// ], +// cx, +// ); +// multibuffer +// }); +// let display_map = +// cx.add_model(|cx| DisplayMap::new(multibuffer, font_id, 14.0, None, 2, 2, cx)); +// let snapshot = display_map.update(cx, |map, cx| map.snapshot(cx)); - assert_eq!(snapshot.text(), "\n\nabc\ndefg\n\n\nhijkl\nmn"); +// assert_eq!(snapshot.text(), "\n\nabc\ndefg\n\n\nhijkl\nmn"); - let col_2_x = snapshot.x_for_point(DisplayPoint::new(2, 2), &text_layout_details); +// let col_2_x = snapshot.x_for_point(DisplayPoint::new(2, 2), &text_layout_details); - // Can't move up into the first excerpt's header - assert_eq!( - up( - &snapshot, - DisplayPoint::new(2, 2), - SelectionGoal::HorizontalPosition(col_2_x), - false, - &text_layout_details - ), - ( - DisplayPoint::new(2, 0), - SelectionGoal::HorizontalPosition(0.0) - ), - ); - assert_eq!( - up( - &snapshot, - DisplayPoint::new(2, 0), - SelectionGoal::None, - false, - &text_layout_details - ), - ( - DisplayPoint::new(2, 0), - SelectionGoal::HorizontalPosition(0.0) - ), - ); +// // Can't move up into the first excerpt's header +// assert_eq!( +// up( +// &snapshot, +// DisplayPoint::new(2, 2), +// SelectionGoal::HorizontalPosition(col_2_x), +// false, +// &text_layout_details +// ), +// ( +// DisplayPoint::new(2, 0), +// SelectionGoal::HorizontalPosition(0.0) +// ), +// ); +// assert_eq!( +// up( +// &snapshot, +// DisplayPoint::new(2, 0), +// SelectionGoal::None, +// false, +// &text_layout_details +// ), +// ( +// DisplayPoint::new(2, 0), +// SelectionGoal::HorizontalPosition(0.0) +// ), +// ); - let col_4_x = snapshot.x_for_point(DisplayPoint::new(3, 4), &text_layout_details); +// let col_4_x = snapshot.x_for_point(DisplayPoint::new(3, 4), &text_layout_details); - // Move up and down within first excerpt - assert_eq!( - up( - &snapshot, - DisplayPoint::new(3, 4), - SelectionGoal::HorizontalPosition(col_4_x), - false, - &text_layout_details - ), - ( - DisplayPoint::new(2, 3), - SelectionGoal::HorizontalPosition(col_4_x) - ), - ); - assert_eq!( - down( - &snapshot, - DisplayPoint::new(2, 3), - SelectionGoal::HorizontalPosition(col_4_x), - false, - &text_layout_details - ), - ( - DisplayPoint::new(3, 4), - SelectionGoal::HorizontalPosition(col_4_x) - ), - ); +// // Move up and down within first excerpt +// assert_eq!( +// up( +// &snapshot, +// DisplayPoint::new(3, 4), +// SelectionGoal::HorizontalPosition(col_4_x), +// false, +// &text_layout_details +// ), +// ( +// DisplayPoint::new(2, 3), +// SelectionGoal::HorizontalPosition(col_4_x) +// ), +// ); +// assert_eq!( +// down( +// &snapshot, +// DisplayPoint::new(2, 3), +// SelectionGoal::HorizontalPosition(col_4_x), +// false, +// &text_layout_details +// ), +// ( +// DisplayPoint::new(3, 4), +// SelectionGoal::HorizontalPosition(col_4_x) +// ), +// ); - let col_5_x = snapshot.x_for_point(DisplayPoint::new(6, 5), &text_layout_details); +// let col_5_x = snapshot.x_for_point(DisplayPoint::new(6, 5), &text_layout_details); - // Move up and down across second excerpt's header - assert_eq!( - up( - &snapshot, - DisplayPoint::new(6, 5), - SelectionGoal::HorizontalPosition(col_5_x), - false, - &text_layout_details - ), - ( - DisplayPoint::new(3, 4), - SelectionGoal::HorizontalPosition(col_5_x) - ), - ); - assert_eq!( - down( - &snapshot, - DisplayPoint::new(3, 4), - SelectionGoal::HorizontalPosition(col_5_x), - false, - &text_layout_details - ), - ( - DisplayPoint::new(6, 5), - SelectionGoal::HorizontalPosition(col_5_x) - ), - ); +// // Move up and down across second excerpt's header +// assert_eq!( +// up( +// &snapshot, +// DisplayPoint::new(6, 5), +// SelectionGoal::HorizontalPosition(col_5_x), +// false, +// &text_layout_details +// ), +// ( +// DisplayPoint::new(3, 4), +// SelectionGoal::HorizontalPosition(col_5_x) +// ), +// ); +// assert_eq!( +// down( +// &snapshot, +// DisplayPoint::new(3, 4), +// SelectionGoal::HorizontalPosition(col_5_x), +// false, +// &text_layout_details +// ), +// ( +// DisplayPoint::new(6, 5), +// SelectionGoal::HorizontalPosition(col_5_x) +// ), +// ); - let max_point_x = snapshot.x_for_point(DisplayPoint::new(7, 2), &text_layout_details); +// let max_point_x = snapshot.x_for_point(DisplayPoint::new(7, 2), &text_layout_details); - // Can't move down off the end - assert_eq!( - down( - &snapshot, - DisplayPoint::new(7, 0), - SelectionGoal::HorizontalPosition(0.0), - false, - &text_layout_details - ), - ( - DisplayPoint::new(7, 2), - SelectionGoal::HorizontalPosition(max_point_x) - ), - ); - assert_eq!( - down( - &snapshot, - DisplayPoint::new(7, 2), - SelectionGoal::HorizontalPosition(max_point_x), - false, - &text_layout_details - ), - ( - DisplayPoint::new(7, 2), - SelectionGoal::HorizontalPosition(max_point_x) - ), - ); - }); - } +// // Can't move down off the end +// assert_eq!( +// down( +// &snapshot, +// DisplayPoint::new(7, 0), +// SelectionGoal::HorizontalPosition(0.0), +// false, +// &text_layout_details +// ), +// ( +// DisplayPoint::new(7, 2), +// SelectionGoal::HorizontalPosition(max_point_x) +// ), +// ); +// assert_eq!( +// down( +// &snapshot, +// DisplayPoint::new(7, 2), +// SelectionGoal::HorizontalPosition(max_point_x), +// false, +// &text_layout_details +// ), +// ( +// DisplayPoint::new(7, 2), +// SelectionGoal::HorizontalPosition(max_point_x) +// ), +// ); +// }); +// } - fn init_test(cx: &mut gpui::AppContext) { - cx.set_global(SettingsStore::test(cx)); - theme::init(cx); - language::init(cx); - crate::init(cx); - Project::init_settings(cx); - } -} +// fn init_test(cx: &mut gpui::AppContext) { +// cx.set_global(SettingsStore::test(cx)); +// theme::init(cx); +// language::init(cx); +// crate::init(cx); +// Project::init_settings(cx); +// } +// } diff --git a/crates/editor2/src/scroll.rs b/crates/editor2/src/scroll.rs index 4e809dbef4..2abf80a747 100644 --- a/crates/editor2/src/scroll.rs +++ b/crates/editor2/src/scroll.rs @@ -39,7 +39,7 @@ pub struct ScrollAnchor { impl ScrollAnchor { fn new() -> Self { Self { - offset: Point::zero(), + offset: gpui::Point::zero(), anchor: Anchor::min(), } } @@ -48,7 +48,7 @@ impl ScrollAnchor { let mut scroll_position = self.offset; if self.anchor != Anchor::min() { let scroll_top = self.anchor.to_display_point(snapshot).row() as f32; - scroll_position.set_y(scroll_top + scroll_position.y()); + scroll_position.set_y(scroll_top + scroll_position.y); } else { scroll_position.set_y(0.); } @@ -82,7 +82,7 @@ impl OngoingScroll { pub fn filter(&self, delta: &mut gpui::Point) -> Option { const UNLOCK_PERCENT: f32 = 1.9; - const UNLOCK_LOWER_BOUND: f32 = 6.; + const UNLOCK_LOWER_BOUND: Pixels = px(6.); let mut axis = self.axis; let x = delta.x.abs(); @@ -116,10 +116,10 @@ impl OngoingScroll { match axis { Some(Axis::Vertical) => { - *delta = point(pk(0.), delta.y()); + *delta = point(px(0.), delta.y); } Some(Axis::Horizontal) => { - *delta = point(delta.x(), px(0.)); + *delta = point(delta.x, px(0.)); } None => {} } @@ -177,14 +177,14 @@ impl ScrollManager { fn set_scroll_position( &mut self, - scroll_position: gpui::Point, + scroll_position: gpui::Point, map: &DisplaySnapshot, local: bool, autoscroll: bool, workspace_id: Option, cx: &mut ViewContext, ) { - let (new_anchor, top_row) = if scroll_position.y() <= 0. { + let (new_anchor, top_row) = if scroll_position.y <= 0. { ( ScrollAnchor { anchor: Anchor::min(), @@ -194,7 +194,7 @@ impl ScrollManager { ) } else { let scroll_top_buffer_point = - DisplayPoint::new(scroll_position.y() as u32, 0).to_point(&map); + DisplayPoint::new(scroll_position.y as u32, 0).to_point(&map); let top_anchor = map .buffer_snapshot .anchor_at(scroll_top_buffer_point, Bias::Right); @@ -203,8 +203,8 @@ impl ScrollManager { ScrollAnchor { anchor: top_anchor, offset: point( - scroll_position.x(), - scroll_position.y() - top_anchor.to_display_point(&map).row() as f32, + scroll_position.x, + scroll_position.y - top_anchor.to_display_point(&map).row() as f32, ), }, scroll_top_buffer_point.row, @@ -236,8 +236,8 @@ impl ScrollManager { item_id, workspace_id, top_row, - anchor.offset.x(), - anchor.offset.y(), + anchor.offset.x, + anchor.offset.y, ) .await .log_err() @@ -277,8 +277,8 @@ impl ScrollManager { } pub fn clamp_scroll_left(&mut self, max: f32) -> bool { - if max < self.anchor.offset.x() { - self.anchor.offset.set_x(max); + if max < self.anchor.offset.x { + self.anchor.offset.x = max; true } else { false diff --git a/crates/editor2/src/scroll/autoscroll.rs b/crates/editor2/src/scroll/autoscroll.rs index ffada50179..5816e5683b 100644 --- a/crates/editor2/src/scroll/autoscroll.rs +++ b/crates/editor2/src/scroll/autoscroll.rs @@ -60,7 +60,7 @@ impl Editor { } else { display_map.max_point().row() as f32 }; - if scroll_position.y() > max_scroll_top { + if scroll_position.y > max_scroll_top { scroll_position.set_y(max_scroll_top); self.set_scroll_position(scroll_position, cx); } @@ -136,7 +136,7 @@ impl Editor { let margin = margin.min(self.scroll_manager.vertical_scroll_margin); let target_top = (target_top - margin).max(0.0); let target_bottom = target_bottom + margin; - let start_row = scroll_position.y(); + let start_row = scroll_position.y; let end_row = start_row + visible_lines; let needs_scroll_up = target_top < start_row; @@ -222,20 +222,15 @@ impl Editor { return false; } - let scroll_left = self.scroll_manager.anchor.offset.x() * max_glyph_width; + let scroll_left = self.scroll_manager.anchor.offset.x * max_glyph_width; let scroll_right = scroll_left + viewport_width; if target_left < scroll_left { - self.scroll_manager - .anchor - .offset - .set_x(target_left / max_glyph_width); + self.scroll_manager.anchor.offset.x = (target_left / max_glyph_width); true } else if target_right > scroll_right { - self.scroll_manager - .anchor - .offset - .set_x((target_right - viewport_width) / max_glyph_width); + self.scroll_manager.anchor.offset.x = + ((target_right - viewport_width) / max_glyph_width); true } else { false diff --git a/crates/editor2/src/test/editor_lsp_test_context.rs b/crates/editor2/src/test/editor_lsp_test_context.rs index 6d1662857d..5a6bdd2723 100644 --- a/crates/editor2/src/test/editor_lsp_test_context.rs +++ b/crates/editor2/src/test/editor_lsp_test_context.rs @@ -1,297 +1,297 @@ -use std::{ - borrow::Cow, - ops::{Deref, DerefMut, Range}, - sync::Arc, -}; +// use std::{ +// borrow::Cow, +// ops::{Deref, DerefMut, Range}, +// sync::Arc, +// }; -use anyhow::Result; +// use anyhow::Result; -use crate::{Editor, ToPoint}; -use collections::HashSet; -use futures::Future; -use gpui::{json, View, ViewContext}; -use indoc::indoc; -use language::{point_to_lsp, FakeLspAdapter, Language, LanguageConfig, LanguageQueries}; -use lsp::{notification, request}; -use multi_buffer::ToPointUtf16; -use project::Project; -use smol::stream::StreamExt; -use workspace::{AppState, Workspace, WorkspaceHandle}; +// use crate::{Editor, ToPoint}; +// use collections::HashSet; +// use futures::Future; +// use gpui::{json, View, ViewContext}; +// use indoc::indoc; +// use language::{point_to_lsp, FakeLspAdapter, Language, LanguageConfig, LanguageQueries}; +// use lsp::{notification, request}; +// use multi_buffer::ToPointUtf16; +// use project::Project; +// use smol::stream::StreamExt; +// use workspace::{AppState, Workspace, WorkspaceHandle}; -use super::editor_test_context::EditorTestContext; +// use super::editor_test_context::EditorTestContext; -pub struct EditorLspTestContext<'a> { - pub cx: EditorTestContext<'a>, - pub lsp: lsp::FakeLanguageServer, - pub workspace: ViewHandle, - pub buffer_lsp_url: lsp::Url, -} +// pub struct EditorLspTestContext<'a> { +// pub cx: EditorTestContext<'a>, +// pub lsp: lsp::FakeLanguageServer, +// pub workspace: View, +// pub buffer_lsp_url: lsp::Url, +// } -impl<'a> EditorLspTestContext<'a> { - pub async fn new( - mut language: Language, - capabilities: lsp::ServerCapabilities, - cx: &'a mut gpui::TestAppContext, - ) -> EditorLspTestContext<'a> { - use json::json; +// impl<'a> EditorLspTestContext<'a> { +// pub async fn new( +// mut language: Language, +// capabilities: lsp::ServerCapabilities, +// cx: &'a mut gpui::TestAppContext, +// ) -> EditorLspTestContext<'a> { +// use json::json; - let app_state = cx.update(AppState::test); +// let app_state = cx.update(AppState::test); - cx.update(|cx| { - language::init(cx); - crate::init(cx); - workspace::init(app_state.clone(), cx); - Project::init_settings(cx); - }); +// cx.update(|cx| { +// language::init(cx); +// crate::init(cx); +// workspace::init(app_state.clone(), cx); +// Project::init_settings(cx); +// }); - let file_name = format!( - "file.{}", - language - .path_suffixes() - .first() - .expect("language must have a path suffix for EditorLspTestContext") - ); +// let file_name = format!( +// "file.{}", +// language +// .path_suffixes() +// .first() +// .expect("language must have a path suffix for EditorLspTestContext") +// ); - let mut fake_servers = language - .set_fake_lsp_adapter(Arc::new(FakeLspAdapter { - capabilities, - ..Default::default() - })) - .await; +// let mut fake_servers = language +// .set_fake_lsp_adapter(Arc::new(FakeLspAdapter { +// capabilities, +// ..Default::default() +// })) +// .await; - let project = Project::test(app_state.fs.clone(), [], cx).await; - project.update(cx, |project, _| project.languages().add(Arc::new(language))); +// let project = Project::test(app_state.fs.clone(), [], cx).await; +// project.update(cx, |project, _| project.languages().add(Arc::new(language))); - app_state - .fs - .as_fake() - .insert_tree("/root", json!({ "dir": { file_name.clone(): "" }})) - .await; +// app_state +// .fs +// .as_fake() +// .insert_tree("/root", json!({ "dir": { file_name.clone(): "" }})) +// .await; - let window = cx.add_window(|cx| Workspace::test_new(project.clone(), cx)); - let workspace = window.root(cx); - project - .update(cx, |project, cx| { - project.find_or_create_local_worktree("/root", true, cx) - }) - .await - .unwrap(); - cx.read(|cx| workspace.read(cx).worktree_scans_complete(cx)) - .await; +// let window = cx.add_window(|cx| Workspace::test_new(project.clone(), cx)); +// let workspace = window.root(cx); +// project +// .update(cx, |project, cx| { +// project.find_or_create_local_worktree("/root", true, cx) +// }) +// .await +// .unwrap(); +// cx.read(|cx| workspace.read(cx).worktree_scans_complete(cx)) +// .await; - let file = cx.read(|cx| workspace.file_project_paths(cx)[0].clone()); - let item = workspace - .update(cx, |workspace, cx| { - workspace.open_path(file, None, true, cx) - }) - .await - .expect("Could not open test file"); +// let file = cx.read(|cx| workspace.file_project_paths(cx)[0].clone()); +// let item = workspace +// .update(cx, |workspace, cx| { +// workspace.open_path(file, None, true, cx) +// }) +// .await +// .expect("Could not open test file"); - let editor = cx.update(|cx| { - item.act_as::(cx) - .expect("Opened test file wasn't an editor") - }); - editor.update(cx, |_, cx| cx.focus_self()); +// let editor = cx.update(|cx| { +// item.act_as::(cx) +// .expect("Opened test file wasn't an editor") +// }); +// editor.update(cx, |_, cx| cx.focus_self()); - let lsp = fake_servers.next().await.unwrap(); +// let lsp = fake_servers.next().await.unwrap(); - Self { - cx: EditorTestContext { - cx, - window: window.into(), - editor, - }, - lsp, - workspace, - buffer_lsp_url: lsp::Url::from_file_path(format!("/root/dir/{file_name}")).unwrap(), - } - } +// Self { +// cx: EditorTestContext { +// cx, +// window: window.into(), +// editor, +// }, +// lsp, +// workspace, +// buffer_lsp_url: lsp::Url::from_file_path(format!("/root/dir/{file_name}")).unwrap(), +// } +// } - pub async fn new_rust( - capabilities: lsp::ServerCapabilities, - cx: &'a mut gpui::TestAppContext, - ) -> EditorLspTestContext<'a> { - let language = Language::new( - LanguageConfig { - name: "Rust".into(), - path_suffixes: vec!["rs".to_string()], - ..Default::default() - }, - Some(tree_sitter_rust::language()), - ) - .with_queries(LanguageQueries { - indents: Some(Cow::from(indoc! {r#" - [ - ((where_clause) _ @end) - (field_expression) - (call_expression) - (assignment_expression) - (let_declaration) - (let_chain) - (await_expression) - ] @indent +// pub async fn new_rust( +// capabilities: lsp::ServerCapabilities, +// cx: &'a mut gpui::TestAppContext, +// ) -> EditorLspTestContext<'a> { +// let language = Language::new( +// LanguageConfig { +// name: "Rust".into(), +// path_suffixes: vec!["rs".to_string()], +// ..Default::default() +// }, +// Some(tree_sitter_rust::language()), +// ) +// .with_queries(LanguageQueries { +// indents: Some(Cow::from(indoc! {r#" +// [ +// ((where_clause) _ @end) +// (field_expression) +// (call_expression) +// (assignment_expression) +// (let_declaration) +// (let_chain) +// (await_expression) +// ] @indent - (_ "[" "]" @end) @indent - (_ "<" ">" @end) @indent - (_ "{" "}" @end) @indent - (_ "(" ")" @end) @indent"#})), - brackets: Some(Cow::from(indoc! {r#" - ("(" @open ")" @close) - ("[" @open "]" @close) - ("{" @open "}" @close) - ("<" @open ">" @close) - ("\"" @open "\"" @close) - (closure_parameters "|" @open "|" @close)"#})), - ..Default::default() - }) - .expect("Could not parse queries"); +// (_ "[" "]" @end) @indent +// (_ "<" ">" @end) @indent +// (_ "{" "}" @end) @indent +// (_ "(" ")" @end) @indent"#})), +// brackets: Some(Cow::from(indoc! {r#" +// ("(" @open ")" @close) +// ("[" @open "]" @close) +// ("{" @open "}" @close) +// ("<" @open ">" @close) +// ("\"" @open "\"" @close) +// (closure_parameters "|" @open "|" @close)"#})), +// ..Default::default() +// }) +// .expect("Could not parse queries"); - Self::new(language, capabilities, cx).await - } +// Self::new(language, capabilities, cx).await +// } - pub async fn new_typescript( - capabilities: lsp::ServerCapabilities, - cx: &'a mut gpui::TestAppContext, - ) -> EditorLspTestContext<'a> { - let mut word_characters: HashSet = Default::default(); - word_characters.insert('$'); - word_characters.insert('#'); - let language = Language::new( - LanguageConfig { - name: "Typescript".into(), - path_suffixes: vec!["ts".to_string()], - brackets: language::BracketPairConfig { - pairs: vec![language::BracketPair { - start: "{".to_string(), - end: "}".to_string(), - close: true, - newline: true, - }], - disabled_scopes_by_bracket_ix: Default::default(), - }, - word_characters, - ..Default::default() - }, - Some(tree_sitter_typescript::language_typescript()), - ) - .with_queries(LanguageQueries { - brackets: Some(Cow::from(indoc! {r#" - ("(" @open ")" @close) - ("[" @open "]" @close) - ("{" @open "}" @close) - ("<" @open ">" @close) - ("\"" @open "\"" @close)"#})), - indents: Some(Cow::from(indoc! {r#" - [ - (call_expression) - (assignment_expression) - (member_expression) - (lexical_declaration) - (variable_declaration) - (assignment_expression) - (if_statement) - (for_statement) - ] @indent +// pub async fn new_typescript( +// capabilities: lsp::ServerCapabilities, +// cx: &'a mut gpui::TestAppContext, +// ) -> EditorLspTestContext<'a> { +// let mut word_characters: HashSet = Default::default(); +// word_characters.insert('$'); +// word_characters.insert('#'); +// let language = Language::new( +// LanguageConfig { +// name: "Typescript".into(), +// path_suffixes: vec!["ts".to_string()], +// brackets: language::BracketPairConfig { +// pairs: vec![language::BracketPair { +// start: "{".to_string(), +// end: "}".to_string(), +// close: true, +// newline: true, +// }], +// disabled_scopes_by_bracket_ix: Default::default(), +// }, +// word_characters, +// ..Default::default() +// }, +// Some(tree_sitter_typescript::language_typescript()), +// ) +// .with_queries(LanguageQueries { +// brackets: Some(Cow::from(indoc! {r#" +// ("(" @open ")" @close) +// ("[" @open "]" @close) +// ("{" @open "}" @close) +// ("<" @open ">" @close) +// ("\"" @open "\"" @close)"#})), +// indents: Some(Cow::from(indoc! {r#" +// [ +// (call_expression) +// (assignment_expression) +// (member_expression) +// (lexical_declaration) +// (variable_declaration) +// (assignment_expression) +// (if_statement) +// (for_statement) +// ] @indent - (_ "[" "]" @end) @indent - (_ "<" ">" @end) @indent - (_ "{" "}" @end) @indent - (_ "(" ")" @end) @indent - "#})), - ..Default::default() - }) - .expect("Could not parse queries"); +// (_ "[" "]" @end) @indent +// (_ "<" ">" @end) @indent +// (_ "{" "}" @end) @indent +// (_ "(" ")" @end) @indent +// "#})), +// ..Default::default() +// }) +// .expect("Could not parse queries"); - Self::new(language, capabilities, cx).await - } +// Self::new(language, capabilities, cx).await +// } - // Constructs lsp range using a marked string with '[', ']' range delimiters - pub fn lsp_range(&mut self, marked_text: &str) -> lsp::Range { - let ranges = self.ranges(marked_text); - self.to_lsp_range(ranges[0].clone()) - } +// // Constructs lsp range using a marked string with '[', ']' range delimiters +// pub fn lsp_range(&mut self, marked_text: &str) -> lsp::Range { +// let ranges = self.ranges(marked_text); +// self.to_lsp_range(ranges[0].clone()) +// } - pub fn to_lsp_range(&mut self, range: Range) -> lsp::Range { - let snapshot = self.update_editor(|editor, cx| editor.snapshot(cx)); - let start_point = range.start.to_point(&snapshot.buffer_snapshot); - let end_point = range.end.to_point(&snapshot.buffer_snapshot); +// pub fn to_lsp_range(&mut self, range: Range) -> lsp::Range { +// let snapshot = self.update_editor(|editor, cx| editor.snapshot(cx)); +// let start_point = range.start.to_point(&snapshot.buffer_snapshot); +// let end_point = range.end.to_point(&snapshot.buffer_snapshot); - self.editor(|editor, cx| { - let buffer = editor.buffer().read(cx); - let start = point_to_lsp( - buffer - .point_to_buffer_offset(start_point, cx) - .unwrap() - .1 - .to_point_utf16(&buffer.read(cx)), - ); - let end = point_to_lsp( - buffer - .point_to_buffer_offset(end_point, cx) - .unwrap() - .1 - .to_point_utf16(&buffer.read(cx)), - ); +// self.editor(|editor, cx| { +// let buffer = editor.buffer().read(cx); +// let start = point_to_lsp( +// buffer +// .point_to_buffer_offset(start_point, cx) +// .unwrap() +// .1 +// .to_point_utf16(&buffer.read(cx)), +// ); +// let end = point_to_lsp( +// buffer +// .point_to_buffer_offset(end_point, cx) +// .unwrap() +// .1 +// .to_point_utf16(&buffer.read(cx)), +// ); - lsp::Range { start, end } - }) - } +// lsp::Range { start, end } +// }) +// } - pub fn to_lsp(&mut self, offset: usize) -> lsp::Position { - let snapshot = self.update_editor(|editor, cx| editor.snapshot(cx)); - let point = offset.to_point(&snapshot.buffer_snapshot); +// pub fn to_lsp(&mut self, offset: usize) -> lsp::Position { +// let snapshot = self.update_editor(|editor, cx| editor.snapshot(cx)); +// let point = offset.to_point(&snapshot.buffer_snapshot); - self.editor(|editor, cx| { - let buffer = editor.buffer().read(cx); - point_to_lsp( - buffer - .point_to_buffer_offset(point, cx) - .unwrap() - .1 - .to_point_utf16(&buffer.read(cx)), - ) - }) - } +// self.editor(|editor, cx| { +// let buffer = editor.buffer().read(cx); +// point_to_lsp( +// buffer +// .point_to_buffer_offset(point, cx) +// .unwrap() +// .1 +// .to_point_utf16(&buffer.read(cx)), +// ) +// }) +// } - pub fn update_workspace(&mut self, update: F) -> T - where - F: FnOnce(&mut Workspace, &mut ViewContext) -> T, - { - self.workspace.update(self.cx.cx, update) - } +// pub fn update_workspace(&mut self, update: F) -> T +// where +// F: FnOnce(&mut Workspace, &mut ViewContext) -> T, +// { +// self.workspace.update(self.cx.cx, update) +// } - pub fn handle_request( - &self, - mut handler: F, - ) -> futures::channel::mpsc::UnboundedReceiver<()> - where - T: 'static + request::Request, - T::Params: 'static + Send, - F: 'static + Send + FnMut(lsp::Url, T::Params, gpui::AsyncAppContext) -> Fut, - Fut: 'static + Send + Future>, - { - let url = self.buffer_lsp_url.clone(); - self.lsp.handle_request::(move |params, cx| { - let url = url.clone(); - handler(url, params, cx) - }) - } +// pub fn handle_request( +// &self, +// mut handler: F, +// ) -> futures::channel::mpsc::UnboundedReceiver<()> +// where +// T: 'static + request::Request, +// T::Params: 'static + Send, +// F: 'static + Send + FnMut(lsp::Url, T::Params, gpui::AsyncAppContext) -> Fut, +// Fut: 'static + Send + Future>, +// { +// let url = self.buffer_lsp_url.clone(); +// self.lsp.handle_request::(move |params, cx| { +// let url = url.clone(); +// handler(url, params, cx) +// }) +// } - pub fn notify(&self, params: T::Params) { - self.lsp.notify::(params); - } -} +// pub fn notify(&self, params: T::Params) { +// self.lsp.notify::(params); +// } +// } -impl<'a> Deref for EditorLspTestContext<'a> { - type Target = EditorTestContext<'a>; +// impl<'a> Deref for EditorLspTestContext<'a> { +// type Target = EditorTestContext<'a>; - fn deref(&self) -> &Self::Target { - &self.cx - } -} +// fn deref(&self) -> &Self::Target { +// &self.cx +// } +// } -impl<'a> DerefMut for EditorLspTestContext<'a> { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.cx - } -} +// impl<'a> DerefMut for EditorLspTestContext<'a> { +// fn deref_mut(&mut self) -> &mut Self::Target { +// &mut self.cx +// } +// } diff --git a/crates/editor2/src/test/editor_test_context.rs b/crates/editor2/src/test/editor_test_context.rs index 0ca043462e..4bf32d0613 100644 --- a/crates/editor2/src/test/editor_test_context.rs +++ b/crates/editor2/src/test/editor_test_context.rs @@ -315,17 +315,17 @@ use util::{ // } // } // } +// +// impl<'a> Deref for EditorTestContext<'a> { +// type Target = gpui::TestAppContext; -impl<'a> Deref for EditorTestContext<'a> { - type Target = gpui::TestAppContext; +// fn deref(&self) -> &Self::Target { +// self.cx +// } +// } - fn deref(&self) -> &Self::Target { - self.cx - } -} - -impl<'a> DerefMut for EditorTestContext<'a> { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.cx - } -} +// impl<'a> DerefMut for EditorTestContext<'a> { +// fn deref_mut(&mut self) -> &mut Self::Target { +// &mut self.cx +// } +// } diff --git a/crates/gpui2/src/geometry.rs b/crates/gpui2/src/geometry.rs index 7d4073144c..468bc1e5b7 100644 --- a/crates/gpui2/src/geometry.rs +++ b/crates/gpui2/src/geometry.rs @@ -755,6 +755,10 @@ impl Pixels { pub fn pow(&self, exponent: f32) -> Self { Self(self.0.powf(exponent)) } + + pub fn abs(&self) -> Self { + Self(self.0.abs()) + } } impl Mul for Pixels { diff --git a/crates/workspace2/src/item.rs b/crates/workspace2/src/item.rs index c2d5c25781..309cf96615 100644 --- a/crates/workspace2/src/item.rs +++ b/crates/workspace2/src/item.rs @@ -90,7 +90,7 @@ pub struct BreadcrumbText { pub highlights: Option, HighlightStyle)>>, } -pub trait Item: Render + EventEmitter + Send { +pub trait Item: Render + EventEmitter { fn deactivated(&mut self, _: &mut ViewContext) {} fn workspace_deactivated(&mut self, _: &mut ViewContext) {} fn navigate(&mut self, _: Box, _: &mut ViewContext) -> bool {