editor.rs

   1#![allow(rustdoc::private_intra_doc_links)]
   2//! This is the place where everything editor-related is stored (data-wise) and displayed (ui-wise).
   3//! The main point of interest in this crate is [`Editor`] type, which is used in every other Zed part as a user input element.
   4//! It comes in different flavors: single line, multiline and a fixed height one.
   5//!
   6//! Editor contains of multiple large submodules:
   7//! * [`element`] — the place where all rendering happens
   8//! * [`display_map`] - chunks up text in the editor into the logical blocks, establishes coordinates and mapping between each of them.
   9//!   Contains all metadata related to text transformations (folds, fake inlay text insertions, soft wraps, tab markup, etc.).
  10//! * [`inlay_hint_cache`] - is a storage of inlay hints out of LSP requests, responsible for querying LSP and updating `display_map`'s state accordingly.
  11//!
  12//! All other submodules and structs are mostly concerned with holding editor data about the way it displays current buffer region(s).
  13//!
  14//! If you're looking to improve Vim mode, you should check out Vim crate that wraps Editor and overrides it's behaviour.
  15pub mod actions;
  16mod blink_manager;
  17pub mod display_map;
  18mod editor_settings;
  19mod element;
  20mod inlay_hint_cache;
  21
  22mod git;
  23mod highlight_matching_bracket;
  24mod hover_popover;
  25pub mod items;
  26mod link_go_to_definition;
  27mod mouse_context_menu;
  28pub mod movement;
  29mod persistence;
  30mod rust_analyzer_ext;
  31pub mod scroll;
  32mod selections_collection;
  33
  34#[cfg(test)]
  35mod editor_tests;
  36#[cfg(any(test, feature = "test-support"))]
  37pub mod test;
  38use ::git::diff::DiffHunk;
  39pub(crate) use actions::*;
  40use aho_corasick::AhoCorasick;
  41use anyhow::{anyhow, Context as _, Result};
  42use blink_manager::BlinkManager;
  43use client::{Collaborator, ParticipantIndex};
  44use clock::ReplicaId;
  45use collections::{BTreeMap, Bound, HashMap, HashSet, VecDeque};
  46use convert_case::{Case, Casing};
  47use copilot::Copilot;
  48pub use display_map::DisplayPoint;
  49use display_map::*;
  50pub use editor_settings::EditorSettings;
  51use element::LineWithInvisibles;
  52pub use element::{Cursor, EditorElement, HighlightedRange, HighlightedRangeLine};
  53use futures::FutureExt;
  54use fuzzy::{StringMatch, StringMatchCandidate};
  55use git::diff_hunk_to_display;
  56use gpui::{
  57    div, impl_actions, point, prelude::*, px, relative, rems, size, uniform_list, Action,
  58    AnyElement, AppContext, AsyncWindowContext, BackgroundExecutor, Bounds, ClipboardItem, Context,
  59    DispatchPhase, ElementId, EventEmitter, FocusHandle, FocusableView, FontId, FontStyle,
  60    FontWeight, HighlightStyle, Hsla, InteractiveText, KeyContext, Model, MouseButton,
  61    ParentElement, Pixels, Render, SharedString, Styled, StyledText, Subscription, Task, TextStyle,
  62    UniformListScrollHandle, View, ViewContext, ViewInputHandler, VisualContext, WeakView,
  63    WhiteSpace, WindowContext,
  64};
  65use highlight_matching_bracket::refresh_matching_bracket_highlights;
  66use hover_popover::{hide_hover, HoverState};
  67use inlay_hint_cache::{InlayHintCache, InlaySplice, InvalidationStrategy};
  68pub use items::MAX_TAB_TITLE_LEN;
  69use itertools::Itertools;
  70use language::{char_kind, CharKind};
  71use language::{
  72    language_settings::{self, all_language_settings, InlayHintSettings},
  73    markdown, point_from_lsp, AutoindentMode, BracketPair, Buffer, Capability, CodeAction,
  74    CodeLabel, Completion, CursorShape, Diagnostic, Documentation, IndentKind, IndentSize,
  75    Language, LanguageServerName, OffsetRangeExt, Point, Selection, SelectionGoal, TransactionId,
  76};
  77
  78use link_go_to_definition::{GoToDefinitionLink, InlayHighlight, LinkGoToDefinitionState};
  79use lsp::{DiagnosticSeverity, LanguageServerId};
  80use mouse_context_menu::MouseContextMenu;
  81use movement::TextLayoutDetails;
  82use multi_buffer::ToOffsetUtf16;
  83pub use multi_buffer::{
  84    Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, ToOffset,
  85    ToPoint,
  86};
  87use ordered_float::OrderedFloat;
  88use parking_lot::RwLock;
  89use project::{FormatTrigger, Location, Project, ProjectPath, ProjectTransaction};
  90use rand::prelude::*;
  91use rpc::proto::*;
  92use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager, ScrollbarAutoHide};
  93use selections_collection::{resolve_multiple, MutableSelectionsCollection, SelectionsCollection};
  94use serde::{Deserialize, Serialize};
  95use settings::{Settings, SettingsStore};
  96use smallvec::SmallVec;
  97use snippet::Snippet;
  98use std::{
  99    any::TypeId,
 100    borrow::Cow,
 101    cmp::{self, Ordering, Reverse},
 102    mem,
 103    num::NonZeroU32,
 104    ops::{ControlFlow, Deref, DerefMut, Range, RangeInclusive},
 105    path::Path,
 106    sync::Arc,
 107    sync::Weak,
 108    time::{Duration, Instant},
 109};
 110pub use sum_tree::Bias;
 111use sum_tree::TreeMap;
 112use text::{OffsetUtf16, Rope};
 113use theme::{
 114    observe_buffer_font_size_adjustment, ActiveTheme, PlayerColor, StatusColors, SyntaxTheme,
 115    ThemeColors, ThemeSettings,
 116};
 117use ui::{
 118    h_flex, prelude::*, ButtonSize, ButtonStyle, IconButton, IconName, IconSize, ListItem, Popover,
 119    Tooltip,
 120};
 121use util::{post_inc, RangeExt, ResultExt, TryFutureExt};
 122use workspace::{searchable::SearchEvent, ItemNavHistory, Pane, SplitDirection, ViewId, Workspace};
 123
 124const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
 125const MAX_LINE_LEN: usize = 1024;
 126const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
 127const MAX_SELECTION_HISTORY_LEN: usize = 1024;
 128const COPILOT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(75);
 129pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
 130#[doc(hidden)]
 131pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
 132#[doc(hidden)]
 133pub const DOCUMENT_HIGHLIGHTS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(75);
 134
 135pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(2);
 136
 137pub fn render_parsed_markdown(
 138    element_id: impl Into<ElementId>,
 139    parsed: &language::ParsedMarkdown,
 140    editor_style: &EditorStyle,
 141    workspace: Option<WeakView<Workspace>>,
 142    cx: &mut ViewContext<Editor>,
 143) -> InteractiveText {
 144    let code_span_background_color = cx
 145        .theme()
 146        .colors()
 147        .editor_document_highlight_read_background;
 148
 149    let highlights = gpui::combine_highlights(
 150        parsed.highlights.iter().filter_map(|(range, highlight)| {
 151            let highlight = highlight.to_highlight_style(&editor_style.syntax)?;
 152            Some((range.clone(), highlight))
 153        }),
 154        parsed
 155            .regions
 156            .iter()
 157            .zip(&parsed.region_ranges)
 158            .filter_map(|(region, range)| {
 159                if region.code {
 160                    Some((
 161                        range.clone(),
 162                        HighlightStyle {
 163                            background_color: Some(code_span_background_color),
 164                            ..Default::default()
 165                        },
 166                    ))
 167                } else {
 168                    None
 169                }
 170            }),
 171    );
 172
 173    let mut links = Vec::new();
 174    let mut link_ranges = Vec::new();
 175    for (range, region) in parsed.region_ranges.iter().zip(&parsed.regions) {
 176        if let Some(link) = region.link.clone() {
 177            links.push(link);
 178            link_ranges.push(range.clone());
 179        }
 180    }
 181
 182    InteractiveText::new(
 183        element_id,
 184        StyledText::new(parsed.text.clone()).with_highlights(&editor_style.text, highlights),
 185    )
 186    .on_click(link_ranges, move |clicked_range_ix, cx| {
 187        match &links[clicked_range_ix] {
 188            markdown::Link::Web { url } => cx.open_url(url),
 189            markdown::Link::Path { path } => {
 190                if let Some(workspace) = &workspace {
 191                    _ = workspace.update(cx, |workspace, cx| {
 192                        workspace.open_abs_path(path.clone(), false, cx).detach();
 193                    });
 194                }
 195            }
 196        }
 197    })
 198}
 199
 200#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
 201pub(crate) enum InlayId {
 202    Suggestion(usize),
 203    Hint(usize),
 204}
 205
 206impl InlayId {
 207    fn id(&self) -> usize {
 208        match self {
 209            Self::Suggestion(id) => *id,
 210            Self::Hint(id) => *id,
 211        }
 212    }
 213}
 214
 215enum DocumentHighlightRead {}
 216enum DocumentHighlightWrite {}
 217enum InputComposition {}
 218
 219#[derive(Copy, Clone, PartialEq, Eq)]
 220pub enum Direction {
 221    Prev,
 222    Next,
 223}
 224
 225pub fn init_settings(cx: &mut AppContext) {
 226    EditorSettings::register(cx);
 227}
 228
 229pub fn init(cx: &mut AppContext) {
 230    init_settings(cx);
 231
 232    workspace::register_project_item::<Editor>(cx);
 233    workspace::register_followable_item::<Editor>(cx);
 234    workspace::register_deserializable_item::<Editor>(cx);
 235    cx.observe_new_views(
 236        |workspace: &mut Workspace, _cx: &mut ViewContext<Workspace>| {
 237            workspace.register_action(Editor::new_file);
 238            workspace.register_action(Editor::new_file_in_direction);
 239        },
 240    )
 241    .detach();
 242
 243    cx.on_action(move |_: &workspace::NewFile, cx| {
 244        let app_state = cx.global::<Weak<workspace::AppState>>();
 245        if let Some(app_state) = app_state.upgrade() {
 246            workspace::open_new(&app_state, cx, |workspace, cx| {
 247                Editor::new_file(workspace, &Default::default(), cx)
 248            })
 249            .detach();
 250        }
 251    });
 252    cx.on_action(move |_: &workspace::NewWindow, cx| {
 253        let app_state = cx.global::<Weak<workspace::AppState>>();
 254        if let Some(app_state) = app_state.upgrade() {
 255            workspace::open_new(&app_state, cx, |workspace, cx| {
 256                Editor::new_file(workspace, &Default::default(), cx)
 257            })
 258            .detach();
 259        }
 260    });
 261}
 262
 263trait InvalidationRegion {
 264    fn ranges(&self) -> &[Range<Anchor>];
 265}
 266
 267#[derive(Clone, Debug, PartialEq)]
 268pub enum SelectPhase {
 269    Begin {
 270        position: DisplayPoint,
 271        add: bool,
 272        click_count: usize,
 273    },
 274    BeginColumnar {
 275        position: DisplayPoint,
 276        goal_column: u32,
 277    },
 278    Extend {
 279        position: DisplayPoint,
 280        click_count: usize,
 281    },
 282    Update {
 283        position: DisplayPoint,
 284        goal_column: u32,
 285        scroll_delta: gpui::Point<f32>,
 286    },
 287    End,
 288}
 289
 290#[derive(Clone, Debug)]
 291pub(crate) enum SelectMode {
 292    Character,
 293    Word(Range<Anchor>),
 294    Line(Range<Anchor>),
 295    All,
 296}
 297
 298#[derive(Copy, Clone, PartialEq, Eq, Debug)]
 299pub enum EditorMode {
 300    SingleLine,
 301    AutoHeight { max_lines: usize },
 302    Full,
 303}
 304
 305#[derive(Clone, Debug)]
 306pub enum SoftWrap {
 307    None,
 308    EditorWidth,
 309    Column(u32),
 310}
 311
 312#[derive(Clone)]
 313pub struct EditorStyle {
 314    pub background: Hsla,
 315    pub local_player: PlayerColor,
 316    pub text: TextStyle,
 317    pub scrollbar_width: Pixels,
 318    pub syntax: Arc<SyntaxTheme>,
 319    pub status: StatusColors,
 320    pub inlays_style: HighlightStyle,
 321    pub suggestions_style: HighlightStyle,
 322}
 323
 324impl Default for EditorStyle {
 325    fn default() -> Self {
 326        Self {
 327            background: Hsla::default(),
 328            local_player: PlayerColor::default(),
 329            text: TextStyle::default(),
 330            scrollbar_width: Pixels::default(),
 331            syntax: Default::default(),
 332            // HACK: Status colors don't have a real default.
 333            // We should look into removing the status colors from the editor
 334            // style and retrieve them directly from the theme.
 335            status: StatusColors::dark(),
 336            inlays_style: HighlightStyle::default(),
 337            suggestions_style: HighlightStyle::default(),
 338        }
 339    }
 340}
 341
 342type CompletionId = usize;
 343
 344// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
 345// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
 346
 347type BackgroundHighlight = (fn(&ThemeColors) -> Hsla, Vec<Range<Anchor>>);
 348type InlayBackgroundHighlight = (fn(&ThemeColors) -> Hsla, Vec<InlayHighlight>);
 349
 350pub struct Editor {
 351    handle: WeakView<Self>,
 352    focus_handle: FocusHandle,
 353    buffer: Model<MultiBuffer>,
 354    display_map: Model<DisplayMap>,
 355    pub selections: SelectionsCollection,
 356    pub scroll_manager: ScrollManager,
 357    columnar_selection_tail: Option<Anchor>,
 358    add_selections_state: Option<AddSelectionsState>,
 359    select_next_state: Option<SelectNextState>,
 360    select_prev_state: Option<SelectNextState>,
 361    selection_history: SelectionHistory,
 362    autoclose_regions: Vec<AutocloseRegion>,
 363    snippet_stack: InvalidationStack<SnippetState>,
 364    select_larger_syntax_node_stack: Vec<Box<[Selection<usize>]>>,
 365    ime_transaction: Option<TransactionId>,
 366    active_diagnostics: Option<ActiveDiagnosticGroup>,
 367    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
 368    project: Option<Model<Project>>,
 369    completion_provider: Option<Box<dyn CompletionProvider>>,
 370    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 371    blink_manager: Model<BlinkManager>,
 372    show_cursor_names: bool,
 373    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 374    pub show_local_selections: bool,
 375    mode: EditorMode,
 376    show_gutter: bool,
 377    show_wrap_guides: Option<bool>,
 378    placeholder_text: Option<Arc<str>>,
 379    highlighted_rows: Option<Range<u32>>,
 380    background_highlights: BTreeMap<TypeId, BackgroundHighlight>,
 381    inlay_background_highlights: TreeMap<Option<TypeId>, InlayBackgroundHighlight>,
 382    nav_history: Option<ItemNavHistory>,
 383    context_menu: RwLock<Option<ContextMenu>>,
 384    mouse_context_menu: Option<MouseContextMenu>,
 385    completion_tasks: Vec<(CompletionId, Task<Option<()>>)>,
 386    next_completion_id: CompletionId,
 387    available_code_actions: Option<(Model<Buffer>, Arc<[CodeAction]>)>,
 388    code_actions_task: Option<Task<()>>,
 389    document_highlights_task: Option<Task<()>>,
 390    pending_rename: Option<RenameState>,
 391    searchable: bool,
 392    cursor_shape: CursorShape,
 393    collapse_matches: bool,
 394    autoindent_mode: Option<AutoindentMode>,
 395    workspace: Option<(WeakView<Workspace>, i64)>,
 396    keymap_context_layers: BTreeMap<TypeId, KeyContext>,
 397    input_enabled: bool,
 398    read_only: bool,
 399    leader_peer_id: Option<PeerId>,
 400    remote_id: Option<ViewId>,
 401    hover_state: HoverState,
 402    gutter_hovered: bool,
 403    link_go_to_definition_state: LinkGoToDefinitionState,
 404    copilot_state: CopilotState,
 405    inlay_hint_cache: InlayHintCache,
 406    next_inlay_id: usize,
 407    _subscriptions: Vec<Subscription>,
 408    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 409    gutter_width: Pixels,
 410    style: Option<EditorStyle>,
 411    editor_actions: Vec<Box<dyn Fn(&mut ViewContext<Self>)>>,
 412    show_copilot_suggestions: bool,
 413    use_autoclose: bool,
 414}
 415
 416pub struct EditorSnapshot {
 417    pub mode: EditorMode,
 418    show_gutter: bool,
 419    pub display_snapshot: DisplaySnapshot,
 420    pub placeholder_text: Option<Arc<str>>,
 421    is_focused: bool,
 422    scroll_anchor: ScrollAnchor,
 423    ongoing_scroll: OngoingScroll,
 424}
 425
 426pub struct GutterDimensions {
 427    pub padding: Pixels,
 428    pub width: Pixels,
 429    pub margin: Pixels,
 430}
 431
 432impl Default for GutterDimensions {
 433    fn default() -> Self {
 434        Self {
 435            padding: Pixels::ZERO,
 436            width: Pixels::ZERO,
 437            margin: Pixels::ZERO,
 438        }
 439    }
 440}
 441
 442#[derive(Debug)]
 443pub struct RemoteSelection {
 444    pub replica_id: ReplicaId,
 445    pub selection: Selection<Anchor>,
 446    pub cursor_shape: CursorShape,
 447    pub peer_id: PeerId,
 448    pub line_mode: bool,
 449    pub participant_index: Option<ParticipantIndex>,
 450    pub user_name: Option<SharedString>,
 451}
 452
 453#[derive(Clone, Debug)]
 454struct SelectionHistoryEntry {
 455    selections: Arc<[Selection<Anchor>]>,
 456    select_next_state: Option<SelectNextState>,
 457    select_prev_state: Option<SelectNextState>,
 458    add_selections_state: Option<AddSelectionsState>,
 459}
 460
 461enum SelectionHistoryMode {
 462    Normal,
 463    Undoing,
 464    Redoing,
 465}
 466
 467#[derive(Clone, PartialEq, Eq, Hash)]
 468struct HoveredCursor {
 469    replica_id: u16,
 470    selection_id: usize,
 471}
 472
 473impl Default for SelectionHistoryMode {
 474    fn default() -> Self {
 475        Self::Normal
 476    }
 477}
 478
 479#[derive(Default)]
 480struct SelectionHistory {
 481    #[allow(clippy::type_complexity)]
 482    selections_by_transaction:
 483        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 484    mode: SelectionHistoryMode,
 485    undo_stack: VecDeque<SelectionHistoryEntry>,
 486    redo_stack: VecDeque<SelectionHistoryEntry>,
 487}
 488
 489impl SelectionHistory {
 490    fn insert_transaction(
 491        &mut self,
 492        transaction_id: TransactionId,
 493        selections: Arc<[Selection<Anchor>]>,
 494    ) {
 495        self.selections_by_transaction
 496            .insert(transaction_id, (selections, None));
 497    }
 498
 499    #[allow(clippy::type_complexity)]
 500    fn transaction(
 501        &self,
 502        transaction_id: TransactionId,
 503    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 504        self.selections_by_transaction.get(&transaction_id)
 505    }
 506
 507    #[allow(clippy::type_complexity)]
 508    fn transaction_mut(
 509        &mut self,
 510        transaction_id: TransactionId,
 511    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 512        self.selections_by_transaction.get_mut(&transaction_id)
 513    }
 514
 515    fn push(&mut self, entry: SelectionHistoryEntry) {
 516        if !entry.selections.is_empty() {
 517            match self.mode {
 518                SelectionHistoryMode::Normal => {
 519                    self.push_undo(entry);
 520                    self.redo_stack.clear();
 521                }
 522                SelectionHistoryMode::Undoing => self.push_redo(entry),
 523                SelectionHistoryMode::Redoing => self.push_undo(entry),
 524            }
 525        }
 526    }
 527
 528    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 529        if self
 530            .undo_stack
 531            .back()
 532            .map_or(true, |e| e.selections != entry.selections)
 533        {
 534            self.undo_stack.push_back(entry);
 535            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 536                self.undo_stack.pop_front();
 537            }
 538        }
 539    }
 540
 541    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 542        if self
 543            .redo_stack
 544            .back()
 545            .map_or(true, |e| e.selections != entry.selections)
 546        {
 547            self.redo_stack.push_back(entry);
 548            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 549                self.redo_stack.pop_front();
 550            }
 551        }
 552    }
 553}
 554
 555#[derive(Clone, Debug)]
 556struct AddSelectionsState {
 557    above: bool,
 558    stack: Vec<usize>,
 559}
 560
 561#[derive(Clone)]
 562struct SelectNextState {
 563    query: AhoCorasick,
 564    wordwise: bool,
 565    done: bool,
 566}
 567
 568impl std::fmt::Debug for SelectNextState {
 569    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 570        f.debug_struct(std::any::type_name::<Self>())
 571            .field("wordwise", &self.wordwise)
 572            .field("done", &self.done)
 573            .finish()
 574    }
 575}
 576
 577#[derive(Debug)]
 578struct AutocloseRegion {
 579    selection_id: usize,
 580    range: Range<Anchor>,
 581    pair: BracketPair,
 582}
 583
 584#[derive(Debug)]
 585struct SnippetState {
 586    ranges: Vec<Vec<Range<Anchor>>>,
 587    active_index: usize,
 588}
 589
 590#[doc(hidden)]
 591pub struct RenameState {
 592    pub range: Range<Anchor>,
 593    pub old_name: Arc<str>,
 594    pub editor: View<Editor>,
 595    block_id: BlockId,
 596}
 597
 598struct InvalidationStack<T>(Vec<T>);
 599
 600enum ContextMenu {
 601    Completions(CompletionsMenu),
 602    CodeActions(CodeActionsMenu),
 603}
 604
 605impl ContextMenu {
 606    fn select_first(
 607        &mut self,
 608        project: Option<&Model<Project>>,
 609        cx: &mut ViewContext<Editor>,
 610    ) -> bool {
 611        if self.visible() {
 612            match self {
 613                ContextMenu::Completions(menu) => menu.select_first(project, cx),
 614                ContextMenu::CodeActions(menu) => menu.select_first(cx),
 615            }
 616            true
 617        } else {
 618            false
 619        }
 620    }
 621
 622    fn select_prev(
 623        &mut self,
 624        project: Option<&Model<Project>>,
 625        cx: &mut ViewContext<Editor>,
 626    ) -> bool {
 627        if self.visible() {
 628            match self {
 629                ContextMenu::Completions(menu) => menu.select_prev(project, cx),
 630                ContextMenu::CodeActions(menu) => menu.select_prev(cx),
 631            }
 632            true
 633        } else {
 634            false
 635        }
 636    }
 637
 638    fn select_next(
 639        &mut self,
 640        project: Option<&Model<Project>>,
 641        cx: &mut ViewContext<Editor>,
 642    ) -> bool {
 643        if self.visible() {
 644            match self {
 645                ContextMenu::Completions(menu) => menu.select_next(project, cx),
 646                ContextMenu::CodeActions(menu) => menu.select_next(cx),
 647            }
 648            true
 649        } else {
 650            false
 651        }
 652    }
 653
 654    fn select_last(
 655        &mut self,
 656        project: Option<&Model<Project>>,
 657        cx: &mut ViewContext<Editor>,
 658    ) -> bool {
 659        if self.visible() {
 660            match self {
 661                ContextMenu::Completions(menu) => menu.select_last(project, cx),
 662                ContextMenu::CodeActions(menu) => menu.select_last(cx),
 663            }
 664            true
 665        } else {
 666            false
 667        }
 668    }
 669
 670    fn visible(&self) -> bool {
 671        match self {
 672            ContextMenu::Completions(menu) => menu.visible(),
 673            ContextMenu::CodeActions(menu) => menu.visible(),
 674        }
 675    }
 676
 677    fn render(
 678        &self,
 679        cursor_position: DisplayPoint,
 680        style: &EditorStyle,
 681        max_height: Pixels,
 682        workspace: Option<WeakView<Workspace>>,
 683        cx: &mut ViewContext<Editor>,
 684    ) -> (DisplayPoint, AnyElement) {
 685        match self {
 686            ContextMenu::Completions(menu) => (
 687                cursor_position,
 688                menu.render(style, max_height, workspace, cx),
 689            ),
 690            ContextMenu::CodeActions(menu) => menu.render(cursor_position, style, max_height, cx),
 691        }
 692    }
 693}
 694
 695#[derive(Clone)]
 696struct CompletionsMenu {
 697    id: CompletionId,
 698    initial_position: Anchor,
 699    buffer: Model<Buffer>,
 700    completions: Arc<RwLock<Box<[Completion]>>>,
 701    match_candidates: Arc<[StringMatchCandidate]>,
 702    matches: Arc<[StringMatch]>,
 703    selected_item: usize,
 704    scroll_handle: UniformListScrollHandle,
 705}
 706
 707impl CompletionsMenu {
 708    fn select_first(&mut self, project: Option<&Model<Project>>, cx: &mut ViewContext<Editor>) {
 709        self.selected_item = 0;
 710        self.scroll_handle.scroll_to_item(self.selected_item);
 711        self.attempt_resolve_selected_completion_documentation(project, cx);
 712        cx.notify();
 713    }
 714
 715    fn select_prev(&mut self, project: Option<&Model<Project>>, cx: &mut ViewContext<Editor>) {
 716        if self.selected_item > 0 {
 717            self.selected_item -= 1;
 718        } else {
 719            self.selected_item = self.matches.len() - 1;
 720        }
 721        self.scroll_handle.scroll_to_item(self.selected_item);
 722        self.attempt_resolve_selected_completion_documentation(project, cx);
 723        cx.notify();
 724    }
 725
 726    fn select_next(&mut self, project: Option<&Model<Project>>, cx: &mut ViewContext<Editor>) {
 727        if self.selected_item + 1 < self.matches.len() {
 728            self.selected_item += 1;
 729        } else {
 730            self.selected_item = 0;
 731        }
 732        self.scroll_handle.scroll_to_item(self.selected_item);
 733        self.attempt_resolve_selected_completion_documentation(project, cx);
 734        cx.notify();
 735    }
 736
 737    fn select_last(&mut self, project: Option<&Model<Project>>, cx: &mut ViewContext<Editor>) {
 738        self.selected_item = self.matches.len() - 1;
 739        self.scroll_handle.scroll_to_item(self.selected_item);
 740        self.attempt_resolve_selected_completion_documentation(project, cx);
 741        cx.notify();
 742    }
 743
 744    fn pre_resolve_completion_documentation(
 745        &self,
 746        editor: &Editor,
 747        cx: &mut ViewContext<Editor>,
 748    ) -> Option<Task<()>> {
 749        let settings = EditorSettings::get_global(cx);
 750        if !settings.show_completion_documentation {
 751            return None;
 752        }
 753
 754        let Some(provider) = editor.completion_provider.as_ref() else {
 755            return None;
 756        };
 757
 758        let resolve_task = provider.resolve_completions(
 759            self.matches.iter().map(|m| m.candidate_id).collect(),
 760            self.completions.clone(),
 761            cx,
 762        );
 763
 764        return Some(cx.spawn(move |this, mut cx| async move {
 765            if let Some(true) = resolve_task.await.log_err() {
 766                this.update(&mut cx, |_, cx| cx.notify()).ok();
 767            }
 768        }));
 769    }
 770
 771    fn attempt_resolve_selected_completion_documentation(
 772        &mut self,
 773        project: Option<&Model<Project>>,
 774        cx: &mut ViewContext<Editor>,
 775    ) {
 776        let settings = EditorSettings::get_global(cx);
 777        if !settings.show_completion_documentation {
 778            return;
 779        }
 780
 781        let completion_index = self.matches[self.selected_item].candidate_id;
 782        let Some(project) = project else {
 783            return;
 784        };
 785
 786        let resolve_task = project.update(cx, |project, cx| {
 787            project.resolve_completions(vec![completion_index], self.completions.clone(), cx)
 788        });
 789        cx.spawn(move |this, mut cx| async move {
 790            if let Some(true) = resolve_task.await.log_err() {
 791                this.update(&mut cx, |_, cx| cx.notify()).ok();
 792            }
 793        })
 794        .detach();
 795    }
 796
 797    fn visible(&self) -> bool {
 798        !self.matches.is_empty()
 799    }
 800
 801    fn render(
 802        &self,
 803        style: &EditorStyle,
 804        max_height: Pixels,
 805        workspace: Option<WeakView<Workspace>>,
 806        cx: &mut ViewContext<Editor>,
 807    ) -> AnyElement {
 808        let settings = EditorSettings::get_global(cx);
 809        let show_completion_documentation = settings.show_completion_documentation;
 810
 811        let widest_completion_ix = self
 812            .matches
 813            .iter()
 814            .enumerate()
 815            .max_by_key(|(_, mat)| {
 816                let completions = self.completions.read();
 817                let completion = &completions[mat.candidate_id];
 818                let documentation = &completion.documentation;
 819
 820                let mut len = completion.label.text.chars().count();
 821                if let Some(Documentation::SingleLine(text)) = documentation {
 822                    if show_completion_documentation {
 823                        len += text.chars().count();
 824                    }
 825                }
 826
 827                len
 828            })
 829            .map(|(ix, _)| ix);
 830
 831        let completions = self.completions.clone();
 832        let matches = self.matches.clone();
 833        let selected_item = self.selected_item;
 834        let style = style.clone();
 835
 836        let multiline_docs = {
 837            let mat = &self.matches[selected_item];
 838            let multiline_docs = match &self.completions.read()[mat.candidate_id].documentation {
 839                Some(Documentation::MultiLinePlainText(text)) => {
 840                    Some(div().child(SharedString::from(text.clone())))
 841                }
 842                Some(Documentation::MultiLineMarkdown(parsed)) => Some(div().child(
 843                    render_parsed_markdown("completions_markdown", parsed, &style, workspace, cx),
 844                )),
 845                _ => None,
 846            };
 847            multiline_docs.map(|div| {
 848                div.id("multiline_docs")
 849                    .max_h(max_height)
 850                    .flex_1()
 851                    .px_1p5()
 852                    .py_1()
 853                    .min_w(px(260.))
 854                    .max_w(px(640.))
 855                    .w(px(500.))
 856                    .overflow_y_scroll()
 857                    // Prevent a mouse down on documentation from being propagated to the editor,
 858                    // because that would move the cursor.
 859                    .on_mouse_down(MouseButton::Left, |_, cx| cx.stop_propagation())
 860            })
 861        };
 862
 863        let list = uniform_list(
 864            cx.view().clone(),
 865            "completions",
 866            matches.len(),
 867            move |_editor, range, cx| {
 868                let start_ix = range.start;
 869                let completions_guard = completions.read();
 870
 871                matches[range]
 872                    .iter()
 873                    .enumerate()
 874                    .map(|(ix, mat)| {
 875                        let item_ix = start_ix + ix;
 876                        let candidate_id = mat.candidate_id;
 877                        let completion = &completions_guard[candidate_id];
 878
 879                        let documentation = if show_completion_documentation {
 880                            &completion.documentation
 881                        } else {
 882                            &None
 883                        };
 884
 885                        let highlights = gpui::combine_highlights(
 886                            mat.ranges().map(|range| (range, FontWeight::BOLD.into())),
 887                            styled_runs_for_code_label(&completion.label, &style.syntax).map(
 888                                |(range, mut highlight)| {
 889                                    // Ignore font weight for syntax highlighting, as we'll use it
 890                                    // for fuzzy matches.
 891                                    highlight.font_weight = None;
 892                                    (range, highlight)
 893                                },
 894                            ),
 895                        );
 896                        let completion_label = StyledText::new(completion.label.text.clone())
 897                            .with_highlights(&style.text, highlights);
 898                        let documentation_label =
 899                            if let Some(Documentation::SingleLine(text)) = documentation {
 900                                if text.trim().is_empty() {
 901                                    None
 902                                } else {
 903                                    Some(
 904                                        h_flex().ml_4().child(
 905                                            Label::new(text.clone())
 906                                                .size(LabelSize::Small)
 907                                                .color(Color::Muted),
 908                                        ),
 909                                    )
 910                                }
 911                            } else {
 912                                None
 913                            };
 914
 915                        div().min_w(px(220.)).max_w(px(540.)).child(
 916                            ListItem::new(mat.candidate_id)
 917                                .inset(true)
 918                                .selected(item_ix == selected_item)
 919                                .on_click(cx.listener(move |editor, _event, cx| {
 920                                    cx.stop_propagation();
 921                                    editor
 922                                        .confirm_completion(
 923                                            &ConfirmCompletion {
 924                                                item_ix: Some(item_ix),
 925                                            },
 926                                            cx,
 927                                        )
 928                                        .map(|task| task.detach_and_log_err(cx));
 929                                }))
 930                                .child(h_flex().overflow_hidden().child(completion_label))
 931                                .end_slot::<Div>(documentation_label),
 932                        )
 933                    })
 934                    .collect()
 935            },
 936        )
 937        .max_h(max_height)
 938        .track_scroll(self.scroll_handle.clone())
 939        .with_width_from_item(widest_completion_ix);
 940
 941        Popover::new()
 942            .child(list)
 943            .when_some(multiline_docs, |popover, multiline_docs| {
 944                popover.aside(multiline_docs)
 945            })
 946            .into_any_element()
 947    }
 948
 949    pub async fn filter(&mut self, query: Option<&str>, executor: BackgroundExecutor) {
 950        let mut matches = if let Some(query) = query {
 951            fuzzy::match_strings(
 952                &self.match_candidates,
 953                query,
 954                query.chars().any(|c| c.is_uppercase()),
 955                100,
 956                &Default::default(),
 957                executor,
 958            )
 959            .await
 960        } else {
 961            self.match_candidates
 962                .iter()
 963                .enumerate()
 964                .map(|(candidate_id, candidate)| StringMatch {
 965                    candidate_id,
 966                    score: Default::default(),
 967                    positions: Default::default(),
 968                    string: candidate.string.clone(),
 969                })
 970                .collect()
 971        };
 972
 973        // Remove all candidates where the query's start does not match the start of any word in the candidate
 974        if let Some(query) = query {
 975            if let Some(query_start) = query.chars().next() {
 976                matches.retain(|string_match| {
 977                    split_words(&string_match.string).any(|word| {
 978                        // Check that the first codepoint of the word as lowercase matches the first
 979                        // codepoint of the query as lowercase
 980                        word.chars()
 981                            .flat_map(|codepoint| codepoint.to_lowercase())
 982                            .zip(query_start.to_lowercase())
 983                            .all(|(word_cp, query_cp)| word_cp == query_cp)
 984                    })
 985                });
 986            }
 987        }
 988
 989        let completions = self.completions.read();
 990        matches.sort_unstable_by_key(|mat| {
 991            let completion = &completions[mat.candidate_id];
 992            (
 993                completion.lsp_completion.sort_text.as_ref(),
 994                Reverse(OrderedFloat(mat.score)),
 995                completion.sort_key(),
 996            )
 997        });
 998
 999        for mat in &mut matches {
1000            let completion = &completions[mat.candidate_id];
1001            mat.string = completion.label.text.clone();
1002            for position in &mut mat.positions {
1003                *position += completion.label.filter_range.start;
1004            }
1005        }
1006        drop(completions);
1007
1008        self.matches = matches.into();
1009        self.selected_item = 0;
1010    }
1011}
1012
1013#[derive(Clone)]
1014struct CodeActionsMenu {
1015    actions: Arc<[CodeAction]>,
1016    buffer: Model<Buffer>,
1017    selected_item: usize,
1018    scroll_handle: UniformListScrollHandle,
1019    deployed_from_indicator: bool,
1020}
1021
1022impl CodeActionsMenu {
1023    fn select_first(&mut self, cx: &mut ViewContext<Editor>) {
1024        self.selected_item = 0;
1025        self.scroll_handle.scroll_to_item(self.selected_item);
1026        cx.notify()
1027    }
1028
1029    fn select_prev(&mut self, cx: &mut ViewContext<Editor>) {
1030        if self.selected_item > 0 {
1031            self.selected_item -= 1;
1032        } else {
1033            self.selected_item = self.actions.len() - 1;
1034        }
1035        self.scroll_handle.scroll_to_item(self.selected_item);
1036        cx.notify();
1037    }
1038
1039    fn select_next(&mut self, cx: &mut ViewContext<Editor>) {
1040        if self.selected_item + 1 < self.actions.len() {
1041            self.selected_item += 1;
1042        } else {
1043            self.selected_item = 0;
1044        }
1045        self.scroll_handle.scroll_to_item(self.selected_item);
1046        cx.notify();
1047    }
1048
1049    fn select_last(&mut self, cx: &mut ViewContext<Editor>) {
1050        self.selected_item = self.actions.len() - 1;
1051        self.scroll_handle.scroll_to_item(self.selected_item);
1052        cx.notify()
1053    }
1054
1055    fn visible(&self) -> bool {
1056        !self.actions.is_empty()
1057    }
1058
1059    fn render(
1060        &self,
1061        mut cursor_position: DisplayPoint,
1062        _style: &EditorStyle,
1063        max_height: Pixels,
1064        cx: &mut ViewContext<Editor>,
1065    ) -> (DisplayPoint, AnyElement) {
1066        let actions = self.actions.clone();
1067        let selected_item = self.selected_item;
1068
1069        let element = uniform_list(
1070            cx.view().clone(),
1071            "code_actions_menu",
1072            self.actions.len(),
1073            move |_this, range, cx| {
1074                actions[range.clone()]
1075                    .iter()
1076                    .enumerate()
1077                    .map(|(ix, action)| {
1078                        let item_ix = range.start + ix;
1079                        let selected = selected_item == item_ix;
1080                        let colors = cx.theme().colors();
1081                        div()
1082                            .px_2()
1083                            .text_color(colors.text)
1084                            .when(selected, |style| {
1085                                style
1086                                    .bg(colors.element_active)
1087                                    .text_color(colors.text_accent)
1088                            })
1089                            .hover(|style| {
1090                                style
1091                                    .bg(colors.element_hover)
1092                                    .text_color(colors.text_accent)
1093                            })
1094                            .on_mouse_down(
1095                                MouseButton::Left,
1096                                cx.listener(move |editor, _, cx| {
1097                                    cx.stop_propagation();
1098                                    editor
1099                                        .confirm_code_action(
1100                                            &ConfirmCodeAction {
1101                                                item_ix: Some(item_ix),
1102                                            },
1103                                            cx,
1104                                        )
1105                                        .map(|task| task.detach_and_log_err(cx));
1106                                }),
1107                            )
1108                            // TASK: It would be good to make lsp_action.title a SharedString to avoid allocating here.
1109                            .child(SharedString::from(action.lsp_action.title.clone()))
1110                    })
1111                    .collect()
1112            },
1113        )
1114        .elevation_1(cx)
1115        .px_2()
1116        .py_1()
1117        .max_h(max_height)
1118        .track_scroll(self.scroll_handle.clone())
1119        .with_width_from_item(
1120            self.actions
1121                .iter()
1122                .enumerate()
1123                .max_by_key(|(_, action)| action.lsp_action.title.chars().count())
1124                .map(|(ix, _)| ix),
1125        )
1126        .into_any_element();
1127
1128        if self.deployed_from_indicator {
1129            *cursor_position.column_mut() = 0;
1130        }
1131
1132        (cursor_position, element)
1133    }
1134}
1135
1136pub(crate) struct CopilotState {
1137    excerpt_id: Option<ExcerptId>,
1138    pending_refresh: Task<Option<()>>,
1139    pending_cycling_refresh: Task<Option<()>>,
1140    cycled: bool,
1141    completions: Vec<copilot::Completion>,
1142    active_completion_index: usize,
1143    suggestion: Option<Inlay>,
1144}
1145
1146impl Default for CopilotState {
1147    fn default() -> Self {
1148        Self {
1149            excerpt_id: None,
1150            pending_cycling_refresh: Task::ready(Some(())),
1151            pending_refresh: Task::ready(Some(())),
1152            completions: Default::default(),
1153            active_completion_index: 0,
1154            cycled: false,
1155            suggestion: None,
1156        }
1157    }
1158}
1159
1160impl CopilotState {
1161    fn active_completion(&self) -> Option<&copilot::Completion> {
1162        self.completions.get(self.active_completion_index)
1163    }
1164
1165    fn text_for_active_completion(
1166        &self,
1167        cursor: Anchor,
1168        buffer: &MultiBufferSnapshot,
1169    ) -> Option<&str> {
1170        use language::ToOffset as _;
1171
1172        let completion = self.active_completion()?;
1173        let excerpt_id = self.excerpt_id?;
1174        let completion_buffer = buffer.buffer_for_excerpt(excerpt_id)?;
1175        if excerpt_id != cursor.excerpt_id
1176            || !completion.range.start.is_valid(completion_buffer)
1177            || !completion.range.end.is_valid(completion_buffer)
1178        {
1179            return None;
1180        }
1181
1182        let mut completion_range = completion.range.to_offset(&completion_buffer);
1183        let prefix_len = Self::common_prefix(
1184            completion_buffer.chars_for_range(completion_range.clone()),
1185            completion.text.chars(),
1186        );
1187        completion_range.start += prefix_len;
1188        let suffix_len = Self::common_prefix(
1189            completion_buffer.reversed_chars_for_range(completion_range.clone()),
1190            completion.text[prefix_len..].chars().rev(),
1191        );
1192        completion_range.end = completion_range.end.saturating_sub(suffix_len);
1193
1194        if completion_range.is_empty()
1195            && completion_range.start == cursor.text_anchor.to_offset(&completion_buffer)
1196        {
1197            Some(&completion.text[prefix_len..completion.text.len() - suffix_len])
1198        } else {
1199            None
1200        }
1201    }
1202
1203    fn cycle_completions(&mut self, direction: Direction) {
1204        match direction {
1205            Direction::Prev => {
1206                self.active_completion_index = if self.active_completion_index == 0 {
1207                    self.completions.len().saturating_sub(1)
1208                } else {
1209                    self.active_completion_index - 1
1210                };
1211            }
1212            Direction::Next => {
1213                if self.completions.len() == 0 {
1214                    self.active_completion_index = 0
1215                } else {
1216                    self.active_completion_index =
1217                        (self.active_completion_index + 1) % self.completions.len();
1218                }
1219            }
1220        }
1221    }
1222
1223    fn push_completion(&mut self, new_completion: copilot::Completion) {
1224        for completion in &self.completions {
1225            if completion.text == new_completion.text && completion.range == new_completion.range {
1226                return;
1227            }
1228        }
1229        self.completions.push(new_completion);
1230    }
1231
1232    fn common_prefix<T1: Iterator<Item = char>, T2: Iterator<Item = char>>(a: T1, b: T2) -> usize {
1233        a.zip(b)
1234            .take_while(|(a, b)| a == b)
1235            .map(|(a, _)| a.len_utf8())
1236            .sum()
1237    }
1238}
1239
1240#[derive(Debug)]
1241struct ActiveDiagnosticGroup {
1242    primary_range: Range<Anchor>,
1243    primary_message: String,
1244    blocks: HashMap<BlockId, Diagnostic>,
1245    is_valid: bool,
1246}
1247
1248#[derive(Serialize, Deserialize)]
1249pub struct ClipboardSelection {
1250    pub len: usize,
1251    pub is_entire_line: bool,
1252    pub first_line_indent: u32,
1253}
1254
1255#[derive(Debug)]
1256pub(crate) struct NavigationData {
1257    cursor_anchor: Anchor,
1258    cursor_position: Point,
1259    scroll_anchor: ScrollAnchor,
1260    scroll_top_row: u32,
1261}
1262
1263enum GotoDefinitionKind {
1264    Symbol,
1265    Type,
1266}
1267
1268#[derive(Debug, Clone)]
1269enum InlayHintRefreshReason {
1270    Toggle(bool),
1271    SettingsChange(InlayHintSettings),
1272    NewLinesShown,
1273    BufferEdited(HashSet<Arc<Language>>),
1274    RefreshRequested,
1275    ExcerptsRemoved(Vec<ExcerptId>),
1276}
1277impl InlayHintRefreshReason {
1278    fn description(&self) -> &'static str {
1279        match self {
1280            Self::Toggle(_) => "toggle",
1281            Self::SettingsChange(_) => "settings change",
1282            Self::NewLinesShown => "new lines shown",
1283            Self::BufferEdited(_) => "buffer edited",
1284            Self::RefreshRequested => "refresh requested",
1285            Self::ExcerptsRemoved(_) => "excerpts removed",
1286        }
1287    }
1288}
1289
1290impl Editor {
1291    pub fn single_line(cx: &mut ViewContext<Self>) -> Self {
1292        let buffer = cx.new_model(|cx| Buffer::new(0, cx.entity_id().as_u64(), String::new()));
1293        let buffer = cx.new_model(|cx| MultiBuffer::singleton(buffer, cx));
1294        Self::new(EditorMode::SingleLine, buffer, None, cx)
1295    }
1296
1297    pub fn multi_line(cx: &mut ViewContext<Self>) -> Self {
1298        let buffer = cx.new_model(|cx| Buffer::new(0, cx.entity_id().as_u64(), String::new()));
1299        let buffer = cx.new_model(|cx| MultiBuffer::singleton(buffer, cx));
1300        Self::new(EditorMode::Full, buffer, None, cx)
1301    }
1302
1303    pub fn auto_height(max_lines: usize, cx: &mut ViewContext<Self>) -> Self {
1304        let buffer = cx.new_model(|cx| Buffer::new(0, cx.entity_id().as_u64(), String::new()));
1305        let buffer = cx.new_model(|cx| MultiBuffer::singleton(buffer, cx));
1306        Self::new(EditorMode::AutoHeight { max_lines }, buffer, None, cx)
1307    }
1308
1309    pub fn for_buffer(
1310        buffer: Model<Buffer>,
1311        project: Option<Model<Project>>,
1312        cx: &mut ViewContext<Self>,
1313    ) -> Self {
1314        let buffer = cx.new_model(|cx| MultiBuffer::singleton(buffer, cx));
1315        Self::new(EditorMode::Full, buffer, project, cx)
1316    }
1317
1318    pub fn for_multibuffer(
1319        buffer: Model<MultiBuffer>,
1320        project: Option<Model<Project>>,
1321        cx: &mut ViewContext<Self>,
1322    ) -> Self {
1323        Self::new(EditorMode::Full, buffer, project, cx)
1324    }
1325
1326    pub fn clone(&self, cx: &mut ViewContext<Self>) -> Self {
1327        let mut clone = Self::new(self.mode, self.buffer.clone(), self.project.clone(), cx);
1328        self.display_map.update(cx, |display_map, cx| {
1329            let snapshot = display_map.snapshot(cx);
1330            clone.display_map.update(cx, |display_map, cx| {
1331                display_map.set_state(&snapshot, cx);
1332            });
1333        });
1334        clone.selections.clone_state(&self.selections);
1335        clone.scroll_manager.clone_state(&self.scroll_manager);
1336        clone.searchable = self.searchable;
1337        clone
1338    }
1339
1340    fn new(
1341        mode: EditorMode,
1342        buffer: Model<MultiBuffer>,
1343        project: Option<Model<Project>>,
1344        cx: &mut ViewContext<Self>,
1345    ) -> Self {
1346        let style = cx.text_style();
1347        let font_size = style.font_size.to_pixels(cx.rem_size());
1348        let display_map = cx.new_model(|cx| {
1349            DisplayMap::new(buffer.clone(), style.font(), font_size, None, 2, 1, cx)
1350        });
1351
1352        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
1353
1354        let blink_manager = cx.new_model(|cx| BlinkManager::new(CURSOR_BLINK_INTERVAL, cx));
1355
1356        let soft_wrap_mode_override =
1357            (mode == EditorMode::SingleLine).then(|| language_settings::SoftWrap::None);
1358
1359        let mut project_subscriptions = Vec::new();
1360        if mode == EditorMode::Full {
1361            if let Some(project) = project.as_ref() {
1362                if buffer.read(cx).is_singleton() {
1363                    project_subscriptions.push(cx.observe(project, |_, _, cx| {
1364                        cx.emit(EditorEvent::TitleChanged);
1365                    }));
1366                }
1367                project_subscriptions.push(cx.subscribe(project, |editor, _, event, cx| {
1368                    if let project::Event::RefreshInlayHints = event {
1369                        editor.refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
1370                    };
1371                }));
1372            }
1373        }
1374
1375        let inlay_hint_settings = inlay_hint_settings(
1376            selections.newest_anchor().head(),
1377            &buffer.read(cx).snapshot(cx),
1378            cx,
1379        );
1380
1381        let focus_handle = cx.focus_handle();
1382        cx.on_focus(&focus_handle, Self::handle_focus).detach();
1383        cx.on_blur(&focus_handle, Self::handle_blur).detach();
1384
1385        let mut this = Self {
1386            handle: cx.view().downgrade(),
1387            focus_handle,
1388            buffer: buffer.clone(),
1389            display_map: display_map.clone(),
1390            selections,
1391            scroll_manager: ScrollManager::new(),
1392            columnar_selection_tail: None,
1393            add_selections_state: None,
1394            select_next_state: None,
1395            select_prev_state: None,
1396            selection_history: Default::default(),
1397            autoclose_regions: Default::default(),
1398            snippet_stack: Default::default(),
1399            select_larger_syntax_node_stack: Vec::new(),
1400            ime_transaction: Default::default(),
1401            active_diagnostics: None,
1402            soft_wrap_mode_override,
1403            completion_provider: project.clone().map(|project| Box::new(project) as _),
1404            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
1405            project,
1406            blink_manager: blink_manager.clone(),
1407            show_local_selections: true,
1408            mode,
1409            show_gutter: mode == EditorMode::Full,
1410            show_wrap_guides: None,
1411            placeholder_text: None,
1412            highlighted_rows: None,
1413            background_highlights: Default::default(),
1414            inlay_background_highlights: Default::default(),
1415            nav_history: None,
1416            context_menu: RwLock::new(None),
1417            mouse_context_menu: None,
1418            completion_tasks: Default::default(),
1419            next_completion_id: 0,
1420            next_inlay_id: 0,
1421            available_code_actions: Default::default(),
1422            code_actions_task: Default::default(),
1423            document_highlights_task: Default::default(),
1424            pending_rename: Default::default(),
1425            searchable: true,
1426            cursor_shape: Default::default(),
1427            autoindent_mode: Some(AutoindentMode::EachLine),
1428            collapse_matches: false,
1429            workspace: None,
1430            keymap_context_layers: Default::default(),
1431            input_enabled: true,
1432            read_only: false,
1433            use_autoclose: true,
1434            leader_peer_id: None,
1435            remote_id: None,
1436            hover_state: Default::default(),
1437            link_go_to_definition_state: Default::default(),
1438            copilot_state: Default::default(),
1439            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
1440            gutter_hovered: false,
1441            pixel_position_of_newest_cursor: None,
1442            gutter_width: Default::default(),
1443            style: None,
1444            show_cursor_names: false,
1445            hovered_cursors: Default::default(),
1446            editor_actions: Default::default(),
1447            show_copilot_suggestions: mode == EditorMode::Full,
1448            _subscriptions: vec![
1449                cx.observe(&buffer, Self::on_buffer_changed),
1450                cx.subscribe(&buffer, Self::on_buffer_event),
1451                cx.observe(&display_map, Self::on_display_map_changed),
1452                cx.observe(&blink_manager, |_, _, cx| cx.notify()),
1453                cx.observe_global::<SettingsStore>(Self::settings_changed),
1454                observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
1455                cx.observe_window_activation(|editor, cx| {
1456                    let active = cx.is_window_active();
1457                    editor.blink_manager.update(cx, |blink_manager, cx| {
1458                        if active {
1459                            blink_manager.enable(cx);
1460                        } else {
1461                            blink_manager.show_cursor(cx);
1462                            blink_manager.disable(cx);
1463                        }
1464                    });
1465                }),
1466            ],
1467        };
1468
1469        this._subscriptions.extend(project_subscriptions);
1470
1471        this.end_selection(cx);
1472        this.scroll_manager.show_scrollbar(cx);
1473
1474        if mode == EditorMode::Full {
1475            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
1476            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
1477        }
1478
1479        this.report_editor_event("open", None, cx);
1480        this
1481    }
1482
1483    fn key_context(&self, cx: &AppContext) -> KeyContext {
1484        let mut key_context = KeyContext::default();
1485        key_context.add("Editor");
1486        let mode = match self.mode {
1487            EditorMode::SingleLine => "single_line",
1488            EditorMode::AutoHeight { .. } => "auto_height",
1489            EditorMode::Full => "full",
1490        };
1491        key_context.set("mode", mode);
1492        if self.pending_rename.is_some() {
1493            key_context.add("renaming");
1494        }
1495        if self.context_menu_visible() {
1496            match self.context_menu.read().as_ref() {
1497                Some(ContextMenu::Completions(_)) => {
1498                    key_context.add("menu");
1499                    key_context.add("showing_completions")
1500                }
1501                Some(ContextMenu::CodeActions(_)) => {
1502                    key_context.add("menu");
1503                    key_context.add("showing_code_actions")
1504                }
1505                None => {}
1506            }
1507        }
1508
1509        for layer in self.keymap_context_layers.values() {
1510            key_context.extend(layer);
1511        }
1512
1513        if let Some(extension) = self
1514            .buffer
1515            .read(cx)
1516            .as_singleton()
1517            .and_then(|buffer| buffer.read(cx).file()?.path().extension()?.to_str())
1518        {
1519            key_context.set("extension", extension.to_string());
1520        }
1521
1522        key_context
1523    }
1524
1525    pub fn new_file(
1526        workspace: &mut Workspace,
1527        _: &workspace::NewFile,
1528        cx: &mut ViewContext<Workspace>,
1529    ) {
1530        let project = workspace.project().clone();
1531        if project.read(cx).is_remote() {
1532            cx.propagate();
1533        } else if let Some(buffer) = project
1534            .update(cx, |project, cx| project.create_buffer("", None, cx))
1535            .log_err()
1536        {
1537            workspace.add_item(
1538                Box::new(cx.new_view(|cx| Editor::for_buffer(buffer, Some(project.clone()), cx))),
1539                cx,
1540            );
1541        }
1542    }
1543
1544    pub fn new_file_in_direction(
1545        workspace: &mut Workspace,
1546        action: &workspace::NewFileInDirection,
1547        cx: &mut ViewContext<Workspace>,
1548    ) {
1549        let project = workspace.project().clone();
1550        if project.read(cx).is_remote() {
1551            cx.propagate();
1552        } else if let Some(buffer) = project
1553            .update(cx, |project, cx| project.create_buffer("", None, cx))
1554            .log_err()
1555        {
1556            workspace.split_item(
1557                action.0,
1558                Box::new(cx.new_view(|cx| Editor::for_buffer(buffer, Some(project.clone()), cx))),
1559                cx,
1560            );
1561        }
1562    }
1563
1564    pub fn replica_id(&self, cx: &AppContext) -> ReplicaId {
1565        self.buffer.read(cx).replica_id()
1566    }
1567
1568    pub fn leader_peer_id(&self) -> Option<PeerId> {
1569        self.leader_peer_id
1570    }
1571
1572    pub fn buffer(&self) -> &Model<MultiBuffer> {
1573        &self.buffer
1574    }
1575
1576    pub fn workspace(&self) -> Option<View<Workspace>> {
1577        self.workspace.as_ref()?.0.upgrade()
1578    }
1579
1580    pub fn pane(&self, cx: &AppContext) -> Option<View<Pane>> {
1581        self.workspace()?.read(cx).pane_for(&self.handle.upgrade()?)
1582    }
1583
1584    pub fn title<'a>(&self, cx: &'a AppContext) -> Cow<'a, str> {
1585        self.buffer().read(cx).title(cx)
1586    }
1587
1588    pub fn snapshot(&mut self, cx: &mut WindowContext) -> EditorSnapshot {
1589        EditorSnapshot {
1590            mode: self.mode,
1591            show_gutter: self.show_gutter,
1592            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
1593            scroll_anchor: self.scroll_manager.anchor(),
1594            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
1595            placeholder_text: self.placeholder_text.clone(),
1596            is_focused: self.focus_handle.is_focused(cx),
1597        }
1598    }
1599
1600    pub fn language_at<'a, T: ToOffset>(
1601        &self,
1602        point: T,
1603        cx: &'a AppContext,
1604    ) -> Option<Arc<Language>> {
1605        self.buffer.read(cx).language_at(point, cx)
1606    }
1607
1608    pub fn file_at<'a, T: ToOffset>(
1609        &self,
1610        point: T,
1611        cx: &'a AppContext,
1612    ) -> Option<Arc<dyn language::File>> {
1613        self.buffer.read(cx).read(cx).file_at(point).cloned()
1614    }
1615
1616    pub fn active_excerpt(
1617        &self,
1618        cx: &AppContext,
1619    ) -> Option<(ExcerptId, Model<Buffer>, Range<text::Anchor>)> {
1620        self.buffer
1621            .read(cx)
1622            .excerpt_containing(self.selections.newest_anchor().head(), cx)
1623    }
1624
1625    pub fn mode(&self) -> EditorMode {
1626        self.mode
1627    }
1628
1629    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
1630        self.collaboration_hub.as_deref()
1631    }
1632
1633    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
1634        self.collaboration_hub = Some(hub);
1635    }
1636
1637    pub fn set_completion_provider(&mut self, hub: Box<dyn CompletionProvider>) {
1638        self.completion_provider = Some(hub);
1639    }
1640
1641    pub fn placeholder_text(&self) -> Option<&str> {
1642        self.placeholder_text.as_deref()
1643    }
1644
1645    pub fn set_placeholder_text(
1646        &mut self,
1647        placeholder_text: impl Into<Arc<str>>,
1648        cx: &mut ViewContext<Self>,
1649    ) {
1650        let placeholder_text = Some(placeholder_text.into());
1651        if self.placeholder_text != placeholder_text {
1652            self.placeholder_text = placeholder_text;
1653            cx.notify();
1654        }
1655    }
1656
1657    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut ViewContext<Self>) {
1658        self.cursor_shape = cursor_shape;
1659        cx.notify();
1660    }
1661
1662    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
1663        self.collapse_matches = collapse_matches;
1664    }
1665
1666    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
1667        if self.collapse_matches {
1668            return range.start..range.start;
1669        }
1670        range.clone()
1671    }
1672
1673    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut ViewContext<Self>) {
1674        if self.display_map.read(cx).clip_at_line_ends != clip {
1675            self.display_map
1676                .update(cx, |map, _| map.clip_at_line_ends = clip);
1677        }
1678    }
1679
1680    pub fn set_keymap_context_layer<Tag: 'static>(
1681        &mut self,
1682        context: KeyContext,
1683        cx: &mut ViewContext<Self>,
1684    ) {
1685        self.keymap_context_layers
1686            .insert(TypeId::of::<Tag>(), context);
1687        cx.notify();
1688    }
1689
1690    pub fn remove_keymap_context_layer<Tag: 'static>(&mut self, cx: &mut ViewContext<Self>) {
1691        self.keymap_context_layers.remove(&TypeId::of::<Tag>());
1692        cx.notify();
1693    }
1694
1695    pub fn set_input_enabled(&mut self, input_enabled: bool) {
1696        self.input_enabled = input_enabled;
1697    }
1698
1699    pub fn set_autoindent(&mut self, autoindent: bool) {
1700        if autoindent {
1701            self.autoindent_mode = Some(AutoindentMode::EachLine);
1702        } else {
1703            self.autoindent_mode = None;
1704        }
1705    }
1706
1707    pub fn read_only(&self, cx: &AppContext) -> bool {
1708        self.read_only || self.buffer.read(cx).read_only()
1709    }
1710
1711    pub fn set_read_only(&mut self, read_only: bool) {
1712        self.read_only = read_only;
1713    }
1714
1715    pub fn set_use_autoclose(&mut self, autoclose: bool) {
1716        self.use_autoclose = autoclose;
1717    }
1718
1719    pub fn set_show_copilot_suggestions(&mut self, show_copilot_suggestions: bool) {
1720        self.show_copilot_suggestions = show_copilot_suggestions;
1721    }
1722
1723    fn selections_did_change(
1724        &mut self,
1725        local: bool,
1726        old_cursor_position: &Anchor,
1727        cx: &mut ViewContext<Self>,
1728    ) {
1729        if self.focus_handle.is_focused(cx) && self.leader_peer_id.is_none() {
1730            self.buffer.update(cx, |buffer, cx| {
1731                buffer.set_active_selections(
1732                    &self.selections.disjoint_anchors(),
1733                    self.selections.line_mode,
1734                    self.cursor_shape,
1735                    cx,
1736                )
1737            });
1738        }
1739
1740        let display_map = self
1741            .display_map
1742            .update(cx, |display_map, cx| display_map.snapshot(cx));
1743        let buffer = &display_map.buffer_snapshot;
1744        self.add_selections_state = None;
1745        self.select_next_state = None;
1746        self.select_prev_state = None;
1747        self.select_larger_syntax_node_stack.clear();
1748        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), buffer);
1749        self.snippet_stack
1750            .invalidate(&self.selections.disjoint_anchors(), buffer);
1751        self.take_rename(false, cx);
1752
1753        let new_cursor_position = self.selections.newest_anchor().head();
1754
1755        self.push_to_nav_history(
1756            old_cursor_position.clone(),
1757            Some(new_cursor_position.to_point(buffer)),
1758            cx,
1759        );
1760
1761        if local {
1762            let new_cursor_position = self.selections.newest_anchor().head();
1763            let mut context_menu = self.context_menu.write();
1764            let completion_menu = match context_menu.as_ref() {
1765                Some(ContextMenu::Completions(menu)) => Some(menu),
1766
1767                _ => {
1768                    *context_menu = None;
1769                    None
1770                }
1771            };
1772
1773            if let Some(completion_menu) = completion_menu {
1774                let cursor_position = new_cursor_position.to_offset(buffer);
1775                let (word_range, kind) =
1776                    buffer.surrounding_word(completion_menu.initial_position.clone());
1777                if kind == Some(CharKind::Word)
1778                    && word_range.to_inclusive().contains(&cursor_position)
1779                {
1780                    let mut completion_menu = completion_menu.clone();
1781                    drop(context_menu);
1782
1783                    let query = Self::completion_query(buffer, cursor_position);
1784                    cx.spawn(move |this, mut cx| async move {
1785                        completion_menu
1786                            .filter(query.as_deref(), cx.background_executor().clone())
1787                            .await;
1788
1789                        this.update(&mut cx, |this, cx| {
1790                            let mut context_menu = this.context_menu.write();
1791                            let Some(ContextMenu::Completions(menu)) = context_menu.as_ref() else {
1792                                return;
1793                            };
1794
1795                            if menu.id > completion_menu.id {
1796                                return;
1797                            }
1798
1799                            *context_menu = Some(ContextMenu::Completions(completion_menu));
1800                            drop(context_menu);
1801                            cx.notify();
1802                        })
1803                    })
1804                    .detach();
1805
1806                    self.show_completions(&ShowCompletions, cx);
1807                } else {
1808                    drop(context_menu);
1809                    self.hide_context_menu(cx);
1810                }
1811            } else {
1812                drop(context_menu);
1813            }
1814
1815            hide_hover(self, cx);
1816
1817            if old_cursor_position.to_display_point(&display_map).row()
1818                != new_cursor_position.to_display_point(&display_map).row()
1819            {
1820                self.available_code_actions.take();
1821            }
1822            self.refresh_code_actions(cx);
1823            self.refresh_document_highlights(cx);
1824            refresh_matching_bracket_highlights(self, cx);
1825            self.discard_copilot_suggestion(cx);
1826        }
1827
1828        self.blink_manager.update(cx, BlinkManager::pause_blinking);
1829        cx.emit(EditorEvent::SelectionsChanged { local });
1830
1831        if self.selections.disjoint_anchors().len() == 1 {
1832            cx.emit(SearchEvent::ActiveMatchChanged)
1833        }
1834
1835        cx.notify();
1836    }
1837
1838    pub fn change_selections<R>(
1839        &mut self,
1840        autoscroll: Option<Autoscroll>,
1841        cx: &mut ViewContext<Self>,
1842        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
1843    ) -> R {
1844        let old_cursor_position = self.selections.newest_anchor().head();
1845        self.push_to_selection_history();
1846
1847        let (changed, result) = self.selections.change_with(cx, change);
1848
1849        if changed {
1850            if let Some(autoscroll) = autoscroll {
1851                self.request_autoscroll(autoscroll, cx);
1852            }
1853            self.selections_did_change(true, &old_cursor_position, cx);
1854        }
1855
1856        result
1857    }
1858
1859    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut ViewContext<Self>)
1860    where
1861        I: IntoIterator<Item = (Range<S>, T)>,
1862        S: ToOffset,
1863        T: Into<Arc<str>>,
1864    {
1865        if self.read_only(cx) {
1866            return;
1867        }
1868
1869        self.buffer
1870            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
1871    }
1872
1873    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut ViewContext<Self>)
1874    where
1875        I: IntoIterator<Item = (Range<S>, T)>,
1876        S: ToOffset,
1877        T: Into<Arc<str>>,
1878    {
1879        if self.read_only(cx) {
1880            return;
1881        }
1882
1883        self.buffer.update(cx, |buffer, cx| {
1884            buffer.edit(edits, self.autoindent_mode.clone(), cx)
1885        });
1886    }
1887
1888    pub fn edit_with_block_indent<I, S, T>(
1889        &mut self,
1890        edits: I,
1891        original_indent_columns: Vec<u32>,
1892        cx: &mut ViewContext<Self>,
1893    ) where
1894        I: IntoIterator<Item = (Range<S>, T)>,
1895        S: ToOffset,
1896        T: Into<Arc<str>>,
1897    {
1898        if self.read_only(cx) {
1899            return;
1900        }
1901
1902        self.buffer.update(cx, |buffer, cx| {
1903            buffer.edit(
1904                edits,
1905                Some(AutoindentMode::Block {
1906                    original_indent_columns,
1907                }),
1908                cx,
1909            )
1910        });
1911    }
1912
1913    fn select(&mut self, phase: SelectPhase, cx: &mut ViewContext<Self>) {
1914        self.hide_context_menu(cx);
1915
1916        match phase {
1917            SelectPhase::Begin {
1918                position,
1919                add,
1920                click_count,
1921            } => self.begin_selection(position, add, click_count, cx),
1922            SelectPhase::BeginColumnar {
1923                position,
1924                goal_column,
1925            } => self.begin_columnar_selection(position, goal_column, cx),
1926            SelectPhase::Extend {
1927                position,
1928                click_count,
1929            } => self.extend_selection(position, click_count, cx),
1930            SelectPhase::Update {
1931                position,
1932                goal_column,
1933                scroll_delta,
1934            } => self.update_selection(position, goal_column, scroll_delta, cx),
1935            SelectPhase::End => self.end_selection(cx),
1936        }
1937    }
1938
1939    fn extend_selection(
1940        &mut self,
1941        position: DisplayPoint,
1942        click_count: usize,
1943        cx: &mut ViewContext<Self>,
1944    ) {
1945        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
1946        let tail = self.selections.newest::<usize>(cx).tail();
1947        self.begin_selection(position, false, click_count, cx);
1948
1949        let position = position.to_offset(&display_map, Bias::Left);
1950        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
1951
1952        let mut pending_selection = self
1953            .selections
1954            .pending_anchor()
1955            .expect("extend_selection not called with pending selection");
1956        if position >= tail {
1957            pending_selection.start = tail_anchor;
1958        } else {
1959            pending_selection.end = tail_anchor;
1960            pending_selection.reversed = true;
1961        }
1962
1963        let mut pending_mode = self.selections.pending_mode().unwrap();
1964        match &mut pending_mode {
1965            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
1966            _ => {}
1967        }
1968
1969        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
1970            s.set_pending(pending_selection, pending_mode)
1971        });
1972    }
1973
1974    fn begin_selection(
1975        &mut self,
1976        position: DisplayPoint,
1977        add: bool,
1978        click_count: usize,
1979        cx: &mut ViewContext<Self>,
1980    ) {
1981        if !self.focus_handle.is_focused(cx) {
1982            cx.focus(&self.focus_handle);
1983        }
1984
1985        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
1986        let buffer = &display_map.buffer_snapshot;
1987        let newest_selection = self.selections.newest_anchor().clone();
1988        let position = display_map.clip_point(position, Bias::Left);
1989
1990        let start;
1991        let end;
1992        let mode;
1993        let auto_scroll;
1994        match click_count {
1995            1 => {
1996                start = buffer.anchor_before(position.to_point(&display_map));
1997                end = start.clone();
1998                mode = SelectMode::Character;
1999                auto_scroll = true;
2000            }
2001            2 => {
2002                let range = movement::surrounding_word(&display_map, position);
2003                start = buffer.anchor_before(range.start.to_point(&display_map));
2004                end = buffer.anchor_before(range.end.to_point(&display_map));
2005                mode = SelectMode::Word(start.clone()..end.clone());
2006                auto_scroll = true;
2007            }
2008            3 => {
2009                let position = display_map
2010                    .clip_point(position, Bias::Left)
2011                    .to_point(&display_map);
2012                let line_start = display_map.prev_line_boundary(position).0;
2013                let next_line_start = buffer.clip_point(
2014                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
2015                    Bias::Left,
2016                );
2017                start = buffer.anchor_before(line_start);
2018                end = buffer.anchor_before(next_line_start);
2019                mode = SelectMode::Line(start.clone()..end.clone());
2020                auto_scroll = true;
2021            }
2022            _ => {
2023                start = buffer.anchor_before(0);
2024                end = buffer.anchor_before(buffer.len());
2025                mode = SelectMode::All;
2026                auto_scroll = false;
2027            }
2028        }
2029
2030        self.change_selections(auto_scroll.then(|| Autoscroll::newest()), cx, |s| {
2031            if !add {
2032                s.clear_disjoint();
2033            } else if click_count > 1 {
2034                s.delete(newest_selection.id)
2035            }
2036
2037            s.set_pending_anchor_range(start..end, mode);
2038        });
2039    }
2040
2041    fn begin_columnar_selection(
2042        &mut self,
2043        position: DisplayPoint,
2044        goal_column: u32,
2045        cx: &mut ViewContext<Self>,
2046    ) {
2047        if !self.focus_handle.is_focused(cx) {
2048            cx.focus(&self.focus_handle);
2049        }
2050
2051        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
2052        let tail = self.selections.newest::<Point>(cx).tail();
2053        self.columnar_selection_tail = Some(display_map.buffer_snapshot.anchor_before(tail));
2054
2055        self.select_columns(
2056            tail.to_display_point(&display_map),
2057            position,
2058            goal_column,
2059            &display_map,
2060            cx,
2061        );
2062    }
2063
2064    fn update_selection(
2065        &mut self,
2066        position: DisplayPoint,
2067        goal_column: u32,
2068        scroll_delta: gpui::Point<f32>,
2069        cx: &mut ViewContext<Self>,
2070    ) {
2071        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
2072
2073        if let Some(tail) = self.columnar_selection_tail.as_ref() {
2074            let tail = tail.to_display_point(&display_map);
2075            self.select_columns(tail, position, goal_column, &display_map, cx);
2076        } else if let Some(mut pending) = self.selections.pending_anchor() {
2077            let buffer = self.buffer.read(cx).snapshot(cx);
2078            let head;
2079            let tail;
2080            let mode = self.selections.pending_mode().unwrap();
2081            match &mode {
2082                SelectMode::Character => {
2083                    head = position.to_point(&display_map);
2084                    tail = pending.tail().to_point(&buffer);
2085                }
2086                SelectMode::Word(original_range) => {
2087                    let original_display_range = original_range.start.to_display_point(&display_map)
2088                        ..original_range.end.to_display_point(&display_map);
2089                    let original_buffer_range = original_display_range.start.to_point(&display_map)
2090                        ..original_display_range.end.to_point(&display_map);
2091                    if movement::is_inside_word(&display_map, position)
2092                        || original_display_range.contains(&position)
2093                    {
2094                        let word_range = movement::surrounding_word(&display_map, position);
2095                        if word_range.start < original_display_range.start {
2096                            head = word_range.start.to_point(&display_map);
2097                        } else {
2098                            head = word_range.end.to_point(&display_map);
2099                        }
2100                    } else {
2101                        head = position.to_point(&display_map);
2102                    }
2103
2104                    if head <= original_buffer_range.start {
2105                        tail = original_buffer_range.end;
2106                    } else {
2107                        tail = original_buffer_range.start;
2108                    }
2109                }
2110                SelectMode::Line(original_range) => {
2111                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
2112
2113                    let position = display_map
2114                        .clip_point(position, Bias::Left)
2115                        .to_point(&display_map);
2116                    let line_start = display_map.prev_line_boundary(position).0;
2117                    let next_line_start = buffer.clip_point(
2118                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
2119                        Bias::Left,
2120                    );
2121
2122                    if line_start < original_range.start {
2123                        head = line_start
2124                    } else {
2125                        head = next_line_start
2126                    }
2127
2128                    if head <= original_range.start {
2129                        tail = original_range.end;
2130                    } else {
2131                        tail = original_range.start;
2132                    }
2133                }
2134                SelectMode::All => {
2135                    return;
2136                }
2137            };
2138
2139            if head < tail {
2140                pending.start = buffer.anchor_before(head);
2141                pending.end = buffer.anchor_before(tail);
2142                pending.reversed = true;
2143            } else {
2144                pending.start = buffer.anchor_before(tail);
2145                pending.end = buffer.anchor_before(head);
2146                pending.reversed = false;
2147            }
2148
2149            self.change_selections(None, cx, |s| {
2150                s.set_pending(pending, mode);
2151            });
2152        } else {
2153            log::error!("update_selection dispatched with no pending selection");
2154            return;
2155        }
2156
2157        self.apply_scroll_delta(scroll_delta, cx);
2158        cx.notify();
2159    }
2160
2161    fn end_selection(&mut self, cx: &mut ViewContext<Self>) {
2162        self.columnar_selection_tail.take();
2163        if self.selections.pending_anchor().is_some() {
2164            let selections = self.selections.all::<usize>(cx);
2165            self.change_selections(None, cx, |s| {
2166                s.select(selections);
2167                s.clear_pending();
2168            });
2169        }
2170    }
2171
2172    fn select_columns(
2173        &mut self,
2174        tail: DisplayPoint,
2175        head: DisplayPoint,
2176        goal_column: u32,
2177        display_map: &DisplaySnapshot,
2178        cx: &mut ViewContext<Self>,
2179    ) {
2180        let start_row = cmp::min(tail.row(), head.row());
2181        let end_row = cmp::max(tail.row(), head.row());
2182        let start_column = cmp::min(tail.column(), goal_column);
2183        let end_column = cmp::max(tail.column(), goal_column);
2184        let reversed = start_column < tail.column();
2185
2186        let selection_ranges = (start_row..=end_row)
2187            .filter_map(|row| {
2188                if start_column <= display_map.line_len(row) && !display_map.is_block_line(row) {
2189                    let start = display_map
2190                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
2191                        .to_point(display_map);
2192                    let end = display_map
2193                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
2194                        .to_point(display_map);
2195                    if reversed {
2196                        Some(end..start)
2197                    } else {
2198                        Some(start..end)
2199                    }
2200                } else {
2201                    None
2202                }
2203            })
2204            .collect::<Vec<_>>();
2205
2206        self.change_selections(None, cx, |s| {
2207            s.select_ranges(selection_ranges);
2208        });
2209        cx.notify();
2210    }
2211
2212    pub fn has_pending_nonempty_selection(&self) -> bool {
2213        let pending_nonempty_selection = match self.selections.pending_anchor() {
2214            Some(Selection { start, end, .. }) => start != end,
2215            None => false,
2216        };
2217        pending_nonempty_selection || self.columnar_selection_tail.is_some()
2218    }
2219
2220    pub fn has_pending_selection(&self) -> bool {
2221        self.selections.pending_anchor().is_some() || self.columnar_selection_tail.is_some()
2222    }
2223
2224    pub fn cancel(&mut self, _: &Cancel, cx: &mut ViewContext<Self>) {
2225        if self.take_rename(false, cx).is_some() {
2226            return;
2227        }
2228
2229        if hide_hover(self, cx) {
2230            return;
2231        }
2232
2233        if self.hide_context_menu(cx).is_some() {
2234            return;
2235        }
2236
2237        if self.discard_copilot_suggestion(cx) {
2238            return;
2239        }
2240
2241        if self.snippet_stack.pop().is_some() {
2242            return;
2243        }
2244
2245        if self.mode == EditorMode::Full {
2246            if self.active_diagnostics.is_some() {
2247                self.dismiss_diagnostics(cx);
2248                return;
2249            }
2250
2251            if self.change_selections(Some(Autoscroll::fit()), cx, |s| s.try_cancel()) {
2252                return;
2253            }
2254        }
2255
2256        cx.propagate();
2257    }
2258
2259    pub fn handle_input(&mut self, text: &str, cx: &mut ViewContext<Self>) {
2260        let text: Arc<str> = text.into();
2261
2262        if self.read_only(cx) {
2263            return;
2264        }
2265
2266        let selections = self.selections.all_adjusted(cx);
2267        let mut brace_inserted = false;
2268        let mut edits = Vec::new();
2269        let mut new_selections = Vec::with_capacity(selections.len());
2270        let mut new_autoclose_regions = Vec::new();
2271        let snapshot = self.buffer.read(cx).read(cx);
2272
2273        for (selection, autoclose_region) in
2274            self.selections_with_autoclose_regions(selections, &snapshot)
2275        {
2276            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
2277                // Determine if the inserted text matches the opening or closing
2278                // bracket of any of this language's bracket pairs.
2279                let mut bracket_pair = None;
2280                let mut is_bracket_pair_start = false;
2281                if !text.is_empty() {
2282                    // `text` can be empty when an user is using IME (e.g. Chinese Wubi Simplified)
2283                    //  and they are removing the character that triggered IME popup.
2284                    for (pair, enabled) in scope.brackets() {
2285                        if enabled && pair.close && pair.start.ends_with(text.as_ref()) {
2286                            bracket_pair = Some(pair.clone());
2287                            is_bracket_pair_start = true;
2288                            break;
2289                        } else if pair.end.as_str() == text.as_ref() {
2290                            bracket_pair = Some(pair.clone());
2291                            break;
2292                        }
2293                    }
2294                }
2295
2296                if let Some(bracket_pair) = bracket_pair {
2297                    if selection.is_empty() {
2298                        if is_bracket_pair_start {
2299                            let prefix_len = bracket_pair.start.len() - text.len();
2300
2301                            // If the inserted text is a suffix of an opening bracket and the
2302                            // selection is preceded by the rest of the opening bracket, then
2303                            // insert the closing bracket.
2304                            let following_text_allows_autoclose = snapshot
2305                                .chars_at(selection.start)
2306                                .next()
2307                                .map_or(true, |c| scope.should_autoclose_before(c));
2308                            let preceding_text_matches_prefix = prefix_len == 0
2309                                || (selection.start.column >= (prefix_len as u32)
2310                                    && snapshot.contains_str_at(
2311                                        Point::new(
2312                                            selection.start.row,
2313                                            selection.start.column - (prefix_len as u32),
2314                                        ),
2315                                        &bracket_pair.start[..prefix_len],
2316                                    ));
2317                            let autoclose = self.use_autoclose
2318                                && snapshot.settings_at(selection.start, cx).use_autoclose;
2319                            if autoclose
2320                                && following_text_allows_autoclose
2321                                && preceding_text_matches_prefix
2322                            {
2323                                let anchor = snapshot.anchor_before(selection.end);
2324                                new_selections.push((selection.map(|_| anchor), text.len()));
2325                                new_autoclose_regions.push((
2326                                    anchor,
2327                                    text.len(),
2328                                    selection.id,
2329                                    bracket_pair.clone(),
2330                                ));
2331                                edits.push((
2332                                    selection.range(),
2333                                    format!("{}{}", text, bracket_pair.end).into(),
2334                                ));
2335                                brace_inserted = true;
2336                                continue;
2337                            }
2338                        }
2339
2340                        if let Some(region) = autoclose_region {
2341                            // If the selection is followed by an auto-inserted closing bracket,
2342                            // then don't insert that closing bracket again; just move the selection
2343                            // past the closing bracket.
2344                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
2345                                && text.as_ref() == region.pair.end.as_str();
2346                            if should_skip {
2347                                let anchor = snapshot.anchor_after(selection.end);
2348                                new_selections
2349                                    .push((selection.map(|_| anchor), region.pair.end.len()));
2350                                continue;
2351                            }
2352                        }
2353                    }
2354                    // If an opening bracket is 1 character long and is typed while
2355                    // text is selected, then surround that text with the bracket pair.
2356                    else if is_bracket_pair_start && bracket_pair.start.chars().count() == 1 {
2357                        edits.push((selection.start..selection.start, text.clone()));
2358                        edits.push((
2359                            selection.end..selection.end,
2360                            bracket_pair.end.as_str().into(),
2361                        ));
2362                        brace_inserted = true;
2363                        new_selections.push((
2364                            Selection {
2365                                id: selection.id,
2366                                start: snapshot.anchor_after(selection.start),
2367                                end: snapshot.anchor_before(selection.end),
2368                                reversed: selection.reversed,
2369                                goal: selection.goal,
2370                            },
2371                            0,
2372                        ));
2373                        continue;
2374                    }
2375                }
2376            }
2377
2378            // If not handling any auto-close operation, then just replace the selected
2379            // text with the given input and move the selection to the end of the
2380            // newly inserted text.
2381            let anchor = snapshot.anchor_after(selection.end);
2382            new_selections.push((selection.map(|_| anchor), 0));
2383            edits.push((selection.start..selection.end, text.clone()));
2384        }
2385
2386        drop(snapshot);
2387        self.transact(cx, |this, cx| {
2388            this.buffer.update(cx, |buffer, cx| {
2389                buffer.edit(edits, this.autoindent_mode.clone(), cx);
2390            });
2391
2392            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
2393            let new_selection_deltas = new_selections.iter().map(|e| e.1);
2394            let snapshot = this.buffer.read(cx).read(cx);
2395            let new_selections = resolve_multiple::<usize, _>(new_anchor_selections, &snapshot)
2396                .zip(new_selection_deltas)
2397                .map(|(selection, delta)| Selection {
2398                    id: selection.id,
2399                    start: selection.start + delta,
2400                    end: selection.end + delta,
2401                    reversed: selection.reversed,
2402                    goal: SelectionGoal::None,
2403                })
2404                .collect::<Vec<_>>();
2405
2406            let mut i = 0;
2407            for (position, delta, selection_id, pair) in new_autoclose_regions {
2408                let position = position.to_offset(&snapshot) + delta;
2409                let start = snapshot.anchor_before(position);
2410                let end = snapshot.anchor_after(position);
2411                while let Some(existing_state) = this.autoclose_regions.get(i) {
2412                    match existing_state.range.start.cmp(&start, &snapshot) {
2413                        Ordering::Less => i += 1,
2414                        Ordering::Greater => break,
2415                        Ordering::Equal => match end.cmp(&existing_state.range.end, &snapshot) {
2416                            Ordering::Less => i += 1,
2417                            Ordering::Equal => break,
2418                            Ordering::Greater => break,
2419                        },
2420                    }
2421                }
2422                this.autoclose_regions.insert(
2423                    i,
2424                    AutocloseRegion {
2425                        selection_id,
2426                        range: start..end,
2427                        pair,
2428                    },
2429                );
2430            }
2431
2432            drop(snapshot);
2433            let had_active_copilot_suggestion = this.has_active_copilot_suggestion(cx);
2434            this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(new_selections));
2435
2436            if !brace_inserted && EditorSettings::get_global(cx).use_on_type_format {
2437                if let Some(on_type_format_task) =
2438                    this.trigger_on_type_formatting(text.to_string(), cx)
2439                {
2440                    on_type_format_task.detach_and_log_err(cx);
2441                }
2442            }
2443
2444            if had_active_copilot_suggestion {
2445                this.refresh_copilot_suggestions(true, cx);
2446                if !this.has_active_copilot_suggestion(cx) {
2447                    this.trigger_completion_on_input(&text, cx);
2448                }
2449            } else {
2450                this.trigger_completion_on_input(&text, cx);
2451                this.refresh_copilot_suggestions(true, cx);
2452            }
2453        });
2454    }
2455
2456    pub fn newline(&mut self, _: &Newline, cx: &mut ViewContext<Self>) {
2457        self.transact(cx, |this, cx| {
2458            let (edits, selection_fixup_info): (Vec<_>, Vec<_>) = {
2459                let selections = this.selections.all::<usize>(cx);
2460                let multi_buffer = this.buffer.read(cx);
2461                let buffer = multi_buffer.snapshot(cx);
2462                selections
2463                    .iter()
2464                    .map(|selection| {
2465                        let start_point = selection.start.to_point(&buffer);
2466                        let mut indent = buffer.indent_size_for_line(start_point.row);
2467                        indent.len = cmp::min(indent.len, start_point.column);
2468                        let start = selection.start;
2469                        let end = selection.end;
2470                        let is_cursor = start == end;
2471                        let language_scope = buffer.language_scope_at(start);
2472                        let (comment_delimiter, insert_extra_newline) = if let Some(language) =
2473                            &language_scope
2474                        {
2475                            let leading_whitespace_len = buffer
2476                                .reversed_chars_at(start)
2477                                .take_while(|c| c.is_whitespace() && *c != '\n')
2478                                .map(|c| c.len_utf8())
2479                                .sum::<usize>();
2480
2481                            let trailing_whitespace_len = buffer
2482                                .chars_at(end)
2483                                .take_while(|c| c.is_whitespace() && *c != '\n')
2484                                .map(|c| c.len_utf8())
2485                                .sum::<usize>();
2486
2487                            let insert_extra_newline =
2488                                language.brackets().any(|(pair, enabled)| {
2489                                    let pair_start = pair.start.trim_end();
2490                                    let pair_end = pair.end.trim_start();
2491
2492                                    enabled
2493                                        && pair.newline
2494                                        && buffer.contains_str_at(
2495                                            end + trailing_whitespace_len,
2496                                            pair_end,
2497                                        )
2498                                        && buffer.contains_str_at(
2499                                            (start - leading_whitespace_len)
2500                                                .saturating_sub(pair_start.len()),
2501                                            pair_start,
2502                                        )
2503                                });
2504                            // Comment extension on newline is allowed only for cursor selections
2505                            let comment_delimiter = language.line_comment_prefix().filter(|_| {
2506                                let is_comment_extension_enabled =
2507                                    multi_buffer.settings_at(0, cx).extend_comment_on_newline;
2508                                is_cursor && is_comment_extension_enabled
2509                            });
2510                            let comment_delimiter = if let Some(delimiter) = comment_delimiter {
2511                                buffer
2512                                    .buffer_line_for_row(start_point.row)
2513                                    .is_some_and(|(snapshot, range)| {
2514                                        let mut index_of_first_non_whitespace = 0;
2515                                        let line_starts_with_comment = snapshot
2516                                            .chars_for_range(range)
2517                                            .skip_while(|c| {
2518                                                let should_skip = c.is_whitespace();
2519                                                if should_skip {
2520                                                    index_of_first_non_whitespace += 1;
2521                                                }
2522                                                should_skip
2523                                            })
2524                                            .take(delimiter.len())
2525                                            .eq(delimiter.chars());
2526                                        let cursor_is_placed_after_comment_marker =
2527                                            index_of_first_non_whitespace + delimiter.len()
2528                                                <= start_point.column as usize;
2529                                        line_starts_with_comment
2530                                            && cursor_is_placed_after_comment_marker
2531                                    })
2532                                    .then(|| delimiter.clone())
2533                            } else {
2534                                None
2535                            };
2536                            (comment_delimiter, insert_extra_newline)
2537                        } else {
2538                            (None, false)
2539                        };
2540
2541                        let capacity_for_delimiter = comment_delimiter
2542                            .as_deref()
2543                            .map(str::len)
2544                            .unwrap_or_default();
2545                        let mut new_text =
2546                            String::with_capacity(1 + capacity_for_delimiter + indent.len as usize);
2547                        new_text.push_str("\n");
2548                        new_text.extend(indent.chars());
2549                        if let Some(delimiter) = &comment_delimiter {
2550                            new_text.push_str(&delimiter);
2551                        }
2552                        if insert_extra_newline {
2553                            new_text = new_text.repeat(2);
2554                        }
2555
2556                        let anchor = buffer.anchor_after(end);
2557                        let new_selection = selection.map(|_| anchor);
2558                        (
2559                            (start..end, new_text),
2560                            (insert_extra_newline, new_selection),
2561                        )
2562                    })
2563                    .unzip()
2564            };
2565
2566            this.edit_with_autoindent(edits, cx);
2567            let buffer = this.buffer.read(cx).snapshot(cx);
2568            let new_selections = selection_fixup_info
2569                .into_iter()
2570                .map(|(extra_newline_inserted, new_selection)| {
2571                    let mut cursor = new_selection.end.to_point(&buffer);
2572                    if extra_newline_inserted {
2573                        cursor.row -= 1;
2574                        cursor.column = buffer.line_len(cursor.row);
2575                    }
2576                    new_selection.map(|_| cursor)
2577                })
2578                .collect();
2579
2580            this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(new_selections));
2581            this.refresh_copilot_suggestions(true, cx);
2582        });
2583    }
2584
2585    pub fn newline_above(&mut self, _: &NewlineAbove, cx: &mut ViewContext<Self>) {
2586        let buffer = self.buffer.read(cx);
2587        let snapshot = buffer.snapshot(cx);
2588
2589        let mut edits = Vec::new();
2590        let mut rows = Vec::new();
2591        let mut rows_inserted = 0;
2592
2593        for selection in self.selections.all_adjusted(cx) {
2594            let cursor = selection.head();
2595            let row = cursor.row;
2596
2597            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
2598
2599            let newline = "\n".to_string();
2600            edits.push((start_of_line..start_of_line, newline));
2601
2602            rows.push(row + rows_inserted);
2603            rows_inserted += 1;
2604        }
2605
2606        self.transact(cx, |editor, cx| {
2607            editor.edit(edits, cx);
2608
2609            editor.change_selections(Some(Autoscroll::fit()), cx, |s| {
2610                let mut index = 0;
2611                s.move_cursors_with(|map, _, _| {
2612                    let row = rows[index];
2613                    index += 1;
2614
2615                    let point = Point::new(row, 0);
2616                    let boundary = map.next_line_boundary(point).1;
2617                    let clipped = map.clip_point(boundary, Bias::Left);
2618
2619                    (clipped, SelectionGoal::None)
2620                });
2621            });
2622
2623            let mut indent_edits = Vec::new();
2624            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
2625            for row in rows {
2626                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
2627                for (row, indent) in indents {
2628                    if indent.len == 0 {
2629                        continue;
2630                    }
2631
2632                    let text = match indent.kind {
2633                        IndentKind::Space => " ".repeat(indent.len as usize),
2634                        IndentKind::Tab => "\t".repeat(indent.len as usize),
2635                    };
2636                    let point = Point::new(row, 0);
2637                    indent_edits.push((point..point, text));
2638                }
2639            }
2640            editor.edit(indent_edits, cx);
2641        });
2642    }
2643
2644    pub fn newline_below(&mut self, _: &NewlineBelow, cx: &mut ViewContext<Self>) {
2645        let buffer = self.buffer.read(cx);
2646        let snapshot = buffer.snapshot(cx);
2647
2648        let mut edits = Vec::new();
2649        let mut rows = Vec::new();
2650        let mut rows_inserted = 0;
2651
2652        for selection in self.selections.all_adjusted(cx) {
2653            let cursor = selection.head();
2654            let row = cursor.row;
2655
2656            let point = Point::new(row + 1, 0);
2657            let start_of_line = snapshot.clip_point(point, Bias::Left);
2658
2659            let newline = "\n".to_string();
2660            edits.push((start_of_line..start_of_line, newline));
2661
2662            rows_inserted += 1;
2663            rows.push(row + rows_inserted);
2664        }
2665
2666        self.transact(cx, |editor, cx| {
2667            editor.edit(edits, cx);
2668
2669            editor.change_selections(Some(Autoscroll::fit()), cx, |s| {
2670                let mut index = 0;
2671                s.move_cursors_with(|map, _, _| {
2672                    let row = rows[index];
2673                    index += 1;
2674
2675                    let point = Point::new(row, 0);
2676                    let boundary = map.next_line_boundary(point).1;
2677                    let clipped = map.clip_point(boundary, Bias::Left);
2678
2679                    (clipped, SelectionGoal::None)
2680                });
2681            });
2682
2683            let mut indent_edits = Vec::new();
2684            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
2685            for row in rows {
2686                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
2687                for (row, indent) in indents {
2688                    if indent.len == 0 {
2689                        continue;
2690                    }
2691
2692                    let text = match indent.kind {
2693                        IndentKind::Space => " ".repeat(indent.len as usize),
2694                        IndentKind::Tab => "\t".repeat(indent.len as usize),
2695                    };
2696                    let point = Point::new(row, 0);
2697                    indent_edits.push((point..point, text));
2698                }
2699            }
2700            editor.edit(indent_edits, cx);
2701        });
2702    }
2703
2704    pub fn insert(&mut self, text: &str, cx: &mut ViewContext<Self>) {
2705        self.insert_with_autoindent_mode(
2706            text,
2707            Some(AutoindentMode::Block {
2708                original_indent_columns: Vec::new(),
2709            }),
2710            cx,
2711        );
2712    }
2713
2714    fn insert_with_autoindent_mode(
2715        &mut self,
2716        text: &str,
2717        autoindent_mode: Option<AutoindentMode>,
2718        cx: &mut ViewContext<Self>,
2719    ) {
2720        if self.read_only(cx) {
2721            return;
2722        }
2723
2724        let text: Arc<str> = text.into();
2725        self.transact(cx, |this, cx| {
2726            let old_selections = this.selections.all_adjusted(cx);
2727            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
2728                let anchors = {
2729                    let snapshot = buffer.read(cx);
2730                    old_selections
2731                        .iter()
2732                        .map(|s| {
2733                            let anchor = snapshot.anchor_after(s.head());
2734                            s.map(|_| anchor)
2735                        })
2736                        .collect::<Vec<_>>()
2737                };
2738                buffer.edit(
2739                    old_selections
2740                        .iter()
2741                        .map(|s| (s.start..s.end, text.clone())),
2742                    autoindent_mode,
2743                    cx,
2744                );
2745                anchors
2746            });
2747
2748            this.change_selections(Some(Autoscroll::fit()), cx, |s| {
2749                s.select_anchors(selection_anchors);
2750            })
2751        });
2752    }
2753
2754    fn trigger_completion_on_input(&mut self, text: &str, cx: &mut ViewContext<Self>) {
2755        if !EditorSettings::get_global(cx).show_completions_on_input {
2756            return;
2757        }
2758
2759        let selection = self.selections.newest_anchor();
2760        if self
2761            .buffer
2762            .read(cx)
2763            .is_completion_trigger(selection.head(), text, cx)
2764        {
2765            self.show_completions(&ShowCompletions, cx);
2766        } else {
2767            self.hide_context_menu(cx);
2768        }
2769    }
2770
2771    /// If any empty selections is touching the start of its innermost containing autoclose
2772    /// region, expand it to select the brackets.
2773    fn select_autoclose_pair(&mut self, cx: &mut ViewContext<Self>) {
2774        let selections = self.selections.all::<usize>(cx);
2775        let buffer = self.buffer.read(cx).read(cx);
2776        let mut new_selections = Vec::new();
2777        for (mut selection, region) in self.selections_with_autoclose_regions(selections, &buffer) {
2778            if let (Some(region), true) = (region, selection.is_empty()) {
2779                let mut range = region.range.to_offset(&buffer);
2780                if selection.start == range.start {
2781                    if range.start >= region.pair.start.len() {
2782                        range.start -= region.pair.start.len();
2783                        if buffer.contains_str_at(range.start, &region.pair.start) {
2784                            if buffer.contains_str_at(range.end, &region.pair.end) {
2785                                range.end += region.pair.end.len();
2786                                selection.start = range.start;
2787                                selection.end = range.end;
2788                            }
2789                        }
2790                    }
2791                }
2792            }
2793            new_selections.push(selection);
2794        }
2795
2796        drop(buffer);
2797        self.change_selections(None, cx, |selections| selections.select(new_selections));
2798    }
2799
2800    /// Iterate the given selections, and for each one, find the smallest surrounding
2801    /// autoclose region. This uses the ordering of the selections and the autoclose
2802    /// regions to avoid repeated comparisons.
2803    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
2804        &'a self,
2805        selections: impl IntoIterator<Item = Selection<D>>,
2806        buffer: &'a MultiBufferSnapshot,
2807    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
2808        let mut i = 0;
2809        let mut regions = self.autoclose_regions.as_slice();
2810        selections.into_iter().map(move |selection| {
2811            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
2812
2813            let mut enclosing = None;
2814            while let Some(pair_state) = regions.get(i) {
2815                if pair_state.range.end.to_offset(buffer) < range.start {
2816                    regions = &regions[i + 1..];
2817                    i = 0;
2818                } else if pair_state.range.start.to_offset(buffer) > range.end {
2819                    break;
2820                } else {
2821                    if pair_state.selection_id == selection.id {
2822                        enclosing = Some(pair_state);
2823                    }
2824                    i += 1;
2825                }
2826            }
2827
2828            (selection.clone(), enclosing)
2829        })
2830    }
2831
2832    /// Remove any autoclose regions that no longer contain their selection.
2833    fn invalidate_autoclose_regions(
2834        &mut self,
2835        mut selections: &[Selection<Anchor>],
2836        buffer: &MultiBufferSnapshot,
2837    ) {
2838        self.autoclose_regions.retain(|state| {
2839            let mut i = 0;
2840            while let Some(selection) = selections.get(i) {
2841                if selection.end.cmp(&state.range.start, buffer).is_lt() {
2842                    selections = &selections[1..];
2843                    continue;
2844                }
2845                if selection.start.cmp(&state.range.end, buffer).is_gt() {
2846                    break;
2847                }
2848                if selection.id == state.selection_id {
2849                    return true;
2850                } else {
2851                    i += 1;
2852                }
2853            }
2854            false
2855        });
2856    }
2857
2858    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
2859        let offset = position.to_offset(buffer);
2860        let (word_range, kind) = buffer.surrounding_word(offset);
2861        if offset > word_range.start && kind == Some(CharKind::Word) {
2862            Some(
2863                buffer
2864                    .text_for_range(word_range.start..offset)
2865                    .collect::<String>(),
2866            )
2867        } else {
2868            None
2869        }
2870    }
2871
2872    pub fn toggle_inlay_hints(&mut self, _: &ToggleInlayHints, cx: &mut ViewContext<Self>) {
2873        self.refresh_inlay_hints(
2874            InlayHintRefreshReason::Toggle(!self.inlay_hint_cache.enabled),
2875            cx,
2876        );
2877    }
2878
2879    pub fn inlay_hints_enabled(&self) -> bool {
2880        self.inlay_hint_cache.enabled
2881    }
2882
2883    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut ViewContext<Self>) {
2884        if self.project.is_none() || self.mode != EditorMode::Full {
2885            return;
2886        }
2887
2888        let reason_description = reason.description();
2889        let (invalidate_cache, required_languages) = match reason {
2890            InlayHintRefreshReason::Toggle(enabled) => {
2891                self.inlay_hint_cache.enabled = enabled;
2892                if enabled {
2893                    (InvalidationStrategy::RefreshRequested, None)
2894                } else {
2895                    self.inlay_hint_cache.clear();
2896                    self.splice_inlay_hints(
2897                        self.visible_inlay_hints(cx)
2898                            .iter()
2899                            .map(|inlay| inlay.id)
2900                            .collect(),
2901                        Vec::new(),
2902                        cx,
2903                    );
2904                    return;
2905                }
2906            }
2907            InlayHintRefreshReason::SettingsChange(new_settings) => {
2908                match self.inlay_hint_cache.update_settings(
2909                    &self.buffer,
2910                    new_settings,
2911                    self.visible_inlay_hints(cx),
2912                    cx,
2913                ) {
2914                    ControlFlow::Break(Some(InlaySplice {
2915                        to_remove,
2916                        to_insert,
2917                    })) => {
2918                        self.splice_inlay_hints(to_remove, to_insert, cx);
2919                        return;
2920                    }
2921                    ControlFlow::Break(None) => return,
2922                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
2923                }
2924            }
2925            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
2926                if let Some(InlaySplice {
2927                    to_remove,
2928                    to_insert,
2929                }) = self.inlay_hint_cache.remove_excerpts(excerpts_removed)
2930                {
2931                    self.splice_inlay_hints(to_remove, to_insert, cx);
2932                }
2933                return;
2934            }
2935            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
2936            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
2937                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
2938            }
2939            InlayHintRefreshReason::RefreshRequested => {
2940                (InvalidationStrategy::RefreshRequested, None)
2941            }
2942        };
2943
2944        if let Some(InlaySplice {
2945            to_remove,
2946            to_insert,
2947        }) = self.inlay_hint_cache.spawn_hint_refresh(
2948            reason_description,
2949            self.excerpts_for_inlay_hints_query(required_languages.as_ref(), cx),
2950            invalidate_cache,
2951            cx,
2952        ) {
2953            self.splice_inlay_hints(to_remove, to_insert, cx);
2954        }
2955    }
2956
2957    fn visible_inlay_hints(&self, cx: &ViewContext<'_, Editor>) -> Vec<Inlay> {
2958        self.display_map
2959            .read(cx)
2960            .current_inlays()
2961            .filter(move |inlay| {
2962                Some(inlay.id) != self.copilot_state.suggestion.as_ref().map(|h| h.id)
2963            })
2964            .cloned()
2965            .collect()
2966    }
2967
2968    pub fn excerpts_for_inlay_hints_query(
2969        &self,
2970        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
2971        cx: &mut ViewContext<Editor>,
2972    ) -> HashMap<ExcerptId, (Model<Buffer>, clock::Global, Range<usize>)> {
2973        let Some(project) = self.project.as_ref() else {
2974            return HashMap::default();
2975        };
2976        let project = project.read(cx);
2977        let multi_buffer = self.buffer().read(cx);
2978        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
2979        let multi_buffer_visible_start = self
2980            .scroll_manager
2981            .anchor()
2982            .anchor
2983            .to_point(&multi_buffer_snapshot);
2984        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
2985            multi_buffer_visible_start
2986                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
2987            Bias::Left,
2988        );
2989        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
2990        multi_buffer
2991            .range_to_buffer_ranges(multi_buffer_visible_range, cx)
2992            .into_iter()
2993            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
2994            .filter_map(|(buffer_handle, excerpt_visible_range, excerpt_id)| {
2995                let buffer = buffer_handle.read(cx);
2996                let buffer_file = project::worktree::File::from_dyn(buffer.file())?;
2997                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
2998                let worktree_entry = buffer_worktree
2999                    .read(cx)
3000                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
3001                if worktree_entry.is_ignored {
3002                    return None;
3003                }
3004
3005                let language = buffer.language()?;
3006                if let Some(restrict_to_languages) = restrict_to_languages {
3007                    if !restrict_to_languages.contains(language) {
3008                        return None;
3009                    }
3010                }
3011                Some((
3012                    excerpt_id,
3013                    (
3014                        buffer_handle,
3015                        buffer.version().clone(),
3016                        excerpt_visible_range,
3017                    ),
3018                ))
3019            })
3020            .collect()
3021    }
3022
3023    pub fn text_layout_details(&self, cx: &WindowContext) -> TextLayoutDetails {
3024        TextLayoutDetails {
3025            text_system: cx.text_system().clone(),
3026            editor_style: self.style.clone().unwrap(),
3027            rem_size: cx.rem_size(),
3028        }
3029    }
3030
3031    fn splice_inlay_hints(
3032        &self,
3033        to_remove: Vec<InlayId>,
3034        to_insert: Vec<Inlay>,
3035        cx: &mut ViewContext<Self>,
3036    ) {
3037        self.display_map.update(cx, |display_map, cx| {
3038            display_map.splice_inlays(to_remove, to_insert, cx);
3039        });
3040        cx.notify();
3041    }
3042
3043    fn trigger_on_type_formatting(
3044        &self,
3045        input: String,
3046        cx: &mut ViewContext<Self>,
3047    ) -> Option<Task<Result<()>>> {
3048        if input.len() != 1 {
3049            return None;
3050        }
3051
3052        let project = self.project.as_ref()?;
3053        let position = self.selections.newest_anchor().head();
3054        let (buffer, buffer_position) = self
3055            .buffer
3056            .read(cx)
3057            .text_anchor_for_position(position.clone(), cx)?;
3058
3059        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
3060        // hence we do LSP request & edit on host side only — add formats to host's history.
3061        let push_to_lsp_host_history = true;
3062        // If this is not the host, append its history with new edits.
3063        let push_to_client_history = project.read(cx).is_remote();
3064
3065        let on_type_formatting = project.update(cx, |project, cx| {
3066            project.on_type_format(
3067                buffer.clone(),
3068                buffer_position,
3069                input,
3070                push_to_lsp_host_history,
3071                cx,
3072            )
3073        });
3074        Some(cx.spawn(|editor, mut cx| async move {
3075            if let Some(transaction) = on_type_formatting.await? {
3076                if push_to_client_history {
3077                    buffer
3078                        .update(&mut cx, |buffer, _| {
3079                            buffer.push_transaction(transaction, Instant::now());
3080                        })
3081                        .ok();
3082                }
3083                editor.update(&mut cx, |editor, cx| {
3084                    editor.refresh_document_highlights(cx);
3085                })?;
3086            }
3087            Ok(())
3088        }))
3089    }
3090
3091    fn show_completions(&mut self, _: &ShowCompletions, cx: &mut ViewContext<Self>) {
3092        if self.pending_rename.is_some() {
3093            return;
3094        }
3095
3096        let Some(provider) = self.completion_provider.as_ref() else {
3097            return;
3098        };
3099
3100        let position = self.selections.newest_anchor().head();
3101        let (buffer, buffer_position) = if let Some(output) = self
3102            .buffer
3103            .read(cx)
3104            .text_anchor_for_position(position.clone(), cx)
3105        {
3106            output
3107        } else {
3108            return;
3109        };
3110
3111        let query = Self::completion_query(&self.buffer.read(cx).read(cx), position.clone());
3112        let completions = provider.completions(&buffer, buffer_position, cx);
3113
3114        let id = post_inc(&mut self.next_completion_id);
3115        let task = cx.spawn(|this, mut cx| {
3116            async move {
3117                let completions = completions.await.log_err();
3118                let (menu, pre_resolve_task) = if let Some(completions) = completions {
3119                    let mut menu = CompletionsMenu {
3120                        id,
3121                        initial_position: position,
3122                        match_candidates: completions
3123                            .iter()
3124                            .enumerate()
3125                            .map(|(id, completion)| {
3126                                StringMatchCandidate::new(
3127                                    id,
3128                                    completion.label.text[completion.label.filter_range.clone()]
3129                                        .into(),
3130                                )
3131                            })
3132                            .collect(),
3133                        buffer,
3134                        completions: Arc::new(RwLock::new(completions.into())),
3135                        matches: Vec::new().into(),
3136                        selected_item: 0,
3137                        scroll_handle: UniformListScrollHandle::new(),
3138                    };
3139                    menu.filter(query.as_deref(), cx.background_executor().clone())
3140                        .await;
3141
3142                    if menu.matches.is_empty() {
3143                        (None, None)
3144                    } else {
3145                        let pre_resolve_task = this
3146                            .update(&mut cx, |editor, cx| {
3147                                menu.pre_resolve_completion_documentation(editor, cx)
3148                            })
3149                            .ok()
3150                            .flatten();
3151                        (Some(menu), pre_resolve_task)
3152                    }
3153                } else {
3154                    (None, None)
3155                };
3156
3157                this.update(&mut cx, |this, cx| {
3158                    this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
3159
3160                    let mut context_menu = this.context_menu.write();
3161                    match context_menu.as_ref() {
3162                        None => {}
3163
3164                        Some(ContextMenu::Completions(prev_menu)) => {
3165                            if prev_menu.id > id {
3166                                return;
3167                            }
3168                        }
3169
3170                        _ => return,
3171                    }
3172
3173                    if this.focus_handle.is_focused(cx) && menu.is_some() {
3174                        let menu = menu.unwrap();
3175                        *context_menu = Some(ContextMenu::Completions(menu));
3176                        drop(context_menu);
3177                        this.discard_copilot_suggestion(cx);
3178                        cx.notify();
3179                    } else if this.completion_tasks.len() <= 1 {
3180                        // If there are no more completion tasks and the last menu was
3181                        // empty, we should hide it. If it was already hidden, we should
3182                        // also show the copilot suggestion when available.
3183                        drop(context_menu);
3184                        if this.hide_context_menu(cx).is_none() {
3185                            this.update_visible_copilot_suggestion(cx);
3186                        }
3187                    }
3188                })?;
3189
3190                if let Some(pre_resolve_task) = pre_resolve_task {
3191                    pre_resolve_task.await;
3192                }
3193
3194                Ok::<_, anyhow::Error>(())
3195            }
3196            .log_err()
3197        });
3198
3199        self.completion_tasks.push((id, task));
3200    }
3201
3202    pub fn confirm_completion(
3203        &mut self,
3204        action: &ConfirmCompletion,
3205        cx: &mut ViewContext<Self>,
3206    ) -> Option<Task<Result<()>>> {
3207        use language::ToOffset as _;
3208
3209        let completions_menu = if let ContextMenu::Completions(menu) = self.hide_context_menu(cx)? {
3210            menu
3211        } else {
3212            return None;
3213        };
3214
3215        let mat = completions_menu
3216            .matches
3217            .get(action.item_ix.unwrap_or(completions_menu.selected_item))?;
3218        let buffer_handle = completions_menu.buffer;
3219        let completions = completions_menu.completions.read();
3220        let completion = completions.get(mat.candidate_id)?;
3221        cx.stop_propagation();
3222
3223        let snippet;
3224        let text;
3225        if completion.is_snippet() {
3226            snippet = Some(Snippet::parse(&completion.new_text).log_err()?);
3227            text = snippet.as_ref().unwrap().text.clone();
3228        } else {
3229            snippet = None;
3230            text = completion.new_text.clone();
3231        };
3232        let selections = self.selections.all::<usize>(cx);
3233        let buffer = buffer_handle.read(cx);
3234        let old_range = completion.old_range.to_offset(buffer);
3235        let old_text = buffer.text_for_range(old_range.clone()).collect::<String>();
3236
3237        let newest_selection = self.selections.newest_anchor();
3238        if newest_selection.start.buffer_id != Some(buffer_handle.read(cx).remote_id()) {
3239            return None;
3240        }
3241
3242        let lookbehind = newest_selection
3243            .start
3244            .text_anchor
3245            .to_offset(buffer)
3246            .saturating_sub(old_range.start);
3247        let lookahead = old_range
3248            .end
3249            .saturating_sub(newest_selection.end.text_anchor.to_offset(buffer));
3250        let mut common_prefix_len = old_text
3251            .bytes()
3252            .zip(text.bytes())
3253            .take_while(|(a, b)| a == b)
3254            .count();
3255
3256        let snapshot = self.buffer.read(cx).snapshot(cx);
3257        let mut range_to_replace: Option<Range<isize>> = None;
3258        let mut ranges = Vec::new();
3259        for selection in &selections {
3260            if snapshot.contains_str_at(selection.start.saturating_sub(lookbehind), &old_text) {
3261                let start = selection.start.saturating_sub(lookbehind);
3262                let end = selection.end + lookahead;
3263                if selection.id == newest_selection.id {
3264                    range_to_replace = Some(
3265                        ((start + common_prefix_len) as isize - selection.start as isize)
3266                            ..(end as isize - selection.start as isize),
3267                    );
3268                }
3269                ranges.push(start + common_prefix_len..end);
3270            } else {
3271                common_prefix_len = 0;
3272                ranges.clear();
3273                ranges.extend(selections.iter().map(|s| {
3274                    if s.id == newest_selection.id {
3275                        range_to_replace = Some(
3276                            old_range.start.to_offset_utf16(&snapshot).0 as isize
3277                                - selection.start as isize
3278                                ..old_range.end.to_offset_utf16(&snapshot).0 as isize
3279                                    - selection.start as isize,
3280                        );
3281                        old_range.clone()
3282                    } else {
3283                        s.start..s.end
3284                    }
3285                }));
3286                break;
3287            }
3288        }
3289        let text = &text[common_prefix_len..];
3290
3291        cx.emit(EditorEvent::InputHandled {
3292            utf16_range_to_replace: range_to_replace,
3293            text: text.into(),
3294        });
3295
3296        self.transact(cx, |this, cx| {
3297            if let Some(mut snippet) = snippet {
3298                snippet.text = text.to_string();
3299                for tabstop in snippet.tabstops.iter_mut().flatten() {
3300                    tabstop.start -= common_prefix_len as isize;
3301                    tabstop.end -= common_prefix_len as isize;
3302                }
3303
3304                this.insert_snippet(&ranges, snippet, cx).log_err();
3305            } else {
3306                this.buffer.update(cx, |buffer, cx| {
3307                    buffer.edit(
3308                        ranges.iter().map(|range| (range.clone(), text)),
3309                        this.autoindent_mode.clone(),
3310                        cx,
3311                    );
3312                });
3313            }
3314
3315            this.refresh_copilot_suggestions(true, cx);
3316        });
3317
3318        let provider = self.completion_provider.as_ref()?;
3319        let apply_edits = provider.apply_additional_edits_for_completion(
3320            buffer_handle,
3321            completion.clone(),
3322            true,
3323            cx,
3324        );
3325        Some(cx.foreground_executor().spawn(async move {
3326            apply_edits.await?;
3327            Ok(())
3328        }))
3329    }
3330
3331    pub fn toggle_code_actions(&mut self, action: &ToggleCodeActions, cx: &mut ViewContext<Self>) {
3332        let mut context_menu = self.context_menu.write();
3333        if matches!(context_menu.as_ref(), Some(ContextMenu::CodeActions(_))) {
3334            *context_menu = None;
3335            cx.notify();
3336            return;
3337        }
3338        drop(context_menu);
3339
3340        let deployed_from_indicator = action.deployed_from_indicator;
3341        let mut task = self.code_actions_task.take();
3342        cx.spawn(|this, mut cx| async move {
3343            while let Some(prev_task) = task {
3344                prev_task.await;
3345                task = this.update(&mut cx, |this, _| this.code_actions_task.take())?;
3346            }
3347
3348            this.update(&mut cx, |this, cx| {
3349                if this.focus_handle.is_focused(cx) {
3350                    if let Some((buffer, actions)) = this.available_code_actions.clone() {
3351                        this.completion_tasks.clear();
3352                        this.discard_copilot_suggestion(cx);
3353                        *this.context_menu.write() =
3354                            Some(ContextMenu::CodeActions(CodeActionsMenu {
3355                                buffer,
3356                                actions,
3357                                selected_item: Default::default(),
3358                                scroll_handle: UniformListScrollHandle::default(),
3359                                deployed_from_indicator,
3360                            }));
3361                        cx.notify();
3362                    }
3363                }
3364            })?;
3365
3366            Ok::<_, anyhow::Error>(())
3367        })
3368        .detach_and_log_err(cx);
3369    }
3370
3371    pub fn confirm_code_action(
3372        &mut self,
3373        action: &ConfirmCodeAction,
3374        cx: &mut ViewContext<Self>,
3375    ) -> Option<Task<Result<()>>> {
3376        let actions_menu = if let ContextMenu::CodeActions(menu) = self.hide_context_menu(cx)? {
3377            menu
3378        } else {
3379            return None;
3380        };
3381        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
3382        let action = actions_menu.actions.get(action_ix)?.clone();
3383        let title = action.lsp_action.title.clone();
3384        let buffer = actions_menu.buffer;
3385        let workspace = self.workspace()?;
3386
3387        let apply_code_actions = workspace
3388            .read(cx)
3389            .project()
3390            .clone()
3391            .update(cx, |project, cx| {
3392                project.apply_code_action(buffer, action, true, cx)
3393            });
3394        let workspace = workspace.downgrade();
3395        Some(cx.spawn(|editor, cx| async move {
3396            let project_transaction = apply_code_actions.await?;
3397            Self::open_project_transaction(&editor, workspace, project_transaction, title, cx).await
3398        }))
3399    }
3400
3401    async fn open_project_transaction(
3402        this: &WeakView<Editor>,
3403        workspace: WeakView<Workspace>,
3404        transaction: ProjectTransaction,
3405        title: String,
3406        mut cx: AsyncWindowContext,
3407    ) -> Result<()> {
3408        let replica_id = this.update(&mut cx, |this, cx| this.replica_id(cx))?;
3409
3410        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
3411        cx.update(|cx| {
3412            entries.sort_unstable_by_key(|(buffer, _)| {
3413                buffer.read(cx).file().map(|f| f.path().clone())
3414            });
3415        })?;
3416
3417        // If the project transaction's edits are all contained within this editor, then
3418        // avoid opening a new editor to display them.
3419
3420        if let Some((buffer, transaction)) = entries.first() {
3421            if entries.len() == 1 {
3422                let excerpt = this.update(&mut cx, |editor, cx| {
3423                    editor
3424                        .buffer()
3425                        .read(cx)
3426                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
3427                })?;
3428                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt {
3429                    if excerpted_buffer == *buffer {
3430                        let all_edits_within_excerpt = buffer.read_with(&cx, |buffer, _| {
3431                            let excerpt_range = excerpt_range.to_offset(buffer);
3432                            buffer
3433                                .edited_ranges_for_transaction::<usize>(transaction)
3434                                .all(|range| {
3435                                    excerpt_range.start <= range.start
3436                                        && excerpt_range.end >= range.end
3437                                })
3438                        })?;
3439
3440                        if all_edits_within_excerpt {
3441                            return Ok(());
3442                        }
3443                    }
3444                }
3445            }
3446        } else {
3447            return Ok(());
3448        }
3449
3450        let mut ranges_to_highlight = Vec::new();
3451        let excerpt_buffer = cx.new_model(|cx| {
3452            let mut multibuffer =
3453                MultiBuffer::new(replica_id, Capability::ReadWrite).with_title(title);
3454            for (buffer_handle, transaction) in &entries {
3455                let buffer = buffer_handle.read(cx);
3456                ranges_to_highlight.extend(
3457                    multibuffer.push_excerpts_with_context_lines(
3458                        buffer_handle.clone(),
3459                        buffer
3460                            .edited_ranges_for_transaction::<usize>(transaction)
3461                            .collect(),
3462                        1,
3463                        cx,
3464                    ),
3465                );
3466            }
3467            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
3468            multibuffer
3469        })?;
3470
3471        workspace.update(&mut cx, |workspace, cx| {
3472            let project = workspace.project().clone();
3473            let editor =
3474                cx.new_view(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), cx));
3475            workspace.add_item(Box::new(editor.clone()), cx);
3476            editor.update(cx, |editor, cx| {
3477                editor.highlight_background::<Self>(
3478                    ranges_to_highlight,
3479                    |theme| theme.editor_highlighted_line_background,
3480                    cx,
3481                );
3482            });
3483        })?;
3484
3485        Ok(())
3486    }
3487
3488    fn refresh_code_actions(&mut self, cx: &mut ViewContext<Self>) -> Option<()> {
3489        let project = self.project.clone()?;
3490        let buffer = self.buffer.read(cx);
3491        let newest_selection = self.selections.newest_anchor().clone();
3492        let (start_buffer, start) = buffer.text_anchor_for_position(newest_selection.start, cx)?;
3493        let (end_buffer, end) = buffer.text_anchor_for_position(newest_selection.end, cx)?;
3494        if start_buffer != end_buffer {
3495            return None;
3496        }
3497
3498        self.code_actions_task = Some(cx.spawn(|this, mut cx| async move {
3499            cx.background_executor()
3500                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
3501                .await;
3502
3503            let actions = if let Ok(code_actions) = project.update(&mut cx, |project, cx| {
3504                project.code_actions(&start_buffer, start..end, cx)
3505            }) {
3506                code_actions.await.log_err()
3507            } else {
3508                None
3509            };
3510
3511            this.update(&mut cx, |this, cx| {
3512                this.available_code_actions = actions.and_then(|actions| {
3513                    if actions.is_empty() {
3514                        None
3515                    } else {
3516                        Some((start_buffer, actions.into()))
3517                    }
3518                });
3519                cx.notify();
3520            })
3521            .log_err();
3522        }));
3523        None
3524    }
3525
3526    fn refresh_document_highlights(&mut self, cx: &mut ViewContext<Self>) -> Option<()> {
3527        if self.pending_rename.is_some() {
3528            return None;
3529        }
3530
3531        let project = self.project.clone()?;
3532        let buffer = self.buffer.read(cx);
3533        let newest_selection = self.selections.newest_anchor().clone();
3534        let cursor_position = newest_selection.head();
3535        let (cursor_buffer, cursor_buffer_position) =
3536            buffer.text_anchor_for_position(cursor_position.clone(), cx)?;
3537        let (tail_buffer, _) = buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
3538        if cursor_buffer != tail_buffer {
3539            return None;
3540        }
3541
3542        self.document_highlights_task = Some(cx.spawn(|this, mut cx| async move {
3543            cx.background_executor()
3544                .timer(DOCUMENT_HIGHLIGHTS_DEBOUNCE_TIMEOUT)
3545                .await;
3546
3547            let highlights = if let Some(highlights) = project
3548                .update(&mut cx, |project, cx| {
3549                    project.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
3550                })
3551                .log_err()
3552            {
3553                highlights.await.log_err()
3554            } else {
3555                None
3556            };
3557
3558            if let Some(highlights) = highlights {
3559                this.update(&mut cx, |this, cx| {
3560                    if this.pending_rename.is_some() {
3561                        return;
3562                    }
3563
3564                    let buffer_id = cursor_position.buffer_id;
3565                    let buffer = this.buffer.read(cx);
3566                    if !buffer
3567                        .text_anchor_for_position(cursor_position, cx)
3568                        .map_or(false, |(buffer, _)| buffer == cursor_buffer)
3569                    {
3570                        return;
3571                    }
3572
3573                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
3574                    let mut write_ranges = Vec::new();
3575                    let mut read_ranges = Vec::new();
3576                    for highlight in highlights {
3577                        for (excerpt_id, excerpt_range) in
3578                            buffer.excerpts_for_buffer(&cursor_buffer, cx)
3579                        {
3580                            let start = highlight
3581                                .range
3582                                .start
3583                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
3584                            let end = highlight
3585                                .range
3586                                .end
3587                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
3588                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
3589                                continue;
3590                            }
3591
3592                            let range = Anchor {
3593                                buffer_id,
3594                                excerpt_id: excerpt_id.clone(),
3595                                text_anchor: start,
3596                            }..Anchor {
3597                                buffer_id,
3598                                excerpt_id,
3599                                text_anchor: end,
3600                            };
3601                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
3602                                write_ranges.push(range);
3603                            } else {
3604                                read_ranges.push(range);
3605                            }
3606                        }
3607                    }
3608
3609                    this.highlight_background::<DocumentHighlightRead>(
3610                        read_ranges,
3611                        |theme| theme.editor_document_highlight_read_background,
3612                        cx,
3613                    );
3614                    this.highlight_background::<DocumentHighlightWrite>(
3615                        write_ranges,
3616                        |theme| theme.editor_document_highlight_write_background,
3617                        cx,
3618                    );
3619                    cx.notify();
3620                })
3621                .log_err();
3622            }
3623        }));
3624        None
3625    }
3626
3627    fn refresh_copilot_suggestions(
3628        &mut self,
3629        debounce: bool,
3630        cx: &mut ViewContext<Self>,
3631    ) -> Option<()> {
3632        let copilot = Copilot::global(cx)?;
3633        if !self.show_copilot_suggestions || !copilot.read(cx).status().is_authorized() {
3634            self.clear_copilot_suggestions(cx);
3635            return None;
3636        }
3637        self.update_visible_copilot_suggestion(cx);
3638
3639        let snapshot = self.buffer.read(cx).snapshot(cx);
3640        let cursor = self.selections.newest_anchor().head();
3641        if !self.is_copilot_enabled_at(cursor, &snapshot, cx) {
3642            self.clear_copilot_suggestions(cx);
3643            return None;
3644        }
3645
3646        let (buffer, buffer_position) =
3647            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
3648        self.copilot_state.pending_refresh = cx.spawn(|this, mut cx| async move {
3649            if debounce {
3650                cx.background_executor()
3651                    .timer(COPILOT_DEBOUNCE_TIMEOUT)
3652                    .await;
3653            }
3654
3655            let completions = copilot
3656                .update(&mut cx, |copilot, cx| {
3657                    copilot.completions(&buffer, buffer_position, cx)
3658                })
3659                .log_err()
3660                .unwrap_or(Task::ready(Ok(Vec::new())))
3661                .await
3662                .log_err()
3663                .into_iter()
3664                .flatten()
3665                .collect_vec();
3666
3667            this.update(&mut cx, |this, cx| {
3668                if !completions.is_empty() {
3669                    this.copilot_state.cycled = false;
3670                    this.copilot_state.pending_cycling_refresh = Task::ready(None);
3671                    this.copilot_state.completions.clear();
3672                    this.copilot_state.active_completion_index = 0;
3673                    this.copilot_state.excerpt_id = Some(cursor.excerpt_id);
3674                    for completion in completions {
3675                        this.copilot_state.push_completion(completion);
3676                    }
3677                    this.update_visible_copilot_suggestion(cx);
3678                }
3679            })
3680            .log_err()?;
3681            Some(())
3682        });
3683
3684        Some(())
3685    }
3686
3687    fn cycle_copilot_suggestions(
3688        &mut self,
3689        direction: Direction,
3690        cx: &mut ViewContext<Self>,
3691    ) -> Option<()> {
3692        let copilot = Copilot::global(cx)?;
3693        if !self.show_copilot_suggestions || !copilot.read(cx).status().is_authorized() {
3694            return None;
3695        }
3696
3697        if self.copilot_state.cycled {
3698            self.copilot_state.cycle_completions(direction);
3699            self.update_visible_copilot_suggestion(cx);
3700        } else {
3701            let cursor = self.selections.newest_anchor().head();
3702            let (buffer, buffer_position) =
3703                self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
3704            self.copilot_state.pending_cycling_refresh = cx.spawn(|this, mut cx| async move {
3705                let completions = copilot
3706                    .update(&mut cx, |copilot, cx| {
3707                        copilot.completions_cycling(&buffer, buffer_position, cx)
3708                    })
3709                    .log_err()?
3710                    .await;
3711
3712                this.update(&mut cx, |this, cx| {
3713                    this.copilot_state.cycled = true;
3714                    for completion in completions.log_err().into_iter().flatten() {
3715                        this.copilot_state.push_completion(completion);
3716                    }
3717                    this.copilot_state.cycle_completions(direction);
3718                    this.update_visible_copilot_suggestion(cx);
3719                })
3720                .log_err()?;
3721
3722                Some(())
3723            });
3724        }
3725
3726        Some(())
3727    }
3728
3729    fn copilot_suggest(&mut self, _: &copilot::Suggest, cx: &mut ViewContext<Self>) {
3730        if !self.has_active_copilot_suggestion(cx) {
3731            self.refresh_copilot_suggestions(false, cx);
3732            return;
3733        }
3734
3735        self.update_visible_copilot_suggestion(cx);
3736    }
3737
3738    pub fn display_cursor_names(&mut self, _: &DisplayCursorNames, cx: &mut ViewContext<Self>) {
3739        self.show_cursor_names(cx);
3740    }
3741
3742    fn show_cursor_names(&mut self, cx: &mut ViewContext<Self>) {
3743        self.show_cursor_names = true;
3744        cx.notify();
3745        cx.spawn(|this, mut cx| async move {
3746            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
3747            this.update(&mut cx, |this, cx| {
3748                this.show_cursor_names = false;
3749                cx.notify()
3750            })
3751            .ok()
3752        })
3753        .detach();
3754    }
3755
3756    fn next_copilot_suggestion(&mut self, _: &copilot::NextSuggestion, cx: &mut ViewContext<Self>) {
3757        if self.has_active_copilot_suggestion(cx) {
3758            self.cycle_copilot_suggestions(Direction::Next, cx);
3759        } else {
3760            let is_copilot_disabled = self.refresh_copilot_suggestions(false, cx).is_none();
3761            if is_copilot_disabled {
3762                cx.propagate();
3763            }
3764        }
3765    }
3766
3767    fn previous_copilot_suggestion(
3768        &mut self,
3769        _: &copilot::PreviousSuggestion,
3770        cx: &mut ViewContext<Self>,
3771    ) {
3772        if self.has_active_copilot_suggestion(cx) {
3773            self.cycle_copilot_suggestions(Direction::Prev, cx);
3774        } else {
3775            let is_copilot_disabled = self.refresh_copilot_suggestions(false, cx).is_none();
3776            if is_copilot_disabled {
3777                cx.propagate();
3778            }
3779        }
3780    }
3781
3782    fn accept_copilot_suggestion(&mut self, cx: &mut ViewContext<Self>) -> bool {
3783        if let Some(suggestion) = self.take_active_copilot_suggestion(cx) {
3784            if let Some((copilot, completion)) =
3785                Copilot::global(cx).zip(self.copilot_state.active_completion())
3786            {
3787                copilot
3788                    .update(cx, |copilot, cx| copilot.accept_completion(completion, cx))
3789                    .detach_and_log_err(cx);
3790
3791                self.report_copilot_event(Some(completion.uuid.clone()), true, cx)
3792            }
3793            cx.emit(EditorEvent::InputHandled {
3794                utf16_range_to_replace: None,
3795                text: suggestion.text.to_string().into(),
3796            });
3797            self.insert_with_autoindent_mode(&suggestion.text.to_string(), None, cx);
3798            cx.notify();
3799            true
3800        } else {
3801            false
3802        }
3803    }
3804
3805    fn discard_copilot_suggestion(&mut self, cx: &mut ViewContext<Self>) -> bool {
3806        if let Some(suggestion) = self.take_active_copilot_suggestion(cx) {
3807            if let Some(copilot) = Copilot::global(cx) {
3808                copilot
3809                    .update(cx, |copilot, cx| {
3810                        copilot.discard_completions(&self.copilot_state.completions, cx)
3811                    })
3812                    .detach_and_log_err(cx);
3813
3814                self.report_copilot_event(None, false, cx)
3815            }
3816
3817            self.display_map.update(cx, |map, cx| {
3818                map.splice_inlays(vec![suggestion.id], Vec::new(), cx)
3819            });
3820            cx.notify();
3821            true
3822        } else {
3823            false
3824        }
3825    }
3826
3827    fn is_copilot_enabled_at(
3828        &self,
3829        location: Anchor,
3830        snapshot: &MultiBufferSnapshot,
3831        cx: &mut ViewContext<Self>,
3832    ) -> bool {
3833        let file = snapshot.file_at(location);
3834        let language = snapshot.language_at(location);
3835        let settings = all_language_settings(file, cx);
3836        self.show_copilot_suggestions
3837            && settings.copilot_enabled(language, file.map(|f| f.path().as_ref()))
3838    }
3839
3840    fn has_active_copilot_suggestion(&self, cx: &AppContext) -> bool {
3841        if let Some(suggestion) = self.copilot_state.suggestion.as_ref() {
3842            let buffer = self.buffer.read(cx).read(cx);
3843            suggestion.position.is_valid(&buffer)
3844        } else {
3845            false
3846        }
3847    }
3848
3849    fn take_active_copilot_suggestion(&mut self, cx: &mut ViewContext<Self>) -> Option<Inlay> {
3850        let suggestion = self.copilot_state.suggestion.take()?;
3851        self.display_map.update(cx, |map, cx| {
3852            map.splice_inlays(vec![suggestion.id], Default::default(), cx);
3853        });
3854        let buffer = self.buffer.read(cx).read(cx);
3855
3856        if suggestion.position.is_valid(&buffer) {
3857            Some(suggestion)
3858        } else {
3859            None
3860        }
3861    }
3862
3863    fn update_visible_copilot_suggestion(&mut self, cx: &mut ViewContext<Self>) {
3864        let snapshot = self.buffer.read(cx).snapshot(cx);
3865        let selection = self.selections.newest_anchor();
3866        let cursor = selection.head();
3867
3868        if self.context_menu.read().is_some()
3869            || !self.completion_tasks.is_empty()
3870            || selection.start != selection.end
3871        {
3872            self.discard_copilot_suggestion(cx);
3873        } else if let Some(text) = self
3874            .copilot_state
3875            .text_for_active_completion(cursor, &snapshot)
3876        {
3877            let text = Rope::from(text);
3878            let mut to_remove = Vec::new();
3879            if let Some(suggestion) = self.copilot_state.suggestion.take() {
3880                to_remove.push(suggestion.id);
3881            }
3882
3883            let suggestion_inlay =
3884                Inlay::suggestion(post_inc(&mut self.next_inlay_id), cursor, text);
3885            self.copilot_state.suggestion = Some(suggestion_inlay.clone());
3886            self.display_map.update(cx, move |map, cx| {
3887                map.splice_inlays(to_remove, vec![suggestion_inlay], cx)
3888            });
3889            cx.notify();
3890        } else {
3891            self.discard_copilot_suggestion(cx);
3892        }
3893    }
3894
3895    fn clear_copilot_suggestions(&mut self, cx: &mut ViewContext<Self>) {
3896        self.copilot_state = Default::default();
3897        self.discard_copilot_suggestion(cx);
3898    }
3899
3900    pub fn render_code_actions_indicator(
3901        &self,
3902        _style: &EditorStyle,
3903        is_active: bool,
3904        cx: &mut ViewContext<Self>,
3905    ) -> Option<IconButton> {
3906        if self.available_code_actions.is_some() {
3907            Some(
3908                IconButton::new("code_actions_indicator", ui::IconName::Bolt)
3909                    .icon_size(IconSize::Small)
3910                    .icon_color(Color::Muted)
3911                    .selected(is_active)
3912                    .on_click(cx.listener(|editor, _e, cx| {
3913                        editor.toggle_code_actions(
3914                            &ToggleCodeActions {
3915                                deployed_from_indicator: true,
3916                            },
3917                            cx,
3918                        );
3919                    })),
3920            )
3921        } else {
3922            None
3923        }
3924    }
3925
3926    pub fn render_fold_indicators(
3927        &self,
3928        fold_data: Vec<Option<(FoldStatus, u32, bool)>>,
3929        _style: &EditorStyle,
3930        gutter_hovered: bool,
3931        _line_height: Pixels,
3932        _gutter_margin: Pixels,
3933        editor_view: View<Editor>,
3934    ) -> Vec<Option<IconButton>> {
3935        fold_data
3936            .iter()
3937            .enumerate()
3938            .map(|(ix, fold_data)| {
3939                fold_data
3940                    .map(|(fold_status, buffer_row, active)| {
3941                        (active || gutter_hovered || fold_status == FoldStatus::Folded).then(|| {
3942                            IconButton::new(ix as usize, ui::IconName::ChevronDown)
3943                                .on_click({
3944                                    let view = editor_view.clone();
3945                                    move |_e, cx| {
3946                                        view.update(cx, |editor, cx| match fold_status {
3947                                            FoldStatus::Folded => {
3948                                                editor.unfold_at(&UnfoldAt { buffer_row }, cx);
3949                                            }
3950                                            FoldStatus::Foldable => {
3951                                                editor.fold_at(&FoldAt { buffer_row }, cx);
3952                                            }
3953                                        })
3954                                    }
3955                                })
3956                                .icon_color(ui::Color::Muted)
3957                                .icon_size(ui::IconSize::Small)
3958                                .selected(fold_status == FoldStatus::Folded)
3959                                .selected_icon(ui::IconName::ChevronRight)
3960                                .size(ui::ButtonSize::None)
3961                        })
3962                    })
3963                    .flatten()
3964            })
3965            .collect()
3966    }
3967
3968    pub fn context_menu_visible(&self) -> bool {
3969        self.context_menu
3970            .read()
3971            .as_ref()
3972            .map_or(false, |menu| menu.visible())
3973    }
3974
3975    pub fn render_context_menu(
3976        &self,
3977        cursor_position: DisplayPoint,
3978        style: &EditorStyle,
3979        max_height: Pixels,
3980        cx: &mut ViewContext<Editor>,
3981    ) -> Option<(DisplayPoint, AnyElement)> {
3982        self.context_menu.read().as_ref().map(|menu| {
3983            menu.render(
3984                cursor_position,
3985                style,
3986                max_height,
3987                self.workspace.as_ref().map(|(w, _)| w.clone()),
3988                cx,
3989            )
3990        })
3991    }
3992
3993    fn hide_context_menu(&mut self, cx: &mut ViewContext<Self>) -> Option<ContextMenu> {
3994        cx.notify();
3995        self.completion_tasks.clear();
3996        let context_menu = self.context_menu.write().take();
3997        if context_menu.is_some() {
3998            self.update_visible_copilot_suggestion(cx);
3999        }
4000        context_menu
4001    }
4002
4003    pub fn insert_snippet(
4004        &mut self,
4005        insertion_ranges: &[Range<usize>],
4006        snippet: Snippet,
4007        cx: &mut ViewContext<Self>,
4008    ) -> Result<()> {
4009        let tabstops = self.buffer.update(cx, |buffer, cx| {
4010            let snippet_text: Arc<str> = snippet.text.clone().into();
4011            buffer.edit(
4012                insertion_ranges
4013                    .iter()
4014                    .cloned()
4015                    .map(|range| (range, snippet_text.clone())),
4016                Some(AutoindentMode::EachLine),
4017                cx,
4018            );
4019
4020            let snapshot = &*buffer.read(cx);
4021            let snippet = &snippet;
4022            snippet
4023                .tabstops
4024                .iter()
4025                .map(|tabstop| {
4026                    let mut tabstop_ranges = tabstop
4027                        .iter()
4028                        .flat_map(|tabstop_range| {
4029                            let mut delta = 0_isize;
4030                            insertion_ranges.iter().map(move |insertion_range| {
4031                                let insertion_start = insertion_range.start as isize + delta;
4032                                delta +=
4033                                    snippet.text.len() as isize - insertion_range.len() as isize;
4034
4035                                let start = snapshot.anchor_before(
4036                                    (insertion_start + tabstop_range.start) as usize,
4037                                );
4038                                let end = snapshot
4039                                    .anchor_after((insertion_start + tabstop_range.end) as usize);
4040                                start..end
4041                            })
4042                        })
4043                        .collect::<Vec<_>>();
4044                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
4045                    tabstop_ranges
4046                })
4047                .collect::<Vec<_>>()
4048        });
4049
4050        if let Some(tabstop) = tabstops.first() {
4051            self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4052                s.select_ranges(tabstop.iter().cloned());
4053            });
4054            self.snippet_stack.push(SnippetState {
4055                active_index: 0,
4056                ranges: tabstops,
4057            });
4058        }
4059
4060        Ok(())
4061    }
4062
4063    pub fn move_to_next_snippet_tabstop(&mut self, cx: &mut ViewContext<Self>) -> bool {
4064        self.move_to_snippet_tabstop(Bias::Right, cx)
4065    }
4066
4067    pub fn move_to_prev_snippet_tabstop(&mut self, cx: &mut ViewContext<Self>) -> bool {
4068        self.move_to_snippet_tabstop(Bias::Left, cx)
4069    }
4070
4071    pub fn move_to_snippet_tabstop(&mut self, bias: Bias, cx: &mut ViewContext<Self>) -> bool {
4072        if let Some(mut snippet) = self.snippet_stack.pop() {
4073            match bias {
4074                Bias::Left => {
4075                    if snippet.active_index > 0 {
4076                        snippet.active_index -= 1;
4077                    } else {
4078                        self.snippet_stack.push(snippet);
4079                        return false;
4080                    }
4081                }
4082                Bias::Right => {
4083                    if snippet.active_index + 1 < snippet.ranges.len() {
4084                        snippet.active_index += 1;
4085                    } else {
4086                        self.snippet_stack.push(snippet);
4087                        return false;
4088                    }
4089                }
4090            }
4091            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
4092                self.change_selections(Some(Autoscroll::fit()), cx, |s| {
4093                    s.select_anchor_ranges(current_ranges.iter().cloned())
4094                });
4095                // If snippet state is not at the last tabstop, push it back on the stack
4096                if snippet.active_index + 1 < snippet.ranges.len() {
4097                    self.snippet_stack.push(snippet);
4098                }
4099                return true;
4100            }
4101        }
4102
4103        false
4104    }
4105
4106    pub fn clear(&mut self, cx: &mut ViewContext<Self>) {
4107        self.transact(cx, |this, cx| {
4108            this.select_all(&SelectAll, cx);
4109            this.insert("", cx);
4110        });
4111    }
4112
4113    pub fn backspace(&mut self, _: &Backspace, cx: &mut ViewContext<Self>) {
4114        self.transact(cx, |this, cx| {
4115            this.select_autoclose_pair(cx);
4116            let mut selections = this.selections.all::<Point>(cx);
4117            if !this.selections.line_mode {
4118                let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
4119                for selection in &mut selections {
4120                    if selection.is_empty() {
4121                        let old_head = selection.head();
4122                        let mut new_head =
4123                            movement::left(&display_map, old_head.to_display_point(&display_map))
4124                                .to_point(&display_map);
4125                        if let Some((buffer, line_buffer_range)) = display_map
4126                            .buffer_snapshot
4127                            .buffer_line_for_row(old_head.row)
4128                        {
4129                            let indent_size =
4130                                buffer.indent_size_for_line(line_buffer_range.start.row);
4131                            let indent_len = match indent_size.kind {
4132                                IndentKind::Space => {
4133                                    buffer.settings_at(line_buffer_range.start, cx).tab_size
4134                                }
4135                                IndentKind::Tab => NonZeroU32::new(1).unwrap(),
4136                            };
4137                            if old_head.column <= indent_size.len && old_head.column > 0 {
4138                                let indent_len = indent_len.get();
4139                                new_head = cmp::min(
4140                                    new_head,
4141                                    Point::new(
4142                                        old_head.row,
4143                                        ((old_head.column - 1) / indent_len) * indent_len,
4144                                    ),
4145                                );
4146                            }
4147                        }
4148
4149                        selection.set_head(new_head, SelectionGoal::None);
4150                    }
4151                }
4152            }
4153
4154            this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections));
4155            this.insert("", cx);
4156            this.refresh_copilot_suggestions(true, cx);
4157        });
4158    }
4159
4160    pub fn delete(&mut self, _: &Delete, cx: &mut ViewContext<Self>) {
4161        self.transact(cx, |this, cx| {
4162            this.change_selections(Some(Autoscroll::fit()), cx, |s| {
4163                let line_mode = s.line_mode;
4164                s.move_with(|map, selection| {
4165                    if selection.is_empty() && !line_mode {
4166                        let cursor = movement::right(map, selection.head());
4167                        selection.end = cursor;
4168                        selection.reversed = true;
4169                        selection.goal = SelectionGoal::None;
4170                    }
4171                })
4172            });
4173            this.insert("", cx);
4174            this.refresh_copilot_suggestions(true, cx);
4175        });
4176    }
4177
4178    pub fn tab_prev(&mut self, _: &TabPrev, cx: &mut ViewContext<Self>) {
4179        if self.move_to_prev_snippet_tabstop(cx) {
4180            return;
4181        }
4182
4183        self.outdent(&Outdent, cx);
4184    }
4185
4186    pub fn tab(&mut self, _: &Tab, cx: &mut ViewContext<Self>) {
4187        if self.move_to_next_snippet_tabstop(cx) || self.read_only(cx) {
4188            return;
4189        }
4190
4191        let mut selections = self.selections.all_adjusted(cx);
4192        let buffer = self.buffer.read(cx);
4193        let snapshot = buffer.snapshot(cx);
4194        let rows_iter = selections.iter().map(|s| s.head().row);
4195        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
4196
4197        let mut edits = Vec::new();
4198        let mut prev_edited_row = 0;
4199        let mut row_delta = 0;
4200        for selection in &mut selections {
4201            if selection.start.row != prev_edited_row {
4202                row_delta = 0;
4203            }
4204            prev_edited_row = selection.end.row;
4205
4206            // If the selection is non-empty, then increase the indentation of the selected lines.
4207            if !selection.is_empty() {
4208                row_delta =
4209                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
4210                continue;
4211            }
4212
4213            // If the selection is empty and the cursor is in the leading whitespace before the
4214            // suggested indentation, then auto-indent the line.
4215            let cursor = selection.head();
4216            let current_indent = snapshot.indent_size_for_line(cursor.row);
4217            if let Some(suggested_indent) = suggested_indents.get(&cursor.row).copied() {
4218                if cursor.column < suggested_indent.len
4219                    && cursor.column <= current_indent.len
4220                    && current_indent.len <= suggested_indent.len
4221                {
4222                    selection.start = Point::new(cursor.row, suggested_indent.len);
4223                    selection.end = selection.start;
4224                    if row_delta == 0 {
4225                        edits.extend(Buffer::edit_for_indent_size_adjustment(
4226                            cursor.row,
4227                            current_indent,
4228                            suggested_indent,
4229                        ));
4230                        row_delta = suggested_indent.len - current_indent.len;
4231                    }
4232                    continue;
4233                }
4234            }
4235
4236            // Accept copilot suggestion if there is only one selection and the cursor is not
4237            // in the leading whitespace.
4238            if self.selections.count() == 1
4239                && cursor.column >= current_indent.len
4240                && self.has_active_copilot_suggestion(cx)
4241            {
4242                self.accept_copilot_suggestion(cx);
4243                return;
4244            }
4245
4246            // Otherwise, insert a hard or soft tab.
4247            let settings = buffer.settings_at(cursor, cx);
4248            let tab_size = if settings.hard_tabs {
4249                IndentSize::tab()
4250            } else {
4251                let tab_size = settings.tab_size.get();
4252                let char_column = snapshot
4253                    .text_for_range(Point::new(cursor.row, 0)..cursor)
4254                    .flat_map(str::chars)
4255                    .count()
4256                    + row_delta as usize;
4257                let chars_to_next_tab_stop = tab_size - (char_column as u32 % tab_size);
4258                IndentSize::spaces(chars_to_next_tab_stop)
4259            };
4260            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
4261            selection.end = selection.start;
4262            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
4263            row_delta += tab_size.len;
4264        }
4265
4266        self.transact(cx, |this, cx| {
4267            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
4268            this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections));
4269            this.refresh_copilot_suggestions(true, cx);
4270        });
4271    }
4272
4273    pub fn indent(&mut self, _: &Indent, cx: &mut ViewContext<Self>) {
4274        let mut selections = self.selections.all::<Point>(cx);
4275        let mut prev_edited_row = 0;
4276        let mut row_delta = 0;
4277        let mut edits = Vec::new();
4278        let buffer = self.buffer.read(cx);
4279        let snapshot = buffer.snapshot(cx);
4280        for selection in &mut selections {
4281            if selection.start.row != prev_edited_row {
4282                row_delta = 0;
4283            }
4284            prev_edited_row = selection.end.row;
4285
4286            row_delta =
4287                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
4288        }
4289
4290        self.transact(cx, |this, cx| {
4291            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
4292            this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections));
4293        });
4294    }
4295
4296    fn indent_selection(
4297        buffer: &MultiBuffer,
4298        snapshot: &MultiBufferSnapshot,
4299        selection: &mut Selection<Point>,
4300        edits: &mut Vec<(Range<Point>, String)>,
4301        delta_for_start_row: u32,
4302        cx: &AppContext,
4303    ) -> u32 {
4304        let settings = buffer.settings_at(selection.start, cx);
4305        let tab_size = settings.tab_size.get();
4306        let indent_kind = if settings.hard_tabs {
4307            IndentKind::Tab
4308        } else {
4309            IndentKind::Space
4310        };
4311        let mut start_row = selection.start.row;
4312        let mut end_row = selection.end.row + 1;
4313
4314        // If a selection ends at the beginning of a line, don't indent
4315        // that last line.
4316        if selection.end.column == 0 {
4317            end_row -= 1;
4318        }
4319
4320        // Avoid re-indenting a row that has already been indented by a
4321        // previous selection, but still update this selection's column
4322        // to reflect that indentation.
4323        if delta_for_start_row > 0 {
4324            start_row += 1;
4325            selection.start.column += delta_for_start_row;
4326            if selection.end.row == selection.start.row {
4327                selection.end.column += delta_for_start_row;
4328            }
4329        }
4330
4331        let mut delta_for_end_row = 0;
4332        for row in start_row..end_row {
4333            let current_indent = snapshot.indent_size_for_line(row);
4334            let indent_delta = match (current_indent.kind, indent_kind) {
4335                (IndentKind::Space, IndentKind::Space) => {
4336                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
4337                    IndentSize::spaces(columns_to_next_tab_stop)
4338                }
4339                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
4340                (_, IndentKind::Tab) => IndentSize::tab(),
4341            };
4342
4343            let row_start = Point::new(row, 0);
4344            edits.push((
4345                row_start..row_start,
4346                indent_delta.chars().collect::<String>(),
4347            ));
4348
4349            // Update this selection's endpoints to reflect the indentation.
4350            if row == selection.start.row {
4351                selection.start.column += indent_delta.len;
4352            }
4353            if row == selection.end.row {
4354                selection.end.column += indent_delta.len;
4355                delta_for_end_row = indent_delta.len;
4356            }
4357        }
4358
4359        if selection.start.row == selection.end.row {
4360            delta_for_start_row + delta_for_end_row
4361        } else {
4362            delta_for_end_row
4363        }
4364    }
4365
4366    pub fn outdent(&mut self, _: &Outdent, cx: &mut ViewContext<Self>) {
4367        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
4368        let selections = self.selections.all::<Point>(cx);
4369        let mut deletion_ranges = Vec::new();
4370        let mut last_outdent = None;
4371        {
4372            let buffer = self.buffer.read(cx);
4373            let snapshot = buffer.snapshot(cx);
4374            for selection in &selections {
4375                let settings = buffer.settings_at(selection.start, cx);
4376                let tab_size = settings.tab_size.get();
4377                let mut rows = selection.spanned_rows(false, &display_map);
4378
4379                // Avoid re-outdenting a row that has already been outdented by a
4380                // previous selection.
4381                if let Some(last_row) = last_outdent {
4382                    if last_row == rows.start {
4383                        rows.start += 1;
4384                    }
4385                }
4386
4387                for row in rows {
4388                    let indent_size = snapshot.indent_size_for_line(row);
4389                    if indent_size.len > 0 {
4390                        let deletion_len = match indent_size.kind {
4391                            IndentKind::Space => {
4392                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
4393                                if columns_to_prev_tab_stop == 0 {
4394                                    tab_size
4395                                } else {
4396                                    columns_to_prev_tab_stop
4397                                }
4398                            }
4399                            IndentKind::Tab => 1,
4400                        };
4401                        deletion_ranges.push(Point::new(row, 0)..Point::new(row, deletion_len));
4402                        last_outdent = Some(row);
4403                    }
4404                }
4405            }
4406        }
4407
4408        self.transact(cx, |this, cx| {
4409            this.buffer.update(cx, |buffer, cx| {
4410                let empty_str: Arc<str> = "".into();
4411                buffer.edit(
4412                    deletion_ranges
4413                        .into_iter()
4414                        .map(|range| (range, empty_str.clone())),
4415                    None,
4416                    cx,
4417                );
4418            });
4419            let selections = this.selections.all::<usize>(cx);
4420            this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections));
4421        });
4422    }
4423
4424    pub fn delete_line(&mut self, _: &DeleteLine, cx: &mut ViewContext<Self>) {
4425        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
4426        let selections = self.selections.all::<Point>(cx);
4427
4428        let mut new_cursors = Vec::new();
4429        let mut edit_ranges = Vec::new();
4430        let mut selections = selections.iter().peekable();
4431        while let Some(selection) = selections.next() {
4432            let mut rows = selection.spanned_rows(false, &display_map);
4433            let goal_display_column = selection.head().to_display_point(&display_map).column();
4434
4435            // Accumulate contiguous regions of rows that we want to delete.
4436            while let Some(next_selection) = selections.peek() {
4437                let next_rows = next_selection.spanned_rows(false, &display_map);
4438                if next_rows.start <= rows.end {
4439                    rows.end = next_rows.end;
4440                    selections.next().unwrap();
4441                } else {
4442                    break;
4443                }
4444            }
4445
4446            let buffer = &display_map.buffer_snapshot;
4447            let mut edit_start = Point::new(rows.start, 0).to_offset(buffer);
4448            let edit_end;
4449            let cursor_buffer_row;
4450            if buffer.max_point().row >= rows.end {
4451                // If there's a line after the range, delete the \n from the end of the row range
4452                // and position the cursor on the next line.
4453                edit_end = Point::new(rows.end, 0).to_offset(buffer);
4454                cursor_buffer_row = rows.end;
4455            } else {
4456                // If there isn't a line after the range, delete the \n from the line before the
4457                // start of the row range and position the cursor there.
4458                edit_start = edit_start.saturating_sub(1);
4459                edit_end = buffer.len();
4460                cursor_buffer_row = rows.start.saturating_sub(1);
4461            }
4462
4463            let mut cursor = Point::new(cursor_buffer_row, 0).to_display_point(&display_map);
4464            *cursor.column_mut() =
4465                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
4466
4467            new_cursors.push((
4468                selection.id,
4469                buffer.anchor_after(cursor.to_point(&display_map)),
4470            ));
4471            edit_ranges.push(edit_start..edit_end);
4472        }
4473
4474        self.transact(cx, |this, cx| {
4475            let buffer = this.buffer.update(cx, |buffer, cx| {
4476                let empty_str: Arc<str> = "".into();
4477                buffer.edit(
4478                    edit_ranges
4479                        .into_iter()
4480                        .map(|range| (range, empty_str.clone())),
4481                    None,
4482                    cx,
4483                );
4484                buffer.snapshot(cx)
4485            });
4486            let new_selections = new_cursors
4487                .into_iter()
4488                .map(|(id, cursor)| {
4489                    let cursor = cursor.to_point(&buffer);
4490                    Selection {
4491                        id,
4492                        start: cursor,
4493                        end: cursor,
4494                        reversed: false,
4495                        goal: SelectionGoal::None,
4496                    }
4497                })
4498                .collect();
4499
4500            this.change_selections(Some(Autoscroll::fit()), cx, |s| {
4501                s.select(new_selections);
4502            });
4503        });
4504    }
4505
4506    pub fn join_lines(&mut self, _: &JoinLines, cx: &mut ViewContext<Self>) {
4507        let mut row_ranges = Vec::<Range<u32>>::new();
4508        for selection in self.selections.all::<Point>(cx) {
4509            let start = selection.start.row;
4510            let end = if selection.start.row == selection.end.row {
4511                selection.start.row + 1
4512            } else {
4513                selection.end.row
4514            };
4515
4516            if let Some(last_row_range) = row_ranges.last_mut() {
4517                if start <= last_row_range.end {
4518                    last_row_range.end = end;
4519                    continue;
4520                }
4521            }
4522            row_ranges.push(start..end);
4523        }
4524
4525        let snapshot = self.buffer.read(cx).snapshot(cx);
4526        let mut cursor_positions = Vec::new();
4527        for row_range in &row_ranges {
4528            let anchor = snapshot.anchor_before(Point::new(
4529                row_range.end - 1,
4530                snapshot.line_len(row_range.end - 1),
4531            ));
4532            cursor_positions.push(anchor.clone()..anchor);
4533        }
4534
4535        self.transact(cx, |this, cx| {
4536            for row_range in row_ranges.into_iter().rev() {
4537                for row in row_range.rev() {
4538                    let end_of_line = Point::new(row, snapshot.line_len(row));
4539                    let indent = snapshot.indent_size_for_line(row + 1);
4540                    let start_of_next_line = Point::new(row + 1, indent.len);
4541
4542                    let replace = if snapshot.line_len(row + 1) > indent.len {
4543                        " "
4544                    } else {
4545                        ""
4546                    };
4547
4548                    this.buffer.update(cx, |buffer, cx| {
4549                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
4550                    });
4551                }
4552            }
4553
4554            this.change_selections(Some(Autoscroll::fit()), cx, |s| {
4555                s.select_anchor_ranges(cursor_positions)
4556            });
4557        });
4558    }
4559
4560    pub fn sort_lines_case_sensitive(
4561        &mut self,
4562        _: &SortLinesCaseSensitive,
4563        cx: &mut ViewContext<Self>,
4564    ) {
4565        self.manipulate_lines(cx, |lines| lines.sort())
4566    }
4567
4568    pub fn sort_lines_case_insensitive(
4569        &mut self,
4570        _: &SortLinesCaseInsensitive,
4571        cx: &mut ViewContext<Self>,
4572    ) {
4573        self.manipulate_lines(cx, |lines| lines.sort_by_key(|line| line.to_lowercase()))
4574    }
4575
4576    pub fn reverse_lines(&mut self, _: &ReverseLines, cx: &mut ViewContext<Self>) {
4577        self.manipulate_lines(cx, |lines| lines.reverse())
4578    }
4579
4580    pub fn shuffle_lines(&mut self, _: &ShuffleLines, cx: &mut ViewContext<Self>) {
4581        self.manipulate_lines(cx, |lines| lines.shuffle(&mut thread_rng()))
4582    }
4583
4584    fn manipulate_lines<Fn>(&mut self, cx: &mut ViewContext<Self>, mut callback: Fn)
4585    where
4586        Fn: FnMut(&mut [&str]),
4587    {
4588        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
4589        let buffer = self.buffer.read(cx).snapshot(cx);
4590
4591        let mut edits = Vec::new();
4592
4593        let selections = self.selections.all::<Point>(cx);
4594        let mut selections = selections.iter().peekable();
4595        let mut contiguous_row_selections = Vec::new();
4596        let mut new_selections = Vec::new();
4597
4598        while let Some(selection) = selections.next() {
4599            let (start_row, end_row) = consume_contiguous_rows(
4600                &mut contiguous_row_selections,
4601                selection,
4602                &display_map,
4603                &mut selections,
4604            );
4605
4606            let start_point = Point::new(start_row, 0);
4607            let end_point = Point::new(end_row - 1, buffer.line_len(end_row - 1));
4608            let text = buffer
4609                .text_for_range(start_point..end_point)
4610                .collect::<String>();
4611            let mut lines = text.split("\n").collect_vec();
4612
4613            let lines_len = lines.len();
4614            callback(&mut lines);
4615
4616            // This is a current limitation with selections.
4617            // If we wanted to support removing or adding lines, we'd need to fix the logic associated with selections.
4618            debug_assert!(
4619                lines.len() == lines_len,
4620                "callback should not change the number of lines"
4621            );
4622
4623            edits.push((start_point..end_point, lines.join("\n")));
4624            let start_anchor = buffer.anchor_after(start_point);
4625            let end_anchor = buffer.anchor_before(end_point);
4626
4627            // Make selection and push
4628            new_selections.push(Selection {
4629                id: selection.id,
4630                start: start_anchor.to_offset(&buffer),
4631                end: end_anchor.to_offset(&buffer),
4632                goal: SelectionGoal::None,
4633                reversed: selection.reversed,
4634            });
4635        }
4636
4637        self.transact(cx, |this, cx| {
4638            this.buffer.update(cx, |buffer, cx| {
4639                buffer.edit(edits, None, cx);
4640            });
4641
4642            this.change_selections(Some(Autoscroll::fit()), cx, |s| {
4643                s.select(new_selections);
4644            });
4645
4646            this.request_autoscroll(Autoscroll::fit(), cx);
4647        });
4648    }
4649
4650    pub fn convert_to_upper_case(&mut self, _: &ConvertToUpperCase, cx: &mut ViewContext<Self>) {
4651        self.manipulate_text(cx, |text| text.to_uppercase())
4652    }
4653
4654    pub fn convert_to_lower_case(&mut self, _: &ConvertToLowerCase, cx: &mut ViewContext<Self>) {
4655        self.manipulate_text(cx, |text| text.to_lowercase())
4656    }
4657
4658    pub fn convert_to_title_case(&mut self, _: &ConvertToTitleCase, cx: &mut ViewContext<Self>) {
4659        self.manipulate_text(cx, |text| {
4660            // Hack to get around the fact that to_case crate doesn't support '\n' as a word boundary
4661            // https://github.com/rutrum/convert-case/issues/16
4662            text.split("\n")
4663                .map(|line| line.to_case(Case::Title))
4664                .join("\n")
4665        })
4666    }
4667
4668    pub fn convert_to_snake_case(&mut self, _: &ConvertToSnakeCase, cx: &mut ViewContext<Self>) {
4669        self.manipulate_text(cx, |text| text.to_case(Case::Snake))
4670    }
4671
4672    pub fn convert_to_kebab_case(&mut self, _: &ConvertToKebabCase, cx: &mut ViewContext<Self>) {
4673        self.manipulate_text(cx, |text| text.to_case(Case::Kebab))
4674    }
4675
4676    pub fn convert_to_upper_camel_case(
4677        &mut self,
4678        _: &ConvertToUpperCamelCase,
4679        cx: &mut ViewContext<Self>,
4680    ) {
4681        self.manipulate_text(cx, |text| {
4682            // Hack to get around the fact that to_case crate doesn't support '\n' as a word boundary
4683            // https://github.com/rutrum/convert-case/issues/16
4684            text.split("\n")
4685                .map(|line| line.to_case(Case::UpperCamel))
4686                .join("\n")
4687        })
4688    }
4689
4690    pub fn convert_to_lower_camel_case(
4691        &mut self,
4692        _: &ConvertToLowerCamelCase,
4693        cx: &mut ViewContext<Self>,
4694    ) {
4695        self.manipulate_text(cx, |text| text.to_case(Case::Camel))
4696    }
4697
4698    fn manipulate_text<Fn>(&mut self, cx: &mut ViewContext<Self>, mut callback: Fn)
4699    where
4700        Fn: FnMut(&str) -> String,
4701    {
4702        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
4703        let buffer = self.buffer.read(cx).snapshot(cx);
4704
4705        let mut new_selections = Vec::new();
4706        let mut edits = Vec::new();
4707        let mut selection_adjustment = 0i32;
4708
4709        for selection in self.selections.all::<usize>(cx) {
4710            let selection_is_empty = selection.is_empty();
4711
4712            let (start, end) = if selection_is_empty {
4713                let word_range = movement::surrounding_word(
4714                    &display_map,
4715                    selection.start.to_display_point(&display_map),
4716                );
4717                let start = word_range.start.to_offset(&display_map, Bias::Left);
4718                let end = word_range.end.to_offset(&display_map, Bias::Left);
4719                (start, end)
4720            } else {
4721                (selection.start, selection.end)
4722            };
4723
4724            let text = buffer.text_for_range(start..end).collect::<String>();
4725            let old_length = text.len() as i32;
4726            let text = callback(&text);
4727
4728            new_selections.push(Selection {
4729                start: (start as i32 - selection_adjustment) as usize,
4730                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
4731                goal: SelectionGoal::None,
4732                ..selection
4733            });
4734
4735            selection_adjustment += old_length - text.len() as i32;
4736
4737            edits.push((start..end, text));
4738        }
4739
4740        self.transact(cx, |this, cx| {
4741            this.buffer.update(cx, |buffer, cx| {
4742                buffer.edit(edits, None, cx);
4743            });
4744
4745            this.change_selections(Some(Autoscroll::fit()), cx, |s| {
4746                s.select(new_selections);
4747            });
4748
4749            this.request_autoscroll(Autoscroll::fit(), cx);
4750        });
4751    }
4752
4753    pub fn duplicate_line(&mut self, _: &DuplicateLine, cx: &mut ViewContext<Self>) {
4754        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
4755        let buffer = &display_map.buffer_snapshot;
4756        let selections = self.selections.all::<Point>(cx);
4757
4758        let mut edits = Vec::new();
4759        let mut selections_iter = selections.iter().peekable();
4760        while let Some(selection) = selections_iter.next() {
4761            // Avoid duplicating the same lines twice.
4762            let mut rows = selection.spanned_rows(false, &display_map);
4763
4764            while let Some(next_selection) = selections_iter.peek() {
4765                let next_rows = next_selection.spanned_rows(false, &display_map);
4766                if next_rows.start < rows.end {
4767                    rows.end = next_rows.end;
4768                    selections_iter.next().unwrap();
4769                } else {
4770                    break;
4771                }
4772            }
4773
4774            // Copy the text from the selected row region and splice it at the start of the region.
4775            let start = Point::new(rows.start, 0);
4776            let end = Point::new(rows.end - 1, buffer.line_len(rows.end - 1));
4777            let text = buffer
4778                .text_for_range(start..end)
4779                .chain(Some("\n"))
4780                .collect::<String>();
4781            edits.push((start..start, text));
4782        }
4783
4784        self.transact(cx, |this, cx| {
4785            this.buffer.update(cx, |buffer, cx| {
4786                buffer.edit(edits, None, cx);
4787            });
4788
4789            this.request_autoscroll(Autoscroll::fit(), cx);
4790        });
4791    }
4792
4793    pub fn move_line_up(&mut self, _: &MoveLineUp, cx: &mut ViewContext<Self>) {
4794        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
4795        let buffer = self.buffer.read(cx).snapshot(cx);
4796
4797        let mut edits = Vec::new();
4798        let mut unfold_ranges = Vec::new();
4799        let mut refold_ranges = Vec::new();
4800
4801        let selections = self.selections.all::<Point>(cx);
4802        let mut selections = selections.iter().peekable();
4803        let mut contiguous_row_selections = Vec::new();
4804        let mut new_selections = Vec::new();
4805
4806        while let Some(selection) = selections.next() {
4807            // Find all the selections that span a contiguous row range
4808            let (start_row, end_row) = consume_contiguous_rows(
4809                &mut contiguous_row_selections,
4810                selection,
4811                &display_map,
4812                &mut selections,
4813            );
4814
4815            // Move the text spanned by the row range to be before the line preceding the row range
4816            if start_row > 0 {
4817                let range_to_move = Point::new(start_row - 1, buffer.line_len(start_row - 1))
4818                    ..Point::new(end_row - 1, buffer.line_len(end_row - 1));
4819                let insertion_point = display_map
4820                    .prev_line_boundary(Point::new(start_row - 1, 0))
4821                    .0;
4822
4823                // Don't move lines across excerpts
4824                if buffer
4825                    .excerpt_boundaries_in_range((
4826                        Bound::Excluded(insertion_point),
4827                        Bound::Included(range_to_move.end),
4828                    ))
4829                    .next()
4830                    .is_none()
4831                {
4832                    let text = buffer
4833                        .text_for_range(range_to_move.clone())
4834                        .flat_map(|s| s.chars())
4835                        .skip(1)
4836                        .chain(['\n'])
4837                        .collect::<String>();
4838
4839                    edits.push((
4840                        buffer.anchor_after(range_to_move.start)
4841                            ..buffer.anchor_before(range_to_move.end),
4842                        String::new(),
4843                    ));
4844                    let insertion_anchor = buffer.anchor_after(insertion_point);
4845                    edits.push((insertion_anchor..insertion_anchor, text));
4846
4847                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
4848
4849                    // Move selections up
4850                    new_selections.extend(contiguous_row_selections.drain(..).map(
4851                        |mut selection| {
4852                            selection.start.row -= row_delta;
4853                            selection.end.row -= row_delta;
4854                            selection
4855                        },
4856                    ));
4857
4858                    // Move folds up
4859                    unfold_ranges.push(range_to_move.clone());
4860                    for fold in display_map.folds_in_range(
4861                        buffer.anchor_before(range_to_move.start)
4862                            ..buffer.anchor_after(range_to_move.end),
4863                    ) {
4864                        let mut start = fold.range.start.to_point(&buffer);
4865                        let mut end = fold.range.end.to_point(&buffer);
4866                        start.row -= row_delta;
4867                        end.row -= row_delta;
4868                        refold_ranges.push(start..end);
4869                    }
4870                }
4871            }
4872
4873            // If we didn't move line(s), preserve the existing selections
4874            new_selections.append(&mut contiguous_row_selections);
4875        }
4876
4877        self.transact(cx, |this, cx| {
4878            this.unfold_ranges(unfold_ranges, true, true, cx);
4879            this.buffer.update(cx, |buffer, cx| {
4880                for (range, text) in edits {
4881                    buffer.edit([(range, text)], None, cx);
4882                }
4883            });
4884            this.fold_ranges(refold_ranges, true, cx);
4885            this.change_selections(Some(Autoscroll::fit()), cx, |s| {
4886                s.select(new_selections);
4887            })
4888        });
4889    }
4890
4891    pub fn move_line_down(&mut self, _: &MoveLineDown, cx: &mut ViewContext<Self>) {
4892        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
4893        let buffer = self.buffer.read(cx).snapshot(cx);
4894
4895        let mut edits = Vec::new();
4896        let mut unfold_ranges = Vec::new();
4897        let mut refold_ranges = Vec::new();
4898
4899        let selections = self.selections.all::<Point>(cx);
4900        let mut selections = selections.iter().peekable();
4901        let mut contiguous_row_selections = Vec::new();
4902        let mut new_selections = Vec::new();
4903
4904        while let Some(selection) = selections.next() {
4905            // Find all the selections that span a contiguous row range
4906            let (start_row, end_row) = consume_contiguous_rows(
4907                &mut contiguous_row_selections,
4908                selection,
4909                &display_map,
4910                &mut selections,
4911            );
4912
4913            // Move the text spanned by the row range to be after the last line of the row range
4914            if end_row <= buffer.max_point().row {
4915                let range_to_move = Point::new(start_row, 0)..Point::new(end_row, 0);
4916                let insertion_point = display_map.next_line_boundary(Point::new(end_row, 0)).0;
4917
4918                // Don't move lines across excerpt boundaries
4919                if buffer
4920                    .excerpt_boundaries_in_range((
4921                        Bound::Excluded(range_to_move.start),
4922                        Bound::Included(insertion_point),
4923                    ))
4924                    .next()
4925                    .is_none()
4926                {
4927                    let mut text = String::from("\n");
4928                    text.extend(buffer.text_for_range(range_to_move.clone()));
4929                    text.pop(); // Drop trailing newline
4930                    edits.push((
4931                        buffer.anchor_after(range_to_move.start)
4932                            ..buffer.anchor_before(range_to_move.end),
4933                        String::new(),
4934                    ));
4935                    let insertion_anchor = buffer.anchor_after(insertion_point);
4936                    edits.push((insertion_anchor..insertion_anchor, text));
4937
4938                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
4939
4940                    // Move selections down
4941                    new_selections.extend(contiguous_row_selections.drain(..).map(
4942                        |mut selection| {
4943                            selection.start.row += row_delta;
4944                            selection.end.row += row_delta;
4945                            selection
4946                        },
4947                    ));
4948
4949                    // Move folds down
4950                    unfold_ranges.push(range_to_move.clone());
4951                    for fold in display_map.folds_in_range(
4952                        buffer.anchor_before(range_to_move.start)
4953                            ..buffer.anchor_after(range_to_move.end),
4954                    ) {
4955                        let mut start = fold.range.start.to_point(&buffer);
4956                        let mut end = fold.range.end.to_point(&buffer);
4957                        start.row += row_delta;
4958                        end.row += row_delta;
4959                        refold_ranges.push(start..end);
4960                    }
4961                }
4962            }
4963
4964            // If we didn't move line(s), preserve the existing selections
4965            new_selections.append(&mut contiguous_row_selections);
4966        }
4967
4968        self.transact(cx, |this, cx| {
4969            this.unfold_ranges(unfold_ranges, true, true, cx);
4970            this.buffer.update(cx, |buffer, cx| {
4971                for (range, text) in edits {
4972                    buffer.edit([(range, text)], None, cx);
4973                }
4974            });
4975            this.fold_ranges(refold_ranges, true, cx);
4976            this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(new_selections));
4977        });
4978    }
4979
4980    pub fn transpose(&mut self, _: &Transpose, cx: &mut ViewContext<Self>) {
4981        let text_layout_details = &self.text_layout_details(cx);
4982        self.transact(cx, |this, cx| {
4983            let edits = this.change_selections(Some(Autoscroll::fit()), cx, |s| {
4984                let mut edits: Vec<(Range<usize>, String)> = Default::default();
4985                let line_mode = s.line_mode;
4986                s.move_with(|display_map, selection| {
4987                    if !selection.is_empty() || line_mode {
4988                        return;
4989                    }
4990
4991                    let mut head = selection.head();
4992                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
4993                    if head.column() == display_map.line_len(head.row()) {
4994                        transpose_offset = display_map
4995                            .buffer_snapshot
4996                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
4997                    }
4998
4999                    if transpose_offset == 0 {
5000                        return;
5001                    }
5002
5003                    *head.column_mut() += 1;
5004                    head = display_map.clip_point(head, Bias::Right);
5005                    let goal = SelectionGoal::HorizontalPosition(
5006                        display_map
5007                            .x_for_display_point(head, &text_layout_details)
5008                            .into(),
5009                    );
5010                    selection.collapse_to(head, goal);
5011
5012                    let transpose_start = display_map
5013                        .buffer_snapshot
5014                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
5015                    if edits.last().map_or(true, |e| e.0.end <= transpose_start) {
5016                        let transpose_end = display_map
5017                            .buffer_snapshot
5018                            .clip_offset(transpose_offset + 1, Bias::Right);
5019                        if let Some(ch) =
5020                            display_map.buffer_snapshot.chars_at(transpose_start).next()
5021                        {
5022                            edits.push((transpose_start..transpose_offset, String::new()));
5023                            edits.push((transpose_end..transpose_end, ch.to_string()));
5024                        }
5025                    }
5026                });
5027                edits
5028            });
5029            this.buffer
5030                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
5031            let selections = this.selections.all::<usize>(cx);
5032            this.change_selections(Some(Autoscroll::fit()), cx, |s| {
5033                s.select(selections);
5034            });
5035        });
5036    }
5037
5038    pub fn cut(&mut self, _: &Cut, cx: &mut ViewContext<Self>) {
5039        let mut text = String::new();
5040        let buffer = self.buffer.read(cx).snapshot(cx);
5041        let mut selections = self.selections.all::<Point>(cx);
5042        let mut clipboard_selections = Vec::with_capacity(selections.len());
5043        {
5044            let max_point = buffer.max_point();
5045            let mut is_first = true;
5046            for selection in &mut selections {
5047                let is_entire_line = selection.is_empty() || self.selections.line_mode;
5048                if is_entire_line {
5049                    selection.start = Point::new(selection.start.row, 0);
5050                    selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
5051                    selection.goal = SelectionGoal::None;
5052                }
5053                if is_first {
5054                    is_first = false;
5055                } else {
5056                    text += "\n";
5057                }
5058                let mut len = 0;
5059                for chunk in buffer.text_for_range(selection.start..selection.end) {
5060                    text.push_str(chunk);
5061                    len += chunk.len();
5062                }
5063                clipboard_selections.push(ClipboardSelection {
5064                    len,
5065                    is_entire_line,
5066                    first_line_indent: buffer.indent_size_for_line(selection.start.row).len,
5067                });
5068            }
5069        }
5070
5071        self.transact(cx, |this, cx| {
5072            this.change_selections(Some(Autoscroll::fit()), cx, |s| {
5073                s.select(selections);
5074            });
5075            this.insert("", cx);
5076            cx.write_to_clipboard(ClipboardItem::new(text).with_metadata(clipboard_selections));
5077        });
5078    }
5079
5080    pub fn copy(&mut self, _: &Copy, cx: &mut ViewContext<Self>) {
5081        let selections = self.selections.all::<Point>(cx);
5082        let buffer = self.buffer.read(cx).read(cx);
5083        let mut text = String::new();
5084
5085        let mut clipboard_selections = Vec::with_capacity(selections.len());
5086        {
5087            let max_point = buffer.max_point();
5088            let mut is_first = true;
5089            for selection in selections.iter() {
5090                let mut start = selection.start;
5091                let mut end = selection.end;
5092                let is_entire_line = selection.is_empty() || self.selections.line_mode;
5093                if is_entire_line {
5094                    start = Point::new(start.row, 0);
5095                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
5096                }
5097                if is_first {
5098                    is_first = false;
5099                } else {
5100                    text += "\n";
5101                }
5102                let mut len = 0;
5103                for chunk in buffer.text_for_range(start..end) {
5104                    text.push_str(chunk);
5105                    len += chunk.len();
5106                }
5107                clipboard_selections.push(ClipboardSelection {
5108                    len,
5109                    is_entire_line,
5110                    first_line_indent: buffer.indent_size_for_line(start.row).len,
5111                });
5112            }
5113        }
5114
5115        cx.write_to_clipboard(ClipboardItem::new(text).with_metadata(clipboard_selections));
5116    }
5117
5118    pub fn paste(&mut self, _: &Paste, cx: &mut ViewContext<Self>) {
5119        if self.read_only(cx) {
5120            return;
5121        }
5122
5123        self.transact(cx, |this, cx| {
5124            if let Some(item) = cx.read_from_clipboard() {
5125                let clipboard_text = Cow::Borrowed(item.text());
5126                if let Some(mut clipboard_selections) = item.metadata::<Vec<ClipboardSelection>>() {
5127                    let old_selections = this.selections.all::<usize>(cx);
5128                    let all_selections_were_entire_line =
5129                        clipboard_selections.iter().all(|s| s.is_entire_line);
5130                    let first_selection_indent_column =
5131                        clipboard_selections.first().map(|s| s.first_line_indent);
5132                    if clipboard_selections.len() != old_selections.len() {
5133                        clipboard_selections.drain(..);
5134                    }
5135
5136                    this.buffer.update(cx, |buffer, cx| {
5137                        let snapshot = buffer.read(cx);
5138                        let mut start_offset = 0;
5139                        let mut edits = Vec::new();
5140                        let mut original_indent_columns = Vec::new();
5141                        let line_mode = this.selections.line_mode;
5142                        for (ix, selection) in old_selections.iter().enumerate() {
5143                            let to_insert;
5144                            let entire_line;
5145                            let original_indent_column;
5146                            if let Some(clipboard_selection) = clipboard_selections.get(ix) {
5147                                let end_offset = start_offset + clipboard_selection.len;
5148                                to_insert = &clipboard_text[start_offset..end_offset];
5149                                entire_line = clipboard_selection.is_entire_line;
5150                                start_offset = end_offset + 1;
5151                                original_indent_column =
5152                                    Some(clipboard_selection.first_line_indent);
5153                            } else {
5154                                to_insert = clipboard_text.as_str();
5155                                entire_line = all_selections_were_entire_line;
5156                                original_indent_column = first_selection_indent_column
5157                            }
5158
5159                            // If the corresponding selection was empty when this slice of the
5160                            // clipboard text was written, then the entire line containing the
5161                            // selection was copied. If this selection is also currently empty,
5162                            // then paste the line before the current line of the buffer.
5163                            let range = if selection.is_empty() && !line_mode && entire_line {
5164                                let column = selection.start.to_point(&snapshot).column as usize;
5165                                let line_start = selection.start - column;
5166                                line_start..line_start
5167                            } else {
5168                                selection.range()
5169                            };
5170
5171                            edits.push((range, to_insert));
5172                            original_indent_columns.extend(original_indent_column);
5173                        }
5174                        drop(snapshot);
5175
5176                        buffer.edit(
5177                            edits,
5178                            Some(AutoindentMode::Block {
5179                                original_indent_columns,
5180                            }),
5181                            cx,
5182                        );
5183                    });
5184
5185                    let selections = this.selections.all::<usize>(cx);
5186                    this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections));
5187                } else {
5188                    this.insert(&clipboard_text, cx);
5189                }
5190            }
5191        });
5192    }
5193
5194    pub fn undo(&mut self, _: &Undo, cx: &mut ViewContext<Self>) {
5195        if self.read_only(cx) {
5196            return;
5197        }
5198
5199        if let Some(tx_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
5200            if let Some((selections, _)) = self.selection_history.transaction(tx_id).cloned() {
5201                self.change_selections(None, cx, |s| {
5202                    s.select_anchors(selections.to_vec());
5203                });
5204            }
5205            self.request_autoscroll(Autoscroll::fit(), cx);
5206            self.unmark_text(cx);
5207            self.refresh_copilot_suggestions(true, cx);
5208            cx.emit(EditorEvent::Edited);
5209        }
5210    }
5211
5212    pub fn redo(&mut self, _: &Redo, cx: &mut ViewContext<Self>) {
5213        if self.read_only(cx) {
5214            return;
5215        }
5216
5217        if let Some(tx_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
5218            if let Some((_, Some(selections))) = self.selection_history.transaction(tx_id).cloned()
5219            {
5220                self.change_selections(None, cx, |s| {
5221                    s.select_anchors(selections.to_vec());
5222                });
5223            }
5224            self.request_autoscroll(Autoscroll::fit(), cx);
5225            self.unmark_text(cx);
5226            self.refresh_copilot_suggestions(true, cx);
5227            cx.emit(EditorEvent::Edited);
5228        }
5229    }
5230
5231    pub fn finalize_last_transaction(&mut self, cx: &mut ViewContext<Self>) {
5232        self.buffer
5233            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
5234    }
5235
5236    pub fn move_left(&mut self, _: &MoveLeft, cx: &mut ViewContext<Self>) {
5237        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
5238            let line_mode = s.line_mode;
5239            s.move_with(|map, selection| {
5240                let cursor = if selection.is_empty() && !line_mode {
5241                    movement::left(map, selection.start)
5242                } else {
5243                    selection.start
5244                };
5245                selection.collapse_to(cursor, SelectionGoal::None);
5246            });
5247        })
5248    }
5249
5250    pub fn select_left(&mut self, _: &SelectLeft, cx: &mut ViewContext<Self>) {
5251        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
5252            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
5253        })
5254    }
5255
5256    pub fn move_right(&mut self, _: &MoveRight, cx: &mut ViewContext<Self>) {
5257        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
5258            let line_mode = s.line_mode;
5259            s.move_with(|map, selection| {
5260                let cursor = if selection.is_empty() && !line_mode {
5261                    movement::right(map, selection.end)
5262                } else {
5263                    selection.end
5264                };
5265                selection.collapse_to(cursor, SelectionGoal::None)
5266            });
5267        })
5268    }
5269
5270    pub fn select_right(&mut self, _: &SelectRight, cx: &mut ViewContext<Self>) {
5271        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
5272            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
5273        })
5274    }
5275
5276    pub fn move_up(&mut self, _: &MoveUp, cx: &mut ViewContext<Self>) {
5277        if self.take_rename(true, cx).is_some() {
5278            return;
5279        }
5280
5281        if matches!(self.mode, EditorMode::SingleLine) {
5282            cx.propagate();
5283            return;
5284        }
5285
5286        let text_layout_details = &self.text_layout_details(cx);
5287
5288        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
5289            let line_mode = s.line_mode;
5290            s.move_with(|map, selection| {
5291                if !selection.is_empty() && !line_mode {
5292                    selection.goal = SelectionGoal::None;
5293                }
5294                let (cursor, goal) = movement::up(
5295                    map,
5296                    selection.start,
5297                    selection.goal,
5298                    false,
5299                    &text_layout_details,
5300                );
5301                selection.collapse_to(cursor, goal);
5302            });
5303        })
5304    }
5305
5306    pub fn move_page_up(&mut self, action: &MovePageUp, cx: &mut ViewContext<Self>) {
5307        if self.take_rename(true, cx).is_some() {
5308            return;
5309        }
5310
5311        if matches!(self.mode, EditorMode::SingleLine) {
5312            cx.propagate();
5313            return;
5314        }
5315
5316        let row_count = if let Some(row_count) = self.visible_line_count() {
5317            row_count as u32 - 1
5318        } else {
5319            return;
5320        };
5321
5322        let autoscroll = if action.center_cursor {
5323            Autoscroll::center()
5324        } else {
5325            Autoscroll::fit()
5326        };
5327
5328        let text_layout_details = &self.text_layout_details(cx);
5329
5330        self.change_selections(Some(autoscroll), cx, |s| {
5331            let line_mode = s.line_mode;
5332            s.move_with(|map, selection| {
5333                if !selection.is_empty() && !line_mode {
5334                    selection.goal = SelectionGoal::None;
5335                }
5336                let (cursor, goal) = movement::up_by_rows(
5337                    map,
5338                    selection.end,
5339                    row_count,
5340                    selection.goal,
5341                    false,
5342                    &text_layout_details,
5343                );
5344                selection.collapse_to(cursor, goal);
5345            });
5346        });
5347    }
5348
5349    pub fn select_up(&mut self, _: &SelectUp, cx: &mut ViewContext<Self>) {
5350        let text_layout_details = &self.text_layout_details(cx);
5351        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
5352            s.move_heads_with(|map, head, goal| {
5353                movement::up(map, head, goal, false, &text_layout_details)
5354            })
5355        })
5356    }
5357
5358    pub fn move_down(&mut self, _: &MoveDown, cx: &mut ViewContext<Self>) {
5359        self.take_rename(true, cx);
5360
5361        if self.mode == EditorMode::SingleLine {
5362            cx.propagate();
5363            return;
5364        }
5365
5366        let text_layout_details = &self.text_layout_details(cx);
5367        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
5368            let line_mode = s.line_mode;
5369            s.move_with(|map, selection| {
5370                if !selection.is_empty() && !line_mode {
5371                    selection.goal = SelectionGoal::None;
5372                }
5373                let (cursor, goal) = movement::down(
5374                    map,
5375                    selection.end,
5376                    selection.goal,
5377                    false,
5378                    &text_layout_details,
5379                );
5380                selection.collapse_to(cursor, goal);
5381            });
5382        });
5383    }
5384
5385    pub fn move_page_down(&mut self, action: &MovePageDown, cx: &mut ViewContext<Self>) {
5386        if self.take_rename(true, cx).is_some() {
5387            return;
5388        }
5389
5390        if self
5391            .context_menu
5392            .write()
5393            .as_mut()
5394            .map(|menu| menu.select_last(self.project.as_ref(), cx))
5395            .unwrap_or(false)
5396        {
5397            return;
5398        }
5399
5400        if matches!(self.mode, EditorMode::SingleLine) {
5401            cx.propagate();
5402            return;
5403        }
5404
5405        let row_count = if let Some(row_count) = self.visible_line_count() {
5406            row_count as u32 - 1
5407        } else {
5408            return;
5409        };
5410
5411        let autoscroll = if action.center_cursor {
5412            Autoscroll::center()
5413        } else {
5414            Autoscroll::fit()
5415        };
5416
5417        let text_layout_details = &self.text_layout_details(cx);
5418        self.change_selections(Some(autoscroll), cx, |s| {
5419            let line_mode = s.line_mode;
5420            s.move_with(|map, selection| {
5421                if !selection.is_empty() && !line_mode {
5422                    selection.goal = SelectionGoal::None;
5423                }
5424                let (cursor, goal) = movement::down_by_rows(
5425                    map,
5426                    selection.end,
5427                    row_count,
5428                    selection.goal,
5429                    false,
5430                    &text_layout_details,
5431                );
5432                selection.collapse_to(cursor, goal);
5433            });
5434        });
5435    }
5436
5437    pub fn select_down(&mut self, _: &SelectDown, cx: &mut ViewContext<Self>) {
5438        let text_layout_details = &self.text_layout_details(cx);
5439        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
5440            s.move_heads_with(|map, head, goal| {
5441                movement::down(map, head, goal, false, &text_layout_details)
5442            })
5443        });
5444    }
5445
5446    pub fn context_menu_first(&mut self, _: &ContextMenuFirst, cx: &mut ViewContext<Self>) {
5447        if let Some(context_menu) = self.context_menu.write().as_mut() {
5448            context_menu.select_first(self.project.as_ref(), cx);
5449        }
5450    }
5451
5452    pub fn context_menu_prev(&mut self, _: &ContextMenuPrev, cx: &mut ViewContext<Self>) {
5453        if let Some(context_menu) = self.context_menu.write().as_mut() {
5454            context_menu.select_prev(self.project.as_ref(), cx);
5455        }
5456    }
5457
5458    pub fn context_menu_next(&mut self, _: &ContextMenuNext, cx: &mut ViewContext<Self>) {
5459        if let Some(context_menu) = self.context_menu.write().as_mut() {
5460            context_menu.select_next(self.project.as_ref(), cx);
5461        }
5462    }
5463
5464    pub fn context_menu_last(&mut self, _: &ContextMenuLast, cx: &mut ViewContext<Self>) {
5465        if let Some(context_menu) = self.context_menu.write().as_mut() {
5466            context_menu.select_last(self.project.as_ref(), cx);
5467        }
5468    }
5469
5470    pub fn move_to_previous_word_start(
5471        &mut self,
5472        _: &MoveToPreviousWordStart,
5473        cx: &mut ViewContext<Self>,
5474    ) {
5475        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
5476            s.move_cursors_with(|map, head, _| {
5477                (
5478                    movement::previous_word_start(map, head),
5479                    SelectionGoal::None,
5480                )
5481            });
5482        })
5483    }
5484
5485    pub fn move_to_previous_subword_start(
5486        &mut self,
5487        _: &MoveToPreviousSubwordStart,
5488        cx: &mut ViewContext<Self>,
5489    ) {
5490        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
5491            s.move_cursors_with(|map, head, _| {
5492                (
5493                    movement::previous_subword_start(map, head),
5494                    SelectionGoal::None,
5495                )
5496            });
5497        })
5498    }
5499
5500    pub fn select_to_previous_word_start(
5501        &mut self,
5502        _: &SelectToPreviousWordStart,
5503        cx: &mut ViewContext<Self>,
5504    ) {
5505        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
5506            s.move_heads_with(|map, head, _| {
5507                (
5508                    movement::previous_word_start(map, head),
5509                    SelectionGoal::None,
5510                )
5511            });
5512        })
5513    }
5514
5515    pub fn select_to_previous_subword_start(
5516        &mut self,
5517        _: &SelectToPreviousSubwordStart,
5518        cx: &mut ViewContext<Self>,
5519    ) {
5520        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
5521            s.move_heads_with(|map, head, _| {
5522                (
5523                    movement::previous_subword_start(map, head),
5524                    SelectionGoal::None,
5525                )
5526            });
5527        })
5528    }
5529
5530    pub fn delete_to_previous_word_start(
5531        &mut self,
5532        _: &DeleteToPreviousWordStart,
5533        cx: &mut ViewContext<Self>,
5534    ) {
5535        self.transact(cx, |this, cx| {
5536            this.select_autoclose_pair(cx);
5537            this.change_selections(Some(Autoscroll::fit()), cx, |s| {
5538                let line_mode = s.line_mode;
5539                s.move_with(|map, selection| {
5540                    if selection.is_empty() && !line_mode {
5541                        let cursor = movement::previous_word_start(map, selection.head());
5542                        selection.set_head(cursor, SelectionGoal::None);
5543                    }
5544                });
5545            });
5546            this.insert("", cx);
5547        });
5548    }
5549
5550    pub fn delete_to_previous_subword_start(
5551        &mut self,
5552        _: &DeleteToPreviousSubwordStart,
5553        cx: &mut ViewContext<Self>,
5554    ) {
5555        self.transact(cx, |this, cx| {
5556            this.select_autoclose_pair(cx);
5557            this.change_selections(Some(Autoscroll::fit()), cx, |s| {
5558                let line_mode = s.line_mode;
5559                s.move_with(|map, selection| {
5560                    if selection.is_empty() && !line_mode {
5561                        let cursor = movement::previous_subword_start(map, selection.head());
5562                        selection.set_head(cursor, SelectionGoal::None);
5563                    }
5564                });
5565            });
5566            this.insert("", cx);
5567        });
5568    }
5569
5570    pub fn move_to_next_word_end(&mut self, _: &MoveToNextWordEnd, cx: &mut ViewContext<Self>) {
5571        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
5572            s.move_cursors_with(|map, head, _| {
5573                (movement::next_word_end(map, head), SelectionGoal::None)
5574            });
5575        })
5576    }
5577
5578    pub fn move_to_next_subword_end(
5579        &mut self,
5580        _: &MoveToNextSubwordEnd,
5581        cx: &mut ViewContext<Self>,
5582    ) {
5583        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
5584            s.move_cursors_with(|map, head, _| {
5585                (movement::next_subword_end(map, head), SelectionGoal::None)
5586            });
5587        })
5588    }
5589
5590    pub fn select_to_next_word_end(&mut self, _: &SelectToNextWordEnd, cx: &mut ViewContext<Self>) {
5591        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
5592            s.move_heads_with(|map, head, _| {
5593                (movement::next_word_end(map, head), SelectionGoal::None)
5594            });
5595        })
5596    }
5597
5598    pub fn select_to_next_subword_end(
5599        &mut self,
5600        _: &SelectToNextSubwordEnd,
5601        cx: &mut ViewContext<Self>,
5602    ) {
5603        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
5604            s.move_heads_with(|map, head, _| {
5605                (movement::next_subword_end(map, head), SelectionGoal::None)
5606            });
5607        })
5608    }
5609
5610    pub fn delete_to_next_word_end(&mut self, _: &DeleteToNextWordEnd, cx: &mut ViewContext<Self>) {
5611        self.transact(cx, |this, cx| {
5612            this.change_selections(Some(Autoscroll::fit()), cx, |s| {
5613                let line_mode = s.line_mode;
5614                s.move_with(|map, selection| {
5615                    if selection.is_empty() && !line_mode {
5616                        let cursor = movement::next_word_end(map, selection.head());
5617                        selection.set_head(cursor, SelectionGoal::None);
5618                    }
5619                });
5620            });
5621            this.insert("", cx);
5622        });
5623    }
5624
5625    pub fn delete_to_next_subword_end(
5626        &mut self,
5627        _: &DeleteToNextSubwordEnd,
5628        cx: &mut ViewContext<Self>,
5629    ) {
5630        self.transact(cx, |this, cx| {
5631            this.change_selections(Some(Autoscroll::fit()), cx, |s| {
5632                s.move_with(|map, selection| {
5633                    if selection.is_empty() {
5634                        let cursor = movement::next_subword_end(map, selection.head());
5635                        selection.set_head(cursor, SelectionGoal::None);
5636                    }
5637                });
5638            });
5639            this.insert("", cx);
5640        });
5641    }
5642
5643    pub fn move_to_beginning_of_line(
5644        &mut self,
5645        _: &MoveToBeginningOfLine,
5646        cx: &mut ViewContext<Self>,
5647    ) {
5648        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
5649            s.move_cursors_with(|map, head, _| {
5650                (
5651                    movement::indented_line_beginning(map, head, true),
5652                    SelectionGoal::None,
5653                )
5654            });
5655        })
5656    }
5657
5658    pub fn select_to_beginning_of_line(
5659        &mut self,
5660        action: &SelectToBeginningOfLine,
5661        cx: &mut ViewContext<Self>,
5662    ) {
5663        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
5664            s.move_heads_with(|map, head, _| {
5665                (
5666                    movement::indented_line_beginning(map, head, action.stop_at_soft_wraps),
5667                    SelectionGoal::None,
5668                )
5669            });
5670        });
5671    }
5672
5673    pub fn delete_to_beginning_of_line(
5674        &mut self,
5675        _: &DeleteToBeginningOfLine,
5676        cx: &mut ViewContext<Self>,
5677    ) {
5678        self.transact(cx, |this, cx| {
5679            this.change_selections(Some(Autoscroll::fit()), cx, |s| {
5680                s.move_with(|_, selection| {
5681                    selection.reversed = true;
5682                });
5683            });
5684
5685            this.select_to_beginning_of_line(
5686                &SelectToBeginningOfLine {
5687                    stop_at_soft_wraps: false,
5688                },
5689                cx,
5690            );
5691            this.backspace(&Backspace, cx);
5692        });
5693    }
5694
5695    pub fn move_to_end_of_line(&mut self, _: &MoveToEndOfLine, cx: &mut ViewContext<Self>) {
5696        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
5697            s.move_cursors_with(|map, head, _| {
5698                (movement::line_end(map, head, true), SelectionGoal::None)
5699            });
5700        })
5701    }
5702
5703    pub fn select_to_end_of_line(
5704        &mut self,
5705        action: &SelectToEndOfLine,
5706        cx: &mut ViewContext<Self>,
5707    ) {
5708        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
5709            s.move_heads_with(|map, head, _| {
5710                (
5711                    movement::line_end(map, head, action.stop_at_soft_wraps),
5712                    SelectionGoal::None,
5713                )
5714            });
5715        })
5716    }
5717
5718    pub fn delete_to_end_of_line(&mut self, _: &DeleteToEndOfLine, cx: &mut ViewContext<Self>) {
5719        self.transact(cx, |this, cx| {
5720            this.select_to_end_of_line(
5721                &SelectToEndOfLine {
5722                    stop_at_soft_wraps: false,
5723                },
5724                cx,
5725            );
5726            this.delete(&Delete, cx);
5727        });
5728    }
5729
5730    pub fn cut_to_end_of_line(&mut self, _: &CutToEndOfLine, cx: &mut ViewContext<Self>) {
5731        self.transact(cx, |this, cx| {
5732            this.select_to_end_of_line(
5733                &SelectToEndOfLine {
5734                    stop_at_soft_wraps: false,
5735                },
5736                cx,
5737            );
5738            this.cut(&Cut, cx);
5739        });
5740    }
5741
5742    pub fn move_to_start_of_paragraph(
5743        &mut self,
5744        _: &MoveToStartOfParagraph,
5745        cx: &mut ViewContext<Self>,
5746    ) {
5747        if matches!(self.mode, EditorMode::SingleLine) {
5748            cx.propagate();
5749            return;
5750        }
5751
5752        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
5753            s.move_with(|map, selection| {
5754                selection.collapse_to(
5755                    movement::start_of_paragraph(map, selection.head(), 1),
5756                    SelectionGoal::None,
5757                )
5758            });
5759        })
5760    }
5761
5762    pub fn move_to_end_of_paragraph(
5763        &mut self,
5764        _: &MoveToEndOfParagraph,
5765        cx: &mut ViewContext<Self>,
5766    ) {
5767        if matches!(self.mode, EditorMode::SingleLine) {
5768            cx.propagate();
5769            return;
5770        }
5771
5772        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
5773            s.move_with(|map, selection| {
5774                selection.collapse_to(
5775                    movement::end_of_paragraph(map, selection.head(), 1),
5776                    SelectionGoal::None,
5777                )
5778            });
5779        })
5780    }
5781
5782    pub fn select_to_start_of_paragraph(
5783        &mut self,
5784        _: &SelectToStartOfParagraph,
5785        cx: &mut ViewContext<Self>,
5786    ) {
5787        if matches!(self.mode, EditorMode::SingleLine) {
5788            cx.propagate();
5789            return;
5790        }
5791
5792        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
5793            s.move_heads_with(|map, head, _| {
5794                (
5795                    movement::start_of_paragraph(map, head, 1),
5796                    SelectionGoal::None,
5797                )
5798            });
5799        })
5800    }
5801
5802    pub fn select_to_end_of_paragraph(
5803        &mut self,
5804        _: &SelectToEndOfParagraph,
5805        cx: &mut ViewContext<Self>,
5806    ) {
5807        if matches!(self.mode, EditorMode::SingleLine) {
5808            cx.propagate();
5809            return;
5810        }
5811
5812        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
5813            s.move_heads_with(|map, head, _| {
5814                (
5815                    movement::end_of_paragraph(map, head, 1),
5816                    SelectionGoal::None,
5817                )
5818            });
5819        })
5820    }
5821
5822    pub fn move_to_beginning(&mut self, _: &MoveToBeginning, cx: &mut ViewContext<Self>) {
5823        if matches!(self.mode, EditorMode::SingleLine) {
5824            cx.propagate();
5825            return;
5826        }
5827
5828        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
5829            s.select_ranges(vec![0..0]);
5830        });
5831    }
5832
5833    pub fn select_to_beginning(&mut self, _: &SelectToBeginning, cx: &mut ViewContext<Self>) {
5834        let mut selection = self.selections.last::<Point>(cx);
5835        selection.set_head(Point::zero(), SelectionGoal::None);
5836
5837        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
5838            s.select(vec![selection]);
5839        });
5840    }
5841
5842    pub fn move_to_end(&mut self, _: &MoveToEnd, cx: &mut ViewContext<Self>) {
5843        if matches!(self.mode, EditorMode::SingleLine) {
5844            cx.propagate();
5845            return;
5846        }
5847
5848        let cursor = self.buffer.read(cx).read(cx).len();
5849        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
5850            s.select_ranges(vec![cursor..cursor])
5851        });
5852    }
5853
5854    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
5855        self.nav_history = nav_history;
5856    }
5857
5858    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
5859        self.nav_history.as_ref()
5860    }
5861
5862    fn push_to_nav_history(
5863        &mut self,
5864        cursor_anchor: Anchor,
5865        new_position: Option<Point>,
5866        cx: &mut ViewContext<Self>,
5867    ) {
5868        if let Some(nav_history) = self.nav_history.as_mut() {
5869            let buffer = self.buffer.read(cx).read(cx);
5870            let cursor_position = cursor_anchor.to_point(&buffer);
5871            let scroll_state = self.scroll_manager.anchor();
5872            let scroll_top_row = scroll_state.top_row(&buffer);
5873            drop(buffer);
5874
5875            if let Some(new_position) = new_position {
5876                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
5877                if row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA {
5878                    return;
5879                }
5880            }
5881
5882            nav_history.push(
5883                Some(NavigationData {
5884                    cursor_anchor,
5885                    cursor_position,
5886                    scroll_anchor: scroll_state,
5887                    scroll_top_row,
5888                }),
5889                cx,
5890            );
5891        }
5892    }
5893
5894    pub fn select_to_end(&mut self, _: &SelectToEnd, cx: &mut ViewContext<Self>) {
5895        let buffer = self.buffer.read(cx).snapshot(cx);
5896        let mut selection = self.selections.first::<usize>(cx);
5897        selection.set_head(buffer.len(), SelectionGoal::None);
5898        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
5899            s.select(vec![selection]);
5900        });
5901    }
5902
5903    pub fn select_all(&mut self, _: &SelectAll, cx: &mut ViewContext<Self>) {
5904        let end = self.buffer.read(cx).read(cx).len();
5905        self.change_selections(None, cx, |s| {
5906            s.select_ranges(vec![0..end]);
5907        });
5908    }
5909
5910    pub fn select_line(&mut self, _: &SelectLine, cx: &mut ViewContext<Self>) {
5911        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
5912        let mut selections = self.selections.all::<Point>(cx);
5913        let max_point = display_map.buffer_snapshot.max_point();
5914        for selection in &mut selections {
5915            let rows = selection.spanned_rows(true, &display_map);
5916            selection.start = Point::new(rows.start, 0);
5917            selection.end = cmp::min(max_point, Point::new(rows.end, 0));
5918            selection.reversed = false;
5919        }
5920        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
5921            s.select(selections);
5922        });
5923    }
5924
5925    pub fn split_selection_into_lines(
5926        &mut self,
5927        _: &SplitSelectionIntoLines,
5928        cx: &mut ViewContext<Self>,
5929    ) {
5930        let mut to_unfold = Vec::new();
5931        let mut new_selection_ranges = Vec::new();
5932        {
5933            let selections = self.selections.all::<Point>(cx);
5934            let buffer = self.buffer.read(cx).read(cx);
5935            for selection in selections {
5936                for row in selection.start.row..selection.end.row {
5937                    let cursor = Point::new(row, buffer.line_len(row));
5938                    new_selection_ranges.push(cursor..cursor);
5939                }
5940                new_selection_ranges.push(selection.end..selection.end);
5941                to_unfold.push(selection.start..selection.end);
5942            }
5943        }
5944        self.unfold_ranges(to_unfold, true, true, cx);
5945        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
5946            s.select_ranges(new_selection_ranges);
5947        });
5948    }
5949
5950    pub fn add_selection_above(&mut self, _: &AddSelectionAbove, cx: &mut ViewContext<Self>) {
5951        self.add_selection(true, cx);
5952    }
5953
5954    pub fn add_selection_below(&mut self, _: &AddSelectionBelow, cx: &mut ViewContext<Self>) {
5955        self.add_selection(false, cx);
5956    }
5957
5958    fn add_selection(&mut self, above: bool, cx: &mut ViewContext<Self>) {
5959        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
5960        let mut selections = self.selections.all::<Point>(cx);
5961        let text_layout_details = self.text_layout_details(cx);
5962        let mut state = self.add_selections_state.take().unwrap_or_else(|| {
5963            let oldest_selection = selections.iter().min_by_key(|s| s.id).unwrap().clone();
5964            let range = oldest_selection.display_range(&display_map).sorted();
5965
5966            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
5967            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
5968            let positions = start_x.min(end_x)..start_x.max(end_x);
5969
5970            selections.clear();
5971            let mut stack = Vec::new();
5972            for row in range.start.row()..=range.end.row() {
5973                if let Some(selection) = self.selections.build_columnar_selection(
5974                    &display_map,
5975                    row,
5976                    &positions,
5977                    oldest_selection.reversed,
5978                    &text_layout_details,
5979                ) {
5980                    stack.push(selection.id);
5981                    selections.push(selection);
5982                }
5983            }
5984
5985            if above {
5986                stack.reverse();
5987            }
5988
5989            AddSelectionsState { above, stack }
5990        });
5991
5992        let last_added_selection = *state.stack.last().unwrap();
5993        let mut new_selections = Vec::new();
5994        if above == state.above {
5995            let end_row = if above {
5996                0
5997            } else {
5998                display_map.max_point().row()
5999            };
6000
6001            'outer: for selection in selections {
6002                if selection.id == last_added_selection {
6003                    let range = selection.display_range(&display_map).sorted();
6004                    debug_assert_eq!(range.start.row(), range.end.row());
6005                    let mut row = range.start.row();
6006                    let positions =
6007                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
6008                            px(start)..px(end)
6009                        } else {
6010                            let start_x =
6011                                display_map.x_for_display_point(range.start, &text_layout_details);
6012                            let end_x =
6013                                display_map.x_for_display_point(range.end, &text_layout_details);
6014                            start_x.min(end_x)..start_x.max(end_x)
6015                        };
6016
6017                    while row != end_row {
6018                        if above {
6019                            row -= 1;
6020                        } else {
6021                            row += 1;
6022                        }
6023
6024                        if let Some(new_selection) = self.selections.build_columnar_selection(
6025                            &display_map,
6026                            row,
6027                            &positions,
6028                            selection.reversed,
6029                            &text_layout_details,
6030                        ) {
6031                            state.stack.push(new_selection.id);
6032                            if above {
6033                                new_selections.push(new_selection);
6034                                new_selections.push(selection);
6035                            } else {
6036                                new_selections.push(selection);
6037                                new_selections.push(new_selection);
6038                            }
6039
6040                            continue 'outer;
6041                        }
6042                    }
6043                }
6044
6045                new_selections.push(selection);
6046            }
6047        } else {
6048            new_selections = selections;
6049            new_selections.retain(|s| s.id != last_added_selection);
6050            state.stack.pop();
6051        }
6052
6053        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
6054            s.select(new_selections);
6055        });
6056        if state.stack.len() > 1 {
6057            self.add_selections_state = Some(state);
6058        }
6059    }
6060
6061    pub fn select_next_match_internal(
6062        &mut self,
6063        display_map: &DisplaySnapshot,
6064        replace_newest: bool,
6065        autoscroll: Option<Autoscroll>,
6066        cx: &mut ViewContext<Self>,
6067    ) -> Result<()> {
6068        fn select_next_match_ranges(
6069            this: &mut Editor,
6070            range: Range<usize>,
6071            replace_newest: bool,
6072            auto_scroll: Option<Autoscroll>,
6073            cx: &mut ViewContext<Editor>,
6074        ) {
6075            this.unfold_ranges([range.clone()], false, true, cx);
6076            this.change_selections(auto_scroll, cx, |s| {
6077                if replace_newest {
6078                    s.delete(s.newest_anchor().id);
6079                }
6080                s.insert_range(range.clone());
6081            });
6082        }
6083
6084        let buffer = &display_map.buffer_snapshot;
6085        let mut selections = self.selections.all::<usize>(cx);
6086        if let Some(mut select_next_state) = self.select_next_state.take() {
6087            let query = &select_next_state.query;
6088            if !select_next_state.done {
6089                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
6090                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
6091                let mut next_selected_range = None;
6092
6093                let bytes_after_last_selection =
6094                    buffer.bytes_in_range(last_selection.end..buffer.len());
6095                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
6096                let query_matches = query
6097                    .stream_find_iter(bytes_after_last_selection)
6098                    .map(|result| (last_selection.end, result))
6099                    .chain(
6100                        query
6101                            .stream_find_iter(bytes_before_first_selection)
6102                            .map(|result| (0, result)),
6103                    );
6104
6105                for (start_offset, query_match) in query_matches {
6106                    let query_match = query_match.unwrap(); // can only fail due to I/O
6107                    let offset_range =
6108                        start_offset + query_match.start()..start_offset + query_match.end();
6109                    let display_range = offset_range.start.to_display_point(&display_map)
6110                        ..offset_range.end.to_display_point(&display_map);
6111
6112                    if !select_next_state.wordwise
6113                        || (!movement::is_inside_word(&display_map, display_range.start)
6114                            && !movement::is_inside_word(&display_map, display_range.end))
6115                    {
6116                        if selections
6117                            .iter()
6118                            .find(|selection| selection.range().overlaps(&offset_range))
6119                            .is_none()
6120                        {
6121                            next_selected_range = Some(offset_range);
6122                            break;
6123                        }
6124                    }
6125                }
6126
6127                if let Some(next_selected_range) = next_selected_range {
6128                    select_next_match_ranges(
6129                        self,
6130                        next_selected_range,
6131                        replace_newest,
6132                        autoscroll,
6133                        cx,
6134                    );
6135                } else {
6136                    select_next_state.done = true;
6137                }
6138            }
6139
6140            self.select_next_state = Some(select_next_state);
6141        } else {
6142            let mut only_carets = true;
6143            let mut same_text_selected = true;
6144            let mut selected_text = None;
6145
6146            let mut selections_iter = selections.iter().peekable();
6147            while let Some(selection) = selections_iter.next() {
6148                if selection.start != selection.end {
6149                    only_carets = false;
6150                }
6151
6152                if same_text_selected {
6153                    if selected_text.is_none() {
6154                        selected_text =
6155                            Some(buffer.text_for_range(selection.range()).collect::<String>());
6156                    }
6157
6158                    if let Some(next_selection) = selections_iter.peek() {
6159                        if next_selection.range().len() == selection.range().len() {
6160                            let next_selected_text = buffer
6161                                .text_for_range(next_selection.range())
6162                                .collect::<String>();
6163                            if Some(next_selected_text) != selected_text {
6164                                same_text_selected = false;
6165                                selected_text = None;
6166                            }
6167                        } else {
6168                            same_text_selected = false;
6169                            selected_text = None;
6170                        }
6171                    }
6172                }
6173            }
6174
6175            if only_carets {
6176                for selection in &mut selections {
6177                    let word_range = movement::surrounding_word(
6178                        &display_map,
6179                        selection.start.to_display_point(&display_map),
6180                    );
6181                    selection.start = word_range.start.to_offset(&display_map, Bias::Left);
6182                    selection.end = word_range.end.to_offset(&display_map, Bias::Left);
6183                    selection.goal = SelectionGoal::None;
6184                    selection.reversed = false;
6185                    select_next_match_ranges(
6186                        self,
6187                        selection.start..selection.end,
6188                        replace_newest,
6189                        autoscroll,
6190                        cx,
6191                    );
6192                }
6193
6194                if selections.len() == 1 {
6195                    let selection = selections
6196                        .last()
6197                        .expect("ensured that there's only one selection");
6198                    let query = buffer
6199                        .text_for_range(selection.start..selection.end)
6200                        .collect::<String>();
6201                    let is_empty = query.is_empty();
6202                    let select_state = SelectNextState {
6203                        query: AhoCorasick::new(&[query])?,
6204                        wordwise: true,
6205                        done: is_empty,
6206                    };
6207                    self.select_next_state = Some(select_state);
6208                } else {
6209                    self.select_next_state = None;
6210                }
6211            } else if let Some(selected_text) = selected_text {
6212                self.select_next_state = Some(SelectNextState {
6213                    query: AhoCorasick::new(&[selected_text])?,
6214                    wordwise: false,
6215                    done: false,
6216                });
6217                self.select_next_match_internal(display_map, replace_newest, autoscroll, cx)?;
6218            }
6219        }
6220        Ok(())
6221    }
6222
6223    pub fn select_all_matches(
6224        &mut self,
6225        action: &SelectAllMatches,
6226        cx: &mut ViewContext<Self>,
6227    ) -> Result<()> {
6228        self.push_to_selection_history();
6229        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
6230
6231        loop {
6232            self.select_next_match_internal(&display_map, action.replace_newest, None, cx)?;
6233
6234            if self
6235                .select_next_state
6236                .as_ref()
6237                .map(|selection_state| selection_state.done)
6238                .unwrap_or(true)
6239            {
6240                break;
6241            }
6242        }
6243
6244        Ok(())
6245    }
6246
6247    pub fn select_next(&mut self, action: &SelectNext, cx: &mut ViewContext<Self>) -> Result<()> {
6248        self.push_to_selection_history();
6249        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
6250        self.select_next_match_internal(
6251            &display_map,
6252            action.replace_newest,
6253            Some(Autoscroll::newest()),
6254            cx,
6255        )?;
6256        Ok(())
6257    }
6258
6259    pub fn select_previous(
6260        &mut self,
6261        action: &SelectPrevious,
6262        cx: &mut ViewContext<Self>,
6263    ) -> Result<()> {
6264        self.push_to_selection_history();
6265        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
6266        let buffer = &display_map.buffer_snapshot;
6267        let mut selections = self.selections.all::<usize>(cx);
6268        if let Some(mut select_prev_state) = self.select_prev_state.take() {
6269            let query = &select_prev_state.query;
6270            if !select_prev_state.done {
6271                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
6272                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
6273                let mut next_selected_range = None;
6274                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
6275                let bytes_before_last_selection =
6276                    buffer.reversed_bytes_in_range(0..last_selection.start);
6277                let bytes_after_first_selection =
6278                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
6279                let query_matches = query
6280                    .stream_find_iter(bytes_before_last_selection)
6281                    .map(|result| (last_selection.start, result))
6282                    .chain(
6283                        query
6284                            .stream_find_iter(bytes_after_first_selection)
6285                            .map(|result| (buffer.len(), result)),
6286                    );
6287                for (end_offset, query_match) in query_matches {
6288                    let query_match = query_match.unwrap(); // can only fail due to I/O
6289                    let offset_range =
6290                        end_offset - query_match.end()..end_offset - query_match.start();
6291                    let display_range = offset_range.start.to_display_point(&display_map)
6292                        ..offset_range.end.to_display_point(&display_map);
6293
6294                    if !select_prev_state.wordwise
6295                        || (!movement::is_inside_word(&display_map, display_range.start)
6296                            && !movement::is_inside_word(&display_map, display_range.end))
6297                    {
6298                        next_selected_range = Some(offset_range);
6299                        break;
6300                    }
6301                }
6302
6303                if let Some(next_selected_range) = next_selected_range {
6304                    self.unfold_ranges([next_selected_range.clone()], false, true, cx);
6305                    self.change_selections(Some(Autoscroll::newest()), cx, |s| {
6306                        if action.replace_newest {
6307                            s.delete(s.newest_anchor().id);
6308                        }
6309                        s.insert_range(next_selected_range);
6310                    });
6311                } else {
6312                    select_prev_state.done = true;
6313                }
6314            }
6315
6316            self.select_prev_state = Some(select_prev_state);
6317        } else {
6318            let mut only_carets = true;
6319            let mut same_text_selected = true;
6320            let mut selected_text = None;
6321
6322            let mut selections_iter = selections.iter().peekable();
6323            while let Some(selection) = selections_iter.next() {
6324                if selection.start != selection.end {
6325                    only_carets = false;
6326                }
6327
6328                if same_text_selected {
6329                    if selected_text.is_none() {
6330                        selected_text =
6331                            Some(buffer.text_for_range(selection.range()).collect::<String>());
6332                    }
6333
6334                    if let Some(next_selection) = selections_iter.peek() {
6335                        if next_selection.range().len() == selection.range().len() {
6336                            let next_selected_text = buffer
6337                                .text_for_range(next_selection.range())
6338                                .collect::<String>();
6339                            if Some(next_selected_text) != selected_text {
6340                                same_text_selected = false;
6341                                selected_text = None;
6342                            }
6343                        } else {
6344                            same_text_selected = false;
6345                            selected_text = None;
6346                        }
6347                    }
6348                }
6349            }
6350
6351            if only_carets {
6352                for selection in &mut selections {
6353                    let word_range = movement::surrounding_word(
6354                        &display_map,
6355                        selection.start.to_display_point(&display_map),
6356                    );
6357                    selection.start = word_range.start.to_offset(&display_map, Bias::Left);
6358                    selection.end = word_range.end.to_offset(&display_map, Bias::Left);
6359                    selection.goal = SelectionGoal::None;
6360                    selection.reversed = false;
6361                }
6362                if selections.len() == 1 {
6363                    let selection = selections
6364                        .last()
6365                        .expect("ensured that there's only one selection");
6366                    let query = buffer
6367                        .text_for_range(selection.start..selection.end)
6368                        .collect::<String>();
6369                    let is_empty = query.is_empty();
6370                    let select_state = SelectNextState {
6371                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
6372                        wordwise: true,
6373                        done: is_empty,
6374                    };
6375                    self.select_prev_state = Some(select_state);
6376                } else {
6377                    self.select_prev_state = None;
6378                }
6379
6380                self.unfold_ranges(
6381                    selections.iter().map(|s| s.range()).collect::<Vec<_>>(),
6382                    false,
6383                    true,
6384                    cx,
6385                );
6386                self.change_selections(Some(Autoscroll::newest()), cx, |s| {
6387                    s.select(selections);
6388                });
6389            } else if let Some(selected_text) = selected_text {
6390                self.select_prev_state = Some(SelectNextState {
6391                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
6392                    wordwise: false,
6393                    done: false,
6394                });
6395                self.select_previous(action, cx)?;
6396            }
6397        }
6398        Ok(())
6399    }
6400
6401    pub fn toggle_comments(&mut self, action: &ToggleComments, cx: &mut ViewContext<Self>) {
6402        let text_layout_details = &self.text_layout_details(cx);
6403        self.transact(cx, |this, cx| {
6404            let mut selections = this.selections.all::<Point>(cx);
6405            let mut edits = Vec::new();
6406            let mut selection_edit_ranges = Vec::new();
6407            let mut last_toggled_row = None;
6408            let snapshot = this.buffer.read(cx).read(cx);
6409            let empty_str: Arc<str> = "".into();
6410            let mut suffixes_inserted = Vec::new();
6411
6412            fn comment_prefix_range(
6413                snapshot: &MultiBufferSnapshot,
6414                row: u32,
6415                comment_prefix: &str,
6416                comment_prefix_whitespace: &str,
6417            ) -> Range<Point> {
6418                let start = Point::new(row, snapshot.indent_size_for_line(row).len);
6419
6420                let mut line_bytes = snapshot
6421                    .bytes_in_range(start..snapshot.max_point())
6422                    .flatten()
6423                    .copied();
6424
6425                // If this line currently begins with the line comment prefix, then record
6426                // the range containing the prefix.
6427                if line_bytes
6428                    .by_ref()
6429                    .take(comment_prefix.len())
6430                    .eq(comment_prefix.bytes())
6431                {
6432                    // Include any whitespace that matches the comment prefix.
6433                    let matching_whitespace_len = line_bytes
6434                        .zip(comment_prefix_whitespace.bytes())
6435                        .take_while(|(a, b)| a == b)
6436                        .count() as u32;
6437                    let end = Point::new(
6438                        start.row,
6439                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
6440                    );
6441                    start..end
6442                } else {
6443                    start..start
6444                }
6445            }
6446
6447            fn comment_suffix_range(
6448                snapshot: &MultiBufferSnapshot,
6449                row: u32,
6450                comment_suffix: &str,
6451                comment_suffix_has_leading_space: bool,
6452            ) -> Range<Point> {
6453                let end = Point::new(row, snapshot.line_len(row));
6454                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
6455
6456                let mut line_end_bytes = snapshot
6457                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
6458                    .flatten()
6459                    .copied();
6460
6461                let leading_space_len = if suffix_start_column > 0
6462                    && line_end_bytes.next() == Some(b' ')
6463                    && comment_suffix_has_leading_space
6464                {
6465                    1
6466                } else {
6467                    0
6468                };
6469
6470                // If this line currently begins with the line comment prefix, then record
6471                // the range containing the prefix.
6472                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
6473                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
6474                    start..end
6475                } else {
6476                    end..end
6477                }
6478            }
6479
6480            // TODO: Handle selections that cross excerpts
6481            for selection in &mut selections {
6482                let start_column = snapshot.indent_size_for_line(selection.start.row).len;
6483                let language = if let Some(language) =
6484                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
6485                {
6486                    language
6487                } else {
6488                    continue;
6489                };
6490
6491                selection_edit_ranges.clear();
6492
6493                // If multiple selections contain a given row, avoid processing that
6494                // row more than once.
6495                let mut start_row = selection.start.row;
6496                if last_toggled_row == Some(start_row) {
6497                    start_row += 1;
6498                }
6499                let end_row =
6500                    if selection.end.row > selection.start.row && selection.end.column == 0 {
6501                        selection.end.row - 1
6502                    } else {
6503                        selection.end.row
6504                    };
6505                last_toggled_row = Some(end_row);
6506
6507                if start_row > end_row {
6508                    continue;
6509                }
6510
6511                // If the language has line comments, toggle those.
6512                if let Some(full_comment_prefix) = language.line_comment_prefix() {
6513                    // Split the comment prefix's trailing whitespace into a separate string,
6514                    // as that portion won't be used for detecting if a line is a comment.
6515                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
6516                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
6517                    let mut all_selection_lines_are_comments = true;
6518
6519                    for row in start_row..=end_row {
6520                        if snapshot.is_line_blank(row) && start_row < end_row {
6521                            continue;
6522                        }
6523
6524                        let prefix_range = comment_prefix_range(
6525                            snapshot.deref(),
6526                            row,
6527                            comment_prefix,
6528                            comment_prefix_whitespace,
6529                        );
6530                        if prefix_range.is_empty() {
6531                            all_selection_lines_are_comments = false;
6532                        }
6533                        selection_edit_ranges.push(prefix_range);
6534                    }
6535
6536                    if all_selection_lines_are_comments {
6537                        edits.extend(
6538                            selection_edit_ranges
6539                                .iter()
6540                                .cloned()
6541                                .map(|range| (range, empty_str.clone())),
6542                        );
6543                    } else {
6544                        let min_column = selection_edit_ranges
6545                            .iter()
6546                            .map(|r| r.start.column)
6547                            .min()
6548                            .unwrap_or(0);
6549                        edits.extend(selection_edit_ranges.iter().map(|range| {
6550                            let position = Point::new(range.start.row, min_column);
6551                            (position..position, full_comment_prefix.clone())
6552                        }));
6553                    }
6554                } else if let Some((full_comment_prefix, comment_suffix)) =
6555                    language.block_comment_delimiters()
6556                {
6557                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
6558                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
6559                    let prefix_range = comment_prefix_range(
6560                        snapshot.deref(),
6561                        start_row,
6562                        comment_prefix,
6563                        comment_prefix_whitespace,
6564                    );
6565                    let suffix_range = comment_suffix_range(
6566                        snapshot.deref(),
6567                        end_row,
6568                        comment_suffix.trim_start_matches(' '),
6569                        comment_suffix.starts_with(' '),
6570                    );
6571
6572                    if prefix_range.is_empty() || suffix_range.is_empty() {
6573                        edits.push((
6574                            prefix_range.start..prefix_range.start,
6575                            full_comment_prefix.clone(),
6576                        ));
6577                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
6578                        suffixes_inserted.push((end_row, comment_suffix.len()));
6579                    } else {
6580                        edits.push((prefix_range, empty_str.clone()));
6581                        edits.push((suffix_range, empty_str.clone()));
6582                    }
6583                } else {
6584                    continue;
6585                }
6586            }
6587
6588            drop(snapshot);
6589            this.buffer.update(cx, |buffer, cx| {
6590                buffer.edit(edits, None, cx);
6591            });
6592
6593            // Adjust selections so that they end before any comment suffixes that
6594            // were inserted.
6595            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
6596            let mut selections = this.selections.all::<Point>(cx);
6597            let snapshot = this.buffer.read(cx).read(cx);
6598            for selection in &mut selections {
6599                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
6600                    match row.cmp(&selection.end.row) {
6601                        Ordering::Less => {
6602                            suffixes_inserted.next();
6603                            continue;
6604                        }
6605                        Ordering::Greater => break,
6606                        Ordering::Equal => {
6607                            if selection.end.column == snapshot.line_len(row) {
6608                                if selection.is_empty() {
6609                                    selection.start.column -= suffix_len as u32;
6610                                }
6611                                selection.end.column -= suffix_len as u32;
6612                            }
6613                            break;
6614                        }
6615                    }
6616                }
6617            }
6618
6619            drop(snapshot);
6620            this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections));
6621
6622            let selections = this.selections.all::<Point>(cx);
6623            let selections_on_single_row = selections.windows(2).all(|selections| {
6624                selections[0].start.row == selections[1].start.row
6625                    && selections[0].end.row == selections[1].end.row
6626                    && selections[0].start.row == selections[0].end.row
6627            });
6628            let selections_selecting = selections
6629                .iter()
6630                .any(|selection| selection.start != selection.end);
6631            let advance_downwards = action.advance_downwards
6632                && selections_on_single_row
6633                && !selections_selecting
6634                && this.mode != EditorMode::SingleLine;
6635
6636            if advance_downwards {
6637                let snapshot = this.buffer.read(cx).snapshot(cx);
6638
6639                this.change_selections(Some(Autoscroll::fit()), cx, |s| {
6640                    s.move_cursors_with(|display_snapshot, display_point, _| {
6641                        let mut point = display_point.to_point(display_snapshot);
6642                        point.row += 1;
6643                        point = snapshot.clip_point(point, Bias::Left);
6644                        let display_point = point.to_display_point(display_snapshot);
6645                        let goal = SelectionGoal::HorizontalPosition(
6646                            display_snapshot
6647                                .x_for_display_point(display_point, &text_layout_details)
6648                                .into(),
6649                        );
6650                        (display_point, goal)
6651                    })
6652                });
6653            }
6654        });
6655    }
6656
6657    pub fn select_larger_syntax_node(
6658        &mut self,
6659        _: &SelectLargerSyntaxNode,
6660        cx: &mut ViewContext<Self>,
6661    ) {
6662        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
6663        let buffer = self.buffer.read(cx).snapshot(cx);
6664        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
6665
6666        let mut stack = mem::take(&mut self.select_larger_syntax_node_stack);
6667        let mut selected_larger_node = false;
6668        let new_selections = old_selections
6669            .iter()
6670            .map(|selection| {
6671                let old_range = selection.start..selection.end;
6672                let mut new_range = old_range.clone();
6673                while let Some(containing_range) =
6674                    buffer.range_for_syntax_ancestor(new_range.clone())
6675                {
6676                    new_range = containing_range;
6677                    if !display_map.intersects_fold(new_range.start)
6678                        && !display_map.intersects_fold(new_range.end)
6679                    {
6680                        break;
6681                    }
6682                }
6683
6684                selected_larger_node |= new_range != old_range;
6685                Selection {
6686                    id: selection.id,
6687                    start: new_range.start,
6688                    end: new_range.end,
6689                    goal: SelectionGoal::None,
6690                    reversed: selection.reversed,
6691                }
6692            })
6693            .collect::<Vec<_>>();
6694
6695        if selected_larger_node {
6696            stack.push(old_selections);
6697            self.change_selections(Some(Autoscroll::fit()), cx, |s| {
6698                s.select(new_selections);
6699            });
6700        }
6701        self.select_larger_syntax_node_stack = stack;
6702    }
6703
6704    pub fn select_smaller_syntax_node(
6705        &mut self,
6706        _: &SelectSmallerSyntaxNode,
6707        cx: &mut ViewContext<Self>,
6708    ) {
6709        let mut stack = mem::take(&mut self.select_larger_syntax_node_stack);
6710        if let Some(selections) = stack.pop() {
6711            self.change_selections(Some(Autoscroll::fit()), cx, |s| {
6712                s.select(selections.to_vec());
6713            });
6714        }
6715        self.select_larger_syntax_node_stack = stack;
6716    }
6717
6718    pub fn move_to_enclosing_bracket(
6719        &mut self,
6720        _: &MoveToEnclosingBracket,
6721        cx: &mut ViewContext<Self>,
6722    ) {
6723        self.change_selections(Some(Autoscroll::fit()), cx, |s| {
6724            s.move_offsets_with(|snapshot, selection| {
6725                let Some(enclosing_bracket_ranges) =
6726                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
6727                else {
6728                    return;
6729                };
6730
6731                let mut best_length = usize::MAX;
6732                let mut best_inside = false;
6733                let mut best_in_bracket_range = false;
6734                let mut best_destination = None;
6735                for (open, close) in enclosing_bracket_ranges {
6736                    let close = close.to_inclusive();
6737                    let length = close.end() - open.start;
6738                    let inside = selection.start >= open.end && selection.end <= *close.start();
6739                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
6740                        || close.contains(&selection.head());
6741
6742                    // If best is next to a bracket and current isn't, skip
6743                    if !in_bracket_range && best_in_bracket_range {
6744                        continue;
6745                    }
6746
6747                    // Prefer smaller lengths unless best is inside and current isn't
6748                    if length > best_length && (best_inside || !inside) {
6749                        continue;
6750                    }
6751
6752                    best_length = length;
6753                    best_inside = inside;
6754                    best_in_bracket_range = in_bracket_range;
6755                    best_destination = Some(
6756                        if close.contains(&selection.start) && close.contains(&selection.end) {
6757                            if inside {
6758                                open.end
6759                            } else {
6760                                open.start
6761                            }
6762                        } else {
6763                            if inside {
6764                                *close.start()
6765                            } else {
6766                                *close.end()
6767                            }
6768                        },
6769                    );
6770                }
6771
6772                if let Some(destination) = best_destination {
6773                    selection.collapse_to(destination, SelectionGoal::None);
6774                }
6775            })
6776        });
6777    }
6778
6779    pub fn undo_selection(&mut self, _: &UndoSelection, cx: &mut ViewContext<Self>) {
6780        self.end_selection(cx);
6781        self.selection_history.mode = SelectionHistoryMode::Undoing;
6782        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
6783            self.change_selections(None, cx, |s| s.select_anchors(entry.selections.to_vec()));
6784            self.select_next_state = entry.select_next_state;
6785            self.select_prev_state = entry.select_prev_state;
6786            self.add_selections_state = entry.add_selections_state;
6787            self.request_autoscroll(Autoscroll::newest(), cx);
6788        }
6789        self.selection_history.mode = SelectionHistoryMode::Normal;
6790    }
6791
6792    pub fn redo_selection(&mut self, _: &RedoSelection, cx: &mut ViewContext<Self>) {
6793        self.end_selection(cx);
6794        self.selection_history.mode = SelectionHistoryMode::Redoing;
6795        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
6796            self.change_selections(None, cx, |s| s.select_anchors(entry.selections.to_vec()));
6797            self.select_next_state = entry.select_next_state;
6798            self.select_prev_state = entry.select_prev_state;
6799            self.add_selections_state = entry.add_selections_state;
6800            self.request_autoscroll(Autoscroll::newest(), cx);
6801        }
6802        self.selection_history.mode = SelectionHistoryMode::Normal;
6803    }
6804
6805    fn go_to_diagnostic(&mut self, _: &GoToDiagnostic, cx: &mut ViewContext<Self>) {
6806        self.go_to_diagnostic_impl(Direction::Next, cx)
6807    }
6808
6809    fn go_to_prev_diagnostic(&mut self, _: &GoToPrevDiagnostic, cx: &mut ViewContext<Self>) {
6810        self.go_to_diagnostic_impl(Direction::Prev, cx)
6811    }
6812
6813    pub fn go_to_diagnostic_impl(&mut self, direction: Direction, cx: &mut ViewContext<Self>) {
6814        let buffer = self.buffer.read(cx).snapshot(cx);
6815        let selection = self.selections.newest::<usize>(cx);
6816
6817        // If there is an active Diagnostic Popover jump to its diagnostic instead.
6818        if direction == Direction::Next {
6819            if let Some(popover) = self.hover_state.diagnostic_popover.as_ref() {
6820                let (group_id, jump_to) = popover.activation_info();
6821                if self.activate_diagnostics(group_id, cx) {
6822                    self.change_selections(Some(Autoscroll::fit()), cx, |s| {
6823                        let mut new_selection = s.newest_anchor().clone();
6824                        new_selection.collapse_to(jump_to, SelectionGoal::None);
6825                        s.select_anchors(vec![new_selection.clone()]);
6826                    });
6827                }
6828                return;
6829            }
6830        }
6831
6832        let mut active_primary_range = self.active_diagnostics.as_ref().map(|active_diagnostics| {
6833            active_diagnostics
6834                .primary_range
6835                .to_offset(&buffer)
6836                .to_inclusive()
6837        });
6838        let mut search_start = if let Some(active_primary_range) = active_primary_range.as_ref() {
6839            if active_primary_range.contains(&selection.head()) {
6840                *active_primary_range.end()
6841            } else {
6842                selection.head()
6843            }
6844        } else {
6845            selection.head()
6846        };
6847
6848        loop {
6849            let mut diagnostics = if direction == Direction::Prev {
6850                buffer.diagnostics_in_range::<_, usize>(0..search_start, true)
6851            } else {
6852                buffer.diagnostics_in_range::<_, usize>(search_start..buffer.len(), false)
6853            };
6854            let group = diagnostics.find_map(|entry| {
6855                if entry.diagnostic.is_primary
6856                    && entry.diagnostic.severity <= DiagnosticSeverity::WARNING
6857                    && !entry.range.is_empty()
6858                    && Some(entry.range.end) != active_primary_range.as_ref().map(|r| *r.end())
6859                    && !entry.range.contains(&search_start)
6860                {
6861                    Some((entry.range, entry.diagnostic.group_id))
6862                } else {
6863                    None
6864                }
6865            });
6866
6867            if let Some((primary_range, group_id)) = group {
6868                if self.activate_diagnostics(group_id, cx) {
6869                    self.change_selections(Some(Autoscroll::fit()), cx, |s| {
6870                        s.select(vec![Selection {
6871                            id: selection.id,
6872                            start: primary_range.start,
6873                            end: primary_range.start,
6874                            reversed: false,
6875                            goal: SelectionGoal::None,
6876                        }]);
6877                    });
6878                }
6879                break;
6880            } else {
6881                // Cycle around to the start of the buffer, potentially moving back to the start of
6882                // the currently active diagnostic.
6883                active_primary_range.take();
6884                if direction == Direction::Prev {
6885                    if search_start == buffer.len() {
6886                        break;
6887                    } else {
6888                        search_start = buffer.len();
6889                    }
6890                } else if search_start == 0 {
6891                    break;
6892                } else {
6893                    search_start = 0;
6894                }
6895            }
6896        }
6897    }
6898
6899    fn go_to_hunk(&mut self, _: &GoToHunk, cx: &mut ViewContext<Self>) {
6900        let snapshot = self
6901            .display_map
6902            .update(cx, |display_map, cx| display_map.snapshot(cx));
6903        let selection = self.selections.newest::<Point>(cx);
6904
6905        if !self.seek_in_direction(
6906            &snapshot,
6907            selection.head(),
6908            false,
6909            snapshot
6910                .buffer_snapshot
6911                .git_diff_hunks_in_range((selection.head().row + 1)..u32::MAX),
6912            cx,
6913        ) {
6914            let wrapped_point = Point::zero();
6915            self.seek_in_direction(
6916                &snapshot,
6917                wrapped_point,
6918                true,
6919                snapshot
6920                    .buffer_snapshot
6921                    .git_diff_hunks_in_range((wrapped_point.row + 1)..u32::MAX),
6922                cx,
6923            );
6924        }
6925    }
6926
6927    fn go_to_prev_hunk(&mut self, _: &GoToPrevHunk, cx: &mut ViewContext<Self>) {
6928        let snapshot = self
6929            .display_map
6930            .update(cx, |display_map, cx| display_map.snapshot(cx));
6931        let selection = self.selections.newest::<Point>(cx);
6932
6933        if !self.seek_in_direction(
6934            &snapshot,
6935            selection.head(),
6936            false,
6937            snapshot
6938                .buffer_snapshot
6939                .git_diff_hunks_in_range_rev(0..selection.head().row),
6940            cx,
6941        ) {
6942            let wrapped_point = snapshot.buffer_snapshot.max_point();
6943            self.seek_in_direction(
6944                &snapshot,
6945                wrapped_point,
6946                true,
6947                snapshot
6948                    .buffer_snapshot
6949                    .git_diff_hunks_in_range_rev(0..wrapped_point.row),
6950                cx,
6951            );
6952        }
6953    }
6954
6955    fn seek_in_direction(
6956        &mut self,
6957        snapshot: &DisplaySnapshot,
6958        initial_point: Point,
6959        is_wrapped: bool,
6960        hunks: impl Iterator<Item = DiffHunk<u32>>,
6961        cx: &mut ViewContext<Editor>,
6962    ) -> bool {
6963        let display_point = initial_point.to_display_point(snapshot);
6964        let mut hunks = hunks
6965            .map(|hunk| diff_hunk_to_display(hunk, &snapshot))
6966            .filter(|hunk| {
6967                if is_wrapped {
6968                    true
6969                } else {
6970                    !hunk.contains_display_row(display_point.row())
6971                }
6972            })
6973            .dedup();
6974
6975        if let Some(hunk) = hunks.next() {
6976            self.change_selections(Some(Autoscroll::fit()), cx, |s| {
6977                let row = hunk.start_display_row();
6978                let point = DisplayPoint::new(row, 0);
6979                s.select_display_ranges([point..point]);
6980            });
6981
6982            true
6983        } else {
6984            false
6985        }
6986    }
6987
6988    pub fn go_to_definition(&mut self, _: &GoToDefinition, cx: &mut ViewContext<Self>) {
6989        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, cx);
6990    }
6991
6992    pub fn go_to_type_definition(&mut self, _: &GoToTypeDefinition, cx: &mut ViewContext<Self>) {
6993        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, cx);
6994    }
6995
6996    pub fn go_to_definition_split(&mut self, _: &GoToDefinitionSplit, cx: &mut ViewContext<Self>) {
6997        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, cx);
6998    }
6999
7000    pub fn go_to_type_definition_split(
7001        &mut self,
7002        _: &GoToTypeDefinitionSplit,
7003        cx: &mut ViewContext<Self>,
7004    ) {
7005        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, cx);
7006    }
7007
7008    fn go_to_definition_of_kind(
7009        &mut self,
7010        kind: GotoDefinitionKind,
7011        split: bool,
7012        cx: &mut ViewContext<Self>,
7013    ) {
7014        let Some(workspace) = self.workspace() else {
7015            return;
7016        };
7017        let buffer = self.buffer.read(cx);
7018        let head = self.selections.newest::<usize>(cx).head();
7019        let (buffer, head) = if let Some(text_anchor) = buffer.text_anchor_for_position(head, cx) {
7020            text_anchor
7021        } else {
7022            return;
7023        };
7024
7025        let project = workspace.read(cx).project().clone();
7026        let definitions = project.update(cx, |project, cx| match kind {
7027            GotoDefinitionKind::Symbol => project.definition(&buffer, head, cx),
7028            GotoDefinitionKind::Type => project.type_definition(&buffer, head, cx),
7029        });
7030
7031        cx.spawn(|editor, mut cx| async move {
7032            let definitions = definitions.await?;
7033            editor.update(&mut cx, |editor, cx| {
7034                editor.navigate_to_definitions(
7035                    definitions
7036                        .into_iter()
7037                        .map(GoToDefinitionLink::Text)
7038                        .collect(),
7039                    split,
7040                    cx,
7041                );
7042            })?;
7043            Ok::<(), anyhow::Error>(())
7044        })
7045        .detach_and_log_err(cx);
7046    }
7047
7048    pub fn navigate_to_definitions(
7049        &mut self,
7050        mut definitions: Vec<GoToDefinitionLink>,
7051        split: bool,
7052        cx: &mut ViewContext<Editor>,
7053    ) {
7054        let Some(workspace) = self.workspace() else {
7055            return;
7056        };
7057        let pane = workspace.read(cx).active_pane().clone();
7058        // If there is one definition, just open it directly
7059        if definitions.len() == 1 {
7060            let definition = definitions.pop().unwrap();
7061            let target_task = match definition {
7062                GoToDefinitionLink::Text(link) => Task::Ready(Some(Ok(Some(link.target)))),
7063                GoToDefinitionLink::InlayHint(lsp_location, server_id) => {
7064                    self.compute_target_location(lsp_location, server_id, cx)
7065                }
7066            };
7067            cx.spawn(|editor, mut cx| async move {
7068                let target = target_task.await.context("target resolution task")?;
7069                if let Some(target) = target {
7070                    editor.update(&mut cx, |editor, cx| {
7071                        let range = target.range.to_offset(target.buffer.read(cx));
7072                        let range = editor.range_for_match(&range);
7073                        if Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref() {
7074                            editor.change_selections(Some(Autoscroll::fit()), cx, |s| {
7075                                s.select_ranges([range]);
7076                            });
7077                        } else {
7078                            cx.window_context().defer(move |cx| {
7079                                let target_editor: View<Self> =
7080                                    workspace.update(cx, |workspace, cx| {
7081                                        if split {
7082                                            workspace.split_project_item(target.buffer.clone(), cx)
7083                                        } else {
7084                                            workspace.open_project_item(target.buffer.clone(), cx)
7085                                        }
7086                                    });
7087                                target_editor.update(cx, |target_editor, cx| {
7088                                    // When selecting a definition in a different buffer, disable the nav history
7089                                    // to avoid creating a history entry at the previous cursor location.
7090                                    pane.update(cx, |pane, _| pane.disable_history());
7091                                    target_editor.change_selections(
7092                                        Some(Autoscroll::fit()),
7093                                        cx,
7094                                        |s| {
7095                                            s.select_ranges([range]);
7096                                        },
7097                                    );
7098                                    pane.update(cx, |pane, _| pane.enable_history());
7099                                });
7100                            });
7101                        }
7102                    })
7103                } else {
7104                    Ok(())
7105                }
7106            })
7107            .detach_and_log_err(cx);
7108        } else if !definitions.is_empty() {
7109            let replica_id = self.replica_id(cx);
7110            cx.spawn(|editor, mut cx| async move {
7111                let (title, location_tasks) = editor
7112                    .update(&mut cx, |editor, cx| {
7113                        let title = definitions
7114                            .iter()
7115                            .find_map(|definition| match definition {
7116                                GoToDefinitionLink::Text(link) => {
7117                                    link.origin.as_ref().map(|origin| {
7118                                        let buffer = origin.buffer.read(cx);
7119                                        format!(
7120                                            "Definitions for {}",
7121                                            buffer
7122                                                .text_for_range(origin.range.clone())
7123                                                .collect::<String>()
7124                                        )
7125                                    })
7126                                }
7127                                GoToDefinitionLink::InlayHint(_, _) => None,
7128                            })
7129                            .unwrap_or("Definitions".to_string());
7130                        let location_tasks = definitions
7131                            .into_iter()
7132                            .map(|definition| match definition {
7133                                GoToDefinitionLink::Text(link) => {
7134                                    Task::Ready(Some(Ok(Some(link.target))))
7135                                }
7136                                GoToDefinitionLink::InlayHint(lsp_location, server_id) => {
7137                                    editor.compute_target_location(lsp_location, server_id, cx)
7138                                }
7139                            })
7140                            .collect::<Vec<_>>();
7141                        (title, location_tasks)
7142                    })
7143                    .context("location tasks preparation")?;
7144
7145                let locations = futures::future::join_all(location_tasks)
7146                    .await
7147                    .into_iter()
7148                    .filter_map(|location| location.transpose())
7149                    .collect::<Result<_>>()
7150                    .context("location tasks")?;
7151                workspace
7152                    .update(&mut cx, |workspace, cx| {
7153                        Self::open_locations_in_multibuffer(
7154                            workspace, locations, replica_id, title, split, cx,
7155                        )
7156                    })
7157                    .ok();
7158
7159                anyhow::Ok(())
7160            })
7161            .detach_and_log_err(cx);
7162        }
7163    }
7164
7165    fn compute_target_location(
7166        &self,
7167        lsp_location: lsp::Location,
7168        server_id: LanguageServerId,
7169        cx: &mut ViewContext<Editor>,
7170    ) -> Task<anyhow::Result<Option<Location>>> {
7171        let Some(project) = self.project.clone() else {
7172            return Task::Ready(Some(Ok(None)));
7173        };
7174
7175        cx.spawn(move |editor, mut cx| async move {
7176            let location_task = editor.update(&mut cx, |editor, cx| {
7177                project.update(cx, |project, cx| {
7178                    let language_server_name =
7179                        editor.buffer.read(cx).as_singleton().and_then(|buffer| {
7180                            project
7181                                .language_server_for_buffer(buffer.read(cx), server_id, cx)
7182                                .map(|(_, lsp_adapter)| {
7183                                    LanguageServerName(Arc::from(lsp_adapter.name()))
7184                                })
7185                        });
7186                    language_server_name.map(|language_server_name| {
7187                        project.open_local_buffer_via_lsp(
7188                            lsp_location.uri.clone(),
7189                            server_id,
7190                            language_server_name,
7191                            cx,
7192                        )
7193                    })
7194                })
7195            })?;
7196            let location = match location_task {
7197                Some(task) => Some({
7198                    let target_buffer_handle = task.await.context("open local buffer")?;
7199                    let range = target_buffer_handle.update(&mut cx, |target_buffer, _| {
7200                        let target_start = target_buffer
7201                            .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
7202                        let target_end = target_buffer
7203                            .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
7204                        target_buffer.anchor_after(target_start)
7205                            ..target_buffer.anchor_before(target_end)
7206                    })?;
7207                    Location {
7208                        buffer: target_buffer_handle,
7209                        range,
7210                    }
7211                }),
7212                None => None,
7213            };
7214            Ok(location)
7215        })
7216    }
7217
7218    pub fn find_all_references(
7219        &mut self,
7220        _: &FindAllReferences,
7221        cx: &mut ViewContext<Self>,
7222    ) -> Option<Task<Result<()>>> {
7223        let buffer = self.buffer.read(cx);
7224        let head = self.selections.newest::<usize>(cx).head();
7225        let (buffer, head) = buffer.text_anchor_for_position(head, cx)?;
7226        let replica_id = self.replica_id(cx);
7227
7228        let workspace = self.workspace()?;
7229        let project = workspace.read(cx).project().clone();
7230        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
7231        Some(cx.spawn(|_, mut cx| async move {
7232            let locations = references.await?;
7233            if locations.is_empty() {
7234                return Ok(());
7235            }
7236
7237            workspace.update(&mut cx, |workspace, cx| {
7238                let title = locations
7239                    .first()
7240                    .as_ref()
7241                    .map(|location| {
7242                        let buffer = location.buffer.read(cx);
7243                        format!(
7244                            "References to `{}`",
7245                            buffer
7246                                .text_for_range(location.range.clone())
7247                                .collect::<String>()
7248                        )
7249                    })
7250                    .unwrap();
7251                Self::open_locations_in_multibuffer(
7252                    workspace, locations, replica_id, title, false, cx,
7253                );
7254            })?;
7255
7256            Ok(())
7257        }))
7258    }
7259
7260    /// Opens a multibuffer with the given project locations in it
7261    pub fn open_locations_in_multibuffer(
7262        workspace: &mut Workspace,
7263        mut locations: Vec<Location>,
7264        replica_id: ReplicaId,
7265        title: String,
7266        split: bool,
7267        cx: &mut ViewContext<Workspace>,
7268    ) {
7269        // If there are multiple definitions, open them in a multibuffer
7270        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
7271        let mut locations = locations.into_iter().peekable();
7272        let mut ranges_to_highlight = Vec::new();
7273        let capability = workspace.project().read(cx).capability();
7274
7275        let excerpt_buffer = cx.new_model(|cx| {
7276            let mut multibuffer = MultiBuffer::new(replica_id, capability);
7277            while let Some(location) = locations.next() {
7278                let buffer = location.buffer.read(cx);
7279                let mut ranges_for_buffer = Vec::new();
7280                let range = location.range.to_offset(buffer);
7281                ranges_for_buffer.push(range.clone());
7282
7283                while let Some(next_location) = locations.peek() {
7284                    if next_location.buffer == location.buffer {
7285                        ranges_for_buffer.push(next_location.range.to_offset(buffer));
7286                        locations.next();
7287                    } else {
7288                        break;
7289                    }
7290                }
7291
7292                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
7293                ranges_to_highlight.extend(multibuffer.push_excerpts_with_context_lines(
7294                    location.buffer.clone(),
7295                    ranges_for_buffer,
7296                    1,
7297                    cx,
7298                ))
7299            }
7300
7301            multibuffer.with_title(title)
7302        });
7303
7304        let editor = cx.new_view(|cx| {
7305            Editor::for_multibuffer(excerpt_buffer, Some(workspace.project().clone()), cx)
7306        });
7307        editor.update(cx, |editor, cx| {
7308            editor.highlight_background::<Self>(
7309                ranges_to_highlight,
7310                |theme| theme.editor_highlighted_line_background,
7311                cx,
7312            );
7313        });
7314        if split {
7315            workspace.split_item(SplitDirection::Right, Box::new(editor), cx);
7316        } else {
7317            workspace.add_item(Box::new(editor), cx);
7318        }
7319    }
7320
7321    pub fn rename(&mut self, _: &Rename, cx: &mut ViewContext<Self>) -> Option<Task<Result<()>>> {
7322        use language::ToOffset as _;
7323
7324        let project = self.project.clone()?;
7325        let selection = self.selections.newest_anchor().clone();
7326        let (cursor_buffer, cursor_buffer_position) = self
7327            .buffer
7328            .read(cx)
7329            .text_anchor_for_position(selection.head(), cx)?;
7330        let (tail_buffer, _) = self
7331            .buffer
7332            .read(cx)
7333            .text_anchor_for_position(selection.tail(), cx)?;
7334        if tail_buffer != cursor_buffer {
7335            return None;
7336        }
7337
7338        let snapshot = cursor_buffer.read(cx).snapshot();
7339        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
7340        let prepare_rename = project.update(cx, |project, cx| {
7341            project.prepare_rename(cursor_buffer, cursor_buffer_offset, cx)
7342        });
7343
7344        Some(cx.spawn(|this, mut cx| async move {
7345            let rename_range = if let Some(range) = prepare_rename.await? {
7346                Some(range)
7347            } else {
7348                this.update(&mut cx, |this, cx| {
7349                    let buffer = this.buffer.read(cx).snapshot(cx);
7350                    let mut buffer_highlights = this
7351                        .document_highlights_for_position(selection.head(), &buffer)
7352                        .filter(|highlight| {
7353                            highlight.start.excerpt_id == selection.head().excerpt_id
7354                                && highlight.end.excerpt_id == selection.head().excerpt_id
7355                        });
7356                    buffer_highlights
7357                        .next()
7358                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
7359                })?
7360            };
7361            if let Some(rename_range) = rename_range {
7362                let rename_buffer_range = rename_range.to_offset(&snapshot);
7363                let cursor_offset_in_rename_range =
7364                    cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
7365
7366                this.update(&mut cx, |this, cx| {
7367                    this.take_rename(false, cx);
7368                    let buffer = this.buffer.read(cx).read(cx);
7369                    let cursor_offset = selection.head().to_offset(&buffer);
7370                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
7371                    let rename_end = rename_start + rename_buffer_range.len();
7372                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
7373                    let mut old_highlight_id = None;
7374                    let old_name: Arc<str> = buffer
7375                        .chunks(rename_start..rename_end, true)
7376                        .map(|chunk| {
7377                            if old_highlight_id.is_none() {
7378                                old_highlight_id = chunk.syntax_highlight_id;
7379                            }
7380                            chunk.text
7381                        })
7382                        .collect::<String>()
7383                        .into();
7384
7385                    drop(buffer);
7386
7387                    // Position the selection in the rename editor so that it matches the current selection.
7388                    this.show_local_selections = false;
7389                    let rename_editor = cx.new_view(|cx| {
7390                        let mut editor = Editor::single_line(cx);
7391                        editor.buffer.update(cx, |buffer, cx| {
7392                            buffer.edit([(0..0, old_name.clone())], None, cx)
7393                        });
7394                        editor.select_all(&SelectAll, cx);
7395                        editor
7396                    });
7397
7398                    let ranges = this
7399                        .clear_background_highlights::<DocumentHighlightWrite>(cx)
7400                        .into_iter()
7401                        .flat_map(|(_, ranges)| ranges.into_iter())
7402                        .chain(
7403                            this.clear_background_highlights::<DocumentHighlightRead>(cx)
7404                                .into_iter()
7405                                .flat_map(|(_, ranges)| ranges.into_iter()),
7406                        )
7407                        .collect();
7408
7409                    this.highlight_text::<Rename>(
7410                        ranges,
7411                        HighlightStyle {
7412                            fade_out: Some(0.6),
7413                            ..Default::default()
7414                        },
7415                        cx,
7416                    );
7417                    let rename_focus_handle = rename_editor.focus_handle(cx);
7418                    cx.focus(&rename_focus_handle);
7419                    let block_id = this.insert_blocks(
7420                        [BlockProperties {
7421                            style: BlockStyle::Flex,
7422                            position: range.start.clone(),
7423                            height: 1,
7424                            render: Arc::new({
7425                                let rename_editor = rename_editor.clone();
7426                                move |cx: &mut BlockContext| {
7427                                    let mut text_style = cx.editor_style.text.clone();
7428                                    if let Some(highlight_style) = old_highlight_id
7429                                        .and_then(|h| h.style(&cx.editor_style.syntax))
7430                                    {
7431                                        text_style = text_style.highlight(highlight_style);
7432                                    }
7433                                    div()
7434                                        .pl(cx.anchor_x)
7435                                        .child(EditorElement::new(
7436                                            &rename_editor,
7437                                            EditorStyle {
7438                                                background: cx.theme().system().transparent,
7439                                                local_player: cx.editor_style.local_player,
7440                                                text: text_style,
7441                                                scrollbar_width: cx.editor_style.scrollbar_width,
7442                                                syntax: cx.editor_style.syntax.clone(),
7443                                                status: cx.editor_style.status.clone(),
7444                                                inlays_style: HighlightStyle {
7445                                                    color: Some(cx.theme().status().hint),
7446                                                    font_weight: Some(FontWeight::BOLD),
7447                                                    ..HighlightStyle::default()
7448                                                },
7449                                                suggestions_style: HighlightStyle {
7450                                                    color: Some(cx.theme().status().predictive),
7451                                                    ..HighlightStyle::default()
7452                                                },
7453                                            },
7454                                        ))
7455                                        .into_any_element()
7456                                }
7457                            }),
7458                            disposition: BlockDisposition::Below,
7459                        }],
7460                        Some(Autoscroll::fit()),
7461                        cx,
7462                    )[0];
7463                    this.pending_rename = Some(RenameState {
7464                        range,
7465                        old_name,
7466                        editor: rename_editor,
7467                        block_id,
7468                    });
7469                })?;
7470            }
7471
7472            Ok(())
7473        }))
7474    }
7475
7476    pub fn confirm_rename(
7477        &mut self,
7478        _: &ConfirmRename,
7479        cx: &mut ViewContext<Self>,
7480    ) -> Option<Task<Result<()>>> {
7481        let rename = self.take_rename(false, cx)?;
7482        let workspace = self.workspace()?;
7483        let (start_buffer, start) = self
7484            .buffer
7485            .read(cx)
7486            .text_anchor_for_position(rename.range.start.clone(), cx)?;
7487        let (end_buffer, end) = self
7488            .buffer
7489            .read(cx)
7490            .text_anchor_for_position(rename.range.end.clone(), cx)?;
7491        if start_buffer != end_buffer {
7492            return None;
7493        }
7494
7495        let buffer = start_buffer;
7496        let range = start..end;
7497        let old_name = rename.old_name;
7498        let new_name = rename.editor.read(cx).text(cx);
7499
7500        let rename = workspace
7501            .read(cx)
7502            .project()
7503            .clone()
7504            .update(cx, |project, cx| {
7505                project.perform_rename(buffer.clone(), range.start, new_name.clone(), true, cx)
7506            });
7507        let workspace = workspace.downgrade();
7508
7509        Some(cx.spawn(|editor, mut cx| async move {
7510            let project_transaction = rename.await?;
7511            Self::open_project_transaction(
7512                &editor,
7513                workspace,
7514                project_transaction,
7515                format!("Rename: {}{}", old_name, new_name),
7516                cx.clone(),
7517            )
7518            .await?;
7519
7520            editor.update(&mut cx, |editor, cx| {
7521                editor.refresh_document_highlights(cx);
7522            })?;
7523            Ok(())
7524        }))
7525    }
7526
7527    fn take_rename(
7528        &mut self,
7529        moving_cursor: bool,
7530        cx: &mut ViewContext<Self>,
7531    ) -> Option<RenameState> {
7532        let rename = self.pending_rename.take()?;
7533        if rename.editor.focus_handle(cx).is_focused(cx) {
7534            cx.focus(&self.focus_handle);
7535        }
7536
7537        self.remove_blocks(
7538            [rename.block_id].into_iter().collect(),
7539            Some(Autoscroll::fit()),
7540            cx,
7541        );
7542        self.clear_highlights::<Rename>(cx);
7543        self.show_local_selections = true;
7544
7545        if moving_cursor {
7546            let rename_editor = rename.editor.read(cx);
7547            let cursor_in_rename_editor = rename_editor.selections.newest::<usize>(cx).head();
7548
7549            // Update the selection to match the position of the selection inside
7550            // the rename editor.
7551            let snapshot = self.buffer.read(cx).read(cx);
7552            let rename_range = rename.range.to_offset(&snapshot);
7553            let cursor_in_editor = snapshot
7554                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
7555                .min(rename_range.end);
7556            drop(snapshot);
7557
7558            self.change_selections(None, cx, |s| {
7559                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
7560            });
7561        } else {
7562            self.refresh_document_highlights(cx);
7563        }
7564
7565        Some(rename)
7566    }
7567
7568    #[cfg(any(test, feature = "test-support"))]
7569    pub fn pending_rename(&self) -> Option<&RenameState> {
7570        self.pending_rename.as_ref()
7571    }
7572
7573    fn format(&mut self, _: &Format, cx: &mut ViewContext<Self>) -> Option<Task<Result<()>>> {
7574        let project = match &self.project {
7575            Some(project) => project.clone(),
7576            None => return None,
7577        };
7578
7579        Some(self.perform_format(project, FormatTrigger::Manual, cx))
7580    }
7581
7582    fn perform_format(
7583        &mut self,
7584        project: Model<Project>,
7585        trigger: FormatTrigger,
7586        cx: &mut ViewContext<Self>,
7587    ) -> Task<Result<()>> {
7588        let buffer = self.buffer().clone();
7589        let buffers = buffer.read(cx).all_buffers();
7590
7591        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
7592        let format = project.update(cx, |project, cx| project.format(buffers, true, trigger, cx));
7593
7594        cx.spawn(|_, mut cx| async move {
7595            let transaction = futures::select_biased! {
7596                _ = timeout => {
7597                    log::warn!("timed out waiting for formatting");
7598                    None
7599                }
7600                transaction = format.log_err().fuse() => transaction,
7601            };
7602
7603            buffer
7604                .update(&mut cx, |buffer, cx| {
7605                    if let Some(transaction) = transaction {
7606                        if !buffer.is_singleton() {
7607                            buffer.push_transaction(&transaction.0, cx);
7608                        }
7609                    }
7610
7611                    cx.notify();
7612                })
7613                .ok();
7614
7615            Ok(())
7616        })
7617    }
7618
7619    fn restart_language_server(&mut self, _: &RestartLanguageServer, cx: &mut ViewContext<Self>) {
7620        if let Some(project) = self.project.clone() {
7621            self.buffer.update(cx, |multi_buffer, cx| {
7622                project.update(cx, |project, cx| {
7623                    project.restart_language_servers_for_buffers(multi_buffer.all_buffers(), cx);
7624                });
7625            })
7626        }
7627    }
7628
7629    fn show_character_palette(&mut self, _: &ShowCharacterPalette, cx: &mut ViewContext<Self>) {
7630        cx.show_character_palette();
7631    }
7632
7633    fn refresh_active_diagnostics(&mut self, cx: &mut ViewContext<Editor>) {
7634        if let Some(active_diagnostics) = self.active_diagnostics.as_mut() {
7635            let buffer = self.buffer.read(cx).snapshot(cx);
7636            let primary_range_start = active_diagnostics.primary_range.start.to_offset(&buffer);
7637            let is_valid = buffer
7638                .diagnostics_in_range::<_, usize>(active_diagnostics.primary_range.clone(), false)
7639                .any(|entry| {
7640                    entry.diagnostic.is_primary
7641                        && !entry.range.is_empty()
7642                        && entry.range.start == primary_range_start
7643                        && entry.diagnostic.message == active_diagnostics.primary_message
7644                });
7645
7646            if is_valid != active_diagnostics.is_valid {
7647                active_diagnostics.is_valid = is_valid;
7648                let mut new_styles = HashMap::default();
7649                for (block_id, diagnostic) in &active_diagnostics.blocks {
7650                    new_styles.insert(
7651                        *block_id,
7652                        diagnostic_block_renderer(diagnostic.clone(), is_valid),
7653                    );
7654                }
7655                self.display_map
7656                    .update(cx, |display_map, _| display_map.replace_blocks(new_styles));
7657            }
7658        }
7659    }
7660
7661    fn activate_diagnostics(&mut self, group_id: usize, cx: &mut ViewContext<Self>) -> bool {
7662        self.dismiss_diagnostics(cx);
7663        self.active_diagnostics = self.display_map.update(cx, |display_map, cx| {
7664            let buffer = self.buffer.read(cx).snapshot(cx);
7665
7666            let mut primary_range = None;
7667            let mut primary_message = None;
7668            let mut group_end = Point::zero();
7669            let diagnostic_group = buffer
7670                .diagnostic_group::<Point>(group_id)
7671                .map(|entry| {
7672                    if entry.range.end > group_end {
7673                        group_end = entry.range.end;
7674                    }
7675                    if entry.diagnostic.is_primary {
7676                        primary_range = Some(entry.range.clone());
7677                        primary_message = Some(entry.diagnostic.message.clone());
7678                    }
7679                    entry
7680                })
7681                .collect::<Vec<_>>();
7682            let primary_range = primary_range?;
7683            let primary_message = primary_message?;
7684            let primary_range =
7685                buffer.anchor_after(primary_range.start)..buffer.anchor_before(primary_range.end);
7686
7687            let blocks = display_map
7688                .insert_blocks(
7689                    diagnostic_group.iter().map(|entry| {
7690                        let diagnostic = entry.diagnostic.clone();
7691                        let message_height = diagnostic.message.lines().count() as u8;
7692                        BlockProperties {
7693                            style: BlockStyle::Fixed,
7694                            position: buffer.anchor_after(entry.range.start),
7695                            height: message_height,
7696                            render: diagnostic_block_renderer(diagnostic, true),
7697                            disposition: BlockDisposition::Below,
7698                        }
7699                    }),
7700                    cx,
7701                )
7702                .into_iter()
7703                .zip(diagnostic_group.into_iter().map(|entry| entry.diagnostic))
7704                .collect();
7705
7706            Some(ActiveDiagnosticGroup {
7707                primary_range,
7708                primary_message,
7709                blocks,
7710                is_valid: true,
7711            })
7712        });
7713        self.active_diagnostics.is_some()
7714    }
7715
7716    fn dismiss_diagnostics(&mut self, cx: &mut ViewContext<Self>) {
7717        if let Some(active_diagnostic_group) = self.active_diagnostics.take() {
7718            self.display_map.update(cx, |display_map, cx| {
7719                display_map.remove_blocks(active_diagnostic_group.blocks.into_keys().collect(), cx);
7720            });
7721            cx.notify();
7722        }
7723    }
7724
7725    pub fn set_selections_from_remote(
7726        &mut self,
7727        selections: Vec<Selection<Anchor>>,
7728        pending_selection: Option<Selection<Anchor>>,
7729        cx: &mut ViewContext<Self>,
7730    ) {
7731        let old_cursor_position = self.selections.newest_anchor().head();
7732        self.selections.change_with(cx, |s| {
7733            s.select_anchors(selections);
7734            if let Some(pending_selection) = pending_selection {
7735                s.set_pending(pending_selection, SelectMode::Character);
7736            } else {
7737                s.clear_pending();
7738            }
7739        });
7740        self.selections_did_change(false, &old_cursor_position, cx);
7741    }
7742
7743    fn push_to_selection_history(&mut self) {
7744        self.selection_history.push(SelectionHistoryEntry {
7745            selections: self.selections.disjoint_anchors(),
7746            select_next_state: self.select_next_state.clone(),
7747            select_prev_state: self.select_prev_state.clone(),
7748            add_selections_state: self.add_selections_state.clone(),
7749        });
7750    }
7751
7752    pub fn transact(
7753        &mut self,
7754        cx: &mut ViewContext<Self>,
7755        update: impl FnOnce(&mut Self, &mut ViewContext<Self>),
7756    ) -> Option<TransactionId> {
7757        self.start_transaction_at(Instant::now(), cx);
7758        update(self, cx);
7759        self.end_transaction_at(Instant::now(), cx)
7760    }
7761
7762    fn start_transaction_at(&mut self, now: Instant, cx: &mut ViewContext<Self>) {
7763        self.end_selection(cx);
7764        if let Some(tx_id) = self
7765            .buffer
7766            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
7767        {
7768            self.selection_history
7769                .insert_transaction(tx_id, self.selections.disjoint_anchors());
7770        }
7771    }
7772
7773    fn end_transaction_at(
7774        &mut self,
7775        now: Instant,
7776        cx: &mut ViewContext<Self>,
7777    ) -> Option<TransactionId> {
7778        if let Some(tx_id) = self
7779            .buffer
7780            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
7781        {
7782            if let Some((_, end_selections)) = self.selection_history.transaction_mut(tx_id) {
7783                *end_selections = Some(self.selections.disjoint_anchors());
7784            } else {
7785                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
7786            }
7787
7788            cx.emit(EditorEvent::Edited);
7789            Some(tx_id)
7790        } else {
7791            None
7792        }
7793    }
7794
7795    pub fn fold(&mut self, _: &actions::Fold, cx: &mut ViewContext<Self>) {
7796        let mut fold_ranges = Vec::new();
7797
7798        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
7799
7800        let selections = self.selections.all_adjusted(cx);
7801        for selection in selections {
7802            let range = selection.range().sorted();
7803            let buffer_start_row = range.start.row;
7804
7805            for row in (0..=range.end.row).rev() {
7806                let fold_range = display_map.foldable_range(row);
7807
7808                if let Some(fold_range) = fold_range {
7809                    if fold_range.end.row >= buffer_start_row {
7810                        fold_ranges.push(fold_range);
7811                        if row <= range.start.row {
7812                            break;
7813                        }
7814                    }
7815                }
7816            }
7817        }
7818
7819        self.fold_ranges(fold_ranges, true, cx);
7820    }
7821
7822    pub fn fold_at(&mut self, fold_at: &FoldAt, cx: &mut ViewContext<Self>) {
7823        let buffer_row = fold_at.buffer_row;
7824        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
7825
7826        if let Some(fold_range) = display_map.foldable_range(buffer_row) {
7827            let autoscroll = self
7828                .selections
7829                .all::<Point>(cx)
7830                .iter()
7831                .any(|selection| fold_range.overlaps(&selection.range()));
7832
7833            self.fold_ranges(std::iter::once(fold_range), autoscroll, cx);
7834        }
7835    }
7836
7837    pub fn unfold_lines(&mut self, _: &UnfoldLines, cx: &mut ViewContext<Self>) {
7838        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
7839        let buffer = &display_map.buffer_snapshot;
7840        let selections = self.selections.all::<Point>(cx);
7841        let ranges = selections
7842            .iter()
7843            .map(|s| {
7844                let range = s.display_range(&display_map).sorted();
7845                let mut start = range.start.to_point(&display_map);
7846                let mut end = range.end.to_point(&display_map);
7847                start.column = 0;
7848                end.column = buffer.line_len(end.row);
7849                start..end
7850            })
7851            .collect::<Vec<_>>();
7852
7853        self.unfold_ranges(ranges, true, true, cx);
7854    }
7855
7856    pub fn unfold_at(&mut self, unfold_at: &UnfoldAt, cx: &mut ViewContext<Self>) {
7857        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
7858
7859        let intersection_range = Point::new(unfold_at.buffer_row, 0)
7860            ..Point::new(
7861                unfold_at.buffer_row,
7862                display_map.buffer_snapshot.line_len(unfold_at.buffer_row),
7863            );
7864
7865        let autoscroll = self
7866            .selections
7867            .all::<Point>(cx)
7868            .iter()
7869            .any(|selection| selection.range().overlaps(&intersection_range));
7870
7871        self.unfold_ranges(std::iter::once(intersection_range), true, autoscroll, cx)
7872    }
7873
7874    pub fn fold_selected_ranges(&mut self, _: &FoldSelectedRanges, cx: &mut ViewContext<Self>) {
7875        let selections = self.selections.all::<Point>(cx);
7876        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
7877        let line_mode = self.selections.line_mode;
7878        let ranges = selections.into_iter().map(|s| {
7879            if line_mode {
7880                let start = Point::new(s.start.row, 0);
7881                let end = Point::new(s.end.row, display_map.buffer_snapshot.line_len(s.end.row));
7882                start..end
7883            } else {
7884                s.start..s.end
7885            }
7886        });
7887        self.fold_ranges(ranges, true, cx);
7888    }
7889
7890    pub fn fold_ranges<T: ToOffset + Clone>(
7891        &mut self,
7892        ranges: impl IntoIterator<Item = Range<T>>,
7893        auto_scroll: bool,
7894        cx: &mut ViewContext<Self>,
7895    ) {
7896        let mut ranges = ranges.into_iter().peekable();
7897        if ranges.peek().is_some() {
7898            self.display_map.update(cx, |map, cx| map.fold(ranges, cx));
7899
7900            if auto_scroll {
7901                self.request_autoscroll(Autoscroll::fit(), cx);
7902            }
7903
7904            cx.notify();
7905        }
7906    }
7907
7908    pub fn unfold_ranges<T: ToOffset + Clone>(
7909        &mut self,
7910        ranges: impl IntoIterator<Item = Range<T>>,
7911        inclusive: bool,
7912        auto_scroll: bool,
7913        cx: &mut ViewContext<Self>,
7914    ) {
7915        let mut ranges = ranges.into_iter().peekable();
7916        if ranges.peek().is_some() {
7917            self.display_map
7918                .update(cx, |map, cx| map.unfold(ranges, inclusive, cx));
7919            if auto_scroll {
7920                self.request_autoscroll(Autoscroll::fit(), cx);
7921            }
7922
7923            cx.notify();
7924        }
7925    }
7926
7927    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut ViewContext<Self>) {
7928        if hovered != self.gutter_hovered {
7929            self.gutter_hovered = hovered;
7930            cx.notify();
7931        }
7932    }
7933
7934    pub fn insert_blocks(
7935        &mut self,
7936        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
7937        autoscroll: Option<Autoscroll>,
7938        cx: &mut ViewContext<Self>,
7939    ) -> Vec<BlockId> {
7940        let blocks = self
7941            .display_map
7942            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
7943        if let Some(autoscroll) = autoscroll {
7944            self.request_autoscroll(autoscroll, cx);
7945        }
7946        blocks
7947    }
7948
7949    pub fn replace_blocks(
7950        &mut self,
7951        blocks: HashMap<BlockId, RenderBlock>,
7952        autoscroll: Option<Autoscroll>,
7953        cx: &mut ViewContext<Self>,
7954    ) {
7955        self.display_map
7956            .update(cx, |display_map, _| display_map.replace_blocks(blocks));
7957        if let Some(autoscroll) = autoscroll {
7958            self.request_autoscroll(autoscroll, cx);
7959        }
7960    }
7961
7962    pub fn remove_blocks(
7963        &mut self,
7964        block_ids: HashSet<BlockId>,
7965        autoscroll: Option<Autoscroll>,
7966        cx: &mut ViewContext<Self>,
7967    ) {
7968        self.display_map.update(cx, |display_map, cx| {
7969            display_map.remove_blocks(block_ids, cx)
7970        });
7971        if let Some(autoscroll) = autoscroll {
7972            self.request_autoscroll(autoscroll, cx);
7973        }
7974    }
7975
7976    pub fn longest_row(&self, cx: &mut AppContext) -> u32 {
7977        self.display_map
7978            .update(cx, |map, cx| map.snapshot(cx))
7979            .longest_row()
7980    }
7981
7982    pub fn max_point(&self, cx: &mut AppContext) -> DisplayPoint {
7983        self.display_map
7984            .update(cx, |map, cx| map.snapshot(cx))
7985            .max_point()
7986    }
7987
7988    pub fn text(&self, cx: &AppContext) -> String {
7989        self.buffer.read(cx).read(cx).text()
7990    }
7991
7992    pub fn text_option(&self, cx: &AppContext) -> Option<String> {
7993        let text = self.text(cx);
7994        let text = text.trim();
7995
7996        if text.is_empty() {
7997            return None;
7998        }
7999
8000        Some(text.to_string())
8001    }
8002
8003    pub fn set_text(&mut self, text: impl Into<Arc<str>>, cx: &mut ViewContext<Self>) {
8004        self.transact(cx, |this, cx| {
8005            this.buffer
8006                .read(cx)
8007                .as_singleton()
8008                .expect("you can only call set_text on editors for singleton buffers")
8009                .update(cx, |buffer, cx| buffer.set_text(text, cx));
8010        });
8011    }
8012
8013    pub fn display_text(&self, cx: &mut AppContext) -> String {
8014        self.display_map
8015            .update(cx, |map, cx| map.snapshot(cx))
8016            .text()
8017    }
8018
8019    pub fn wrap_guides(&self, cx: &AppContext) -> SmallVec<[(usize, bool); 2]> {
8020        let mut wrap_guides = smallvec::smallvec![];
8021
8022        if self.show_wrap_guides == Some(false) {
8023            return wrap_guides;
8024        }
8025
8026        let settings = self.buffer.read(cx).settings_at(0, cx);
8027        if settings.show_wrap_guides {
8028            if let SoftWrap::Column(soft_wrap) = self.soft_wrap_mode(cx) {
8029                wrap_guides.push((soft_wrap as usize, true));
8030            }
8031            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
8032        }
8033
8034        wrap_guides
8035    }
8036
8037    pub fn soft_wrap_mode(&self, cx: &AppContext) -> SoftWrap {
8038        let settings = self.buffer.read(cx).settings_at(0, cx);
8039        let mode = self
8040            .soft_wrap_mode_override
8041            .unwrap_or_else(|| settings.soft_wrap);
8042        match mode {
8043            language_settings::SoftWrap::None => SoftWrap::None,
8044            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
8045            language_settings::SoftWrap::PreferredLineLength => {
8046                SoftWrap::Column(settings.preferred_line_length)
8047            }
8048        }
8049    }
8050
8051    pub fn set_soft_wrap_mode(
8052        &mut self,
8053        mode: language_settings::SoftWrap,
8054        cx: &mut ViewContext<Self>,
8055    ) {
8056        self.soft_wrap_mode_override = Some(mode);
8057        cx.notify();
8058    }
8059
8060    pub fn set_style(&mut self, style: EditorStyle, cx: &mut ViewContext<Self>) {
8061        let rem_size = cx.rem_size();
8062        self.display_map.update(cx, |map, cx| {
8063            map.set_font(
8064                style.text.font(),
8065                style.text.font_size.to_pixels(rem_size),
8066                cx,
8067            )
8068        });
8069        self.style = Some(style);
8070    }
8071
8072    #[cfg(any(test, feature = "test-support"))]
8073    pub fn style(&self) -> Option<&EditorStyle> {
8074        self.style.as_ref()
8075    }
8076
8077    // Called by the element. This method is not designed to be called outside of the editor
8078    // element's layout code because it does not notify when rewrapping is computed synchronously.
8079    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut AppContext) -> bool {
8080        self.display_map
8081            .update(cx, |map, cx| map.set_wrap_width(width, cx))
8082    }
8083
8084    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, cx: &mut ViewContext<Self>) {
8085        if self.soft_wrap_mode_override.is_some() {
8086            self.soft_wrap_mode_override.take();
8087        } else {
8088            let soft_wrap = match self.soft_wrap_mode(cx) {
8089                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
8090                SoftWrap::EditorWidth | SoftWrap::Column(_) => language_settings::SoftWrap::None,
8091            };
8092            self.soft_wrap_mode_override = Some(soft_wrap);
8093        }
8094        cx.notify();
8095    }
8096
8097    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut ViewContext<Self>) {
8098        self.show_gutter = show_gutter;
8099        cx.notify();
8100    }
8101
8102    pub fn set_show_wrap_guides(&mut self, show_gutter: bool, cx: &mut ViewContext<Self>) {
8103        self.show_wrap_guides = Some(show_gutter);
8104        cx.notify();
8105    }
8106
8107    pub fn reveal_in_finder(&mut self, _: &RevealInFinder, cx: &mut ViewContext<Self>) {
8108        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
8109            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
8110                cx.reveal_path(&file.abs_path(cx));
8111            }
8112        }
8113    }
8114
8115    pub fn copy_path(&mut self, _: &CopyPath, cx: &mut ViewContext<Self>) {
8116        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
8117            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
8118                if let Some(path) = file.abs_path(cx).to_str() {
8119                    cx.write_to_clipboard(ClipboardItem::new(path.to_string()));
8120                }
8121            }
8122        }
8123    }
8124
8125    pub fn copy_relative_path(&mut self, _: &CopyRelativePath, cx: &mut ViewContext<Self>) {
8126        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
8127            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
8128                if let Some(path) = file.path().to_str() {
8129                    cx.write_to_clipboard(ClipboardItem::new(path.to_string()));
8130                }
8131            }
8132        }
8133    }
8134
8135    pub fn highlight_rows(&mut self, rows: Option<Range<u32>>) {
8136        self.highlighted_rows = rows;
8137    }
8138
8139    pub fn highlighted_rows(&self) -> Option<Range<u32>> {
8140        self.highlighted_rows.clone()
8141    }
8142
8143    pub fn highlight_background<T: 'static>(
8144        &mut self,
8145        ranges: Vec<Range<Anchor>>,
8146        color_fetcher: fn(&ThemeColors) -> Hsla,
8147        cx: &mut ViewContext<Self>,
8148    ) {
8149        self.background_highlights
8150            .insert(TypeId::of::<T>(), (color_fetcher, ranges));
8151        cx.notify();
8152    }
8153
8154    pub(crate) fn highlight_inlay_background<T: 'static>(
8155        &mut self,
8156        ranges: Vec<InlayHighlight>,
8157        color_fetcher: fn(&ThemeColors) -> Hsla,
8158        cx: &mut ViewContext<Self>,
8159    ) {
8160        // TODO: no actual highlights happen for inlays currently, find a way to do that
8161        self.inlay_background_highlights
8162            .insert(Some(TypeId::of::<T>()), (color_fetcher, ranges));
8163        cx.notify();
8164    }
8165
8166    pub fn clear_background_highlights<T: 'static>(
8167        &mut self,
8168        cx: &mut ViewContext<Self>,
8169    ) -> Option<BackgroundHighlight> {
8170        let text_highlights = self.background_highlights.remove(&TypeId::of::<T>());
8171        let inlay_highlights = self
8172            .inlay_background_highlights
8173            .remove(&Some(TypeId::of::<T>()));
8174        if text_highlights.is_some() || inlay_highlights.is_some() {
8175            cx.notify();
8176        }
8177        text_highlights
8178    }
8179
8180    #[cfg(feature = "test-support")]
8181    pub fn all_text_background_highlights(
8182        &mut self,
8183        cx: &mut ViewContext<Self>,
8184    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
8185        let snapshot = self.snapshot(cx);
8186        let buffer = &snapshot.buffer_snapshot;
8187        let start = buffer.anchor_before(0);
8188        let end = buffer.anchor_after(buffer.len());
8189        let theme = cx.theme().colors();
8190        self.background_highlights_in_range(start..end, &snapshot, theme)
8191    }
8192
8193    fn document_highlights_for_position<'a>(
8194        &'a self,
8195        position: Anchor,
8196        buffer: &'a MultiBufferSnapshot,
8197    ) -> impl 'a + Iterator<Item = &Range<Anchor>> {
8198        let read_highlights = self
8199            .background_highlights
8200            .get(&TypeId::of::<DocumentHighlightRead>())
8201            .map(|h| &h.1);
8202        let write_highlights = self
8203            .background_highlights
8204            .get(&TypeId::of::<DocumentHighlightWrite>())
8205            .map(|h| &h.1);
8206        let left_position = position.bias_left(buffer);
8207        let right_position = position.bias_right(buffer);
8208        read_highlights
8209            .into_iter()
8210            .chain(write_highlights)
8211            .flat_map(move |ranges| {
8212                let start_ix = match ranges.binary_search_by(|probe| {
8213                    let cmp = probe.end.cmp(&left_position, buffer);
8214                    if cmp.is_ge() {
8215                        Ordering::Greater
8216                    } else {
8217                        Ordering::Less
8218                    }
8219                }) {
8220                    Ok(i) | Err(i) => i,
8221                };
8222
8223                let right_position = right_position.clone();
8224                ranges[start_ix..]
8225                    .iter()
8226                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
8227            })
8228    }
8229
8230    pub fn has_background_highlights<T: 'static>(&self) -> bool {
8231        self.background_highlights
8232            .get(&TypeId::of::<T>())
8233            .map_or(false, |(_, highlights)| !highlights.is_empty())
8234    }
8235
8236    pub fn background_highlights_in_range(
8237        &self,
8238        search_range: Range<Anchor>,
8239        display_snapshot: &DisplaySnapshot,
8240        theme: &ThemeColors,
8241    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
8242        let mut results = Vec::new();
8243        for (color_fetcher, ranges) in self.background_highlights.values() {
8244            let color = color_fetcher(theme);
8245            let start_ix = match ranges.binary_search_by(|probe| {
8246                let cmp = probe
8247                    .end
8248                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
8249                if cmp.is_gt() {
8250                    Ordering::Greater
8251                } else {
8252                    Ordering::Less
8253                }
8254            }) {
8255                Ok(i) | Err(i) => i,
8256            };
8257            for range in &ranges[start_ix..] {
8258                if range
8259                    .start
8260                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
8261                    .is_ge()
8262                {
8263                    break;
8264                }
8265
8266                let start = range.start.to_display_point(&display_snapshot);
8267                let end = range.end.to_display_point(&display_snapshot);
8268                results.push((start..end, color))
8269            }
8270        }
8271        results
8272    }
8273
8274    pub fn background_highlight_row_ranges<T: 'static>(
8275        &self,
8276        search_range: Range<Anchor>,
8277        display_snapshot: &DisplaySnapshot,
8278        count: usize,
8279    ) -> Vec<RangeInclusive<DisplayPoint>> {
8280        let mut results = Vec::new();
8281        let Some((_, ranges)) = self.background_highlights.get(&TypeId::of::<T>()) else {
8282            return vec![];
8283        };
8284
8285        let start_ix = match ranges.binary_search_by(|probe| {
8286            let cmp = probe
8287                .end
8288                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
8289            if cmp.is_gt() {
8290                Ordering::Greater
8291            } else {
8292                Ordering::Less
8293            }
8294        }) {
8295            Ok(i) | Err(i) => i,
8296        };
8297        let mut push_region = |start: Option<Point>, end: Option<Point>| {
8298            if let (Some(start_display), Some(end_display)) = (start, end) {
8299                results.push(
8300                    start_display.to_display_point(display_snapshot)
8301                        ..=end_display.to_display_point(display_snapshot),
8302                );
8303            }
8304        };
8305        let mut start_row: Option<Point> = None;
8306        let mut end_row: Option<Point> = None;
8307        if ranges.len() > count {
8308            return Vec::new();
8309        }
8310        for range in &ranges[start_ix..] {
8311            if range
8312                .start
8313                .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
8314                .is_ge()
8315            {
8316                break;
8317            }
8318            let end = range.end.to_point(&display_snapshot.buffer_snapshot);
8319            if let Some(current_row) = &end_row {
8320                if end.row == current_row.row {
8321                    continue;
8322                }
8323            }
8324            let start = range.start.to_point(&display_snapshot.buffer_snapshot);
8325            if start_row.is_none() {
8326                assert_eq!(end_row, None);
8327                start_row = Some(start);
8328                end_row = Some(end);
8329                continue;
8330            }
8331            if let Some(current_end) = end_row.as_mut() {
8332                if start.row > current_end.row + 1 {
8333                    push_region(start_row, end_row);
8334                    start_row = Some(start);
8335                    end_row = Some(end);
8336                } else {
8337                    // Merge two hunks.
8338                    *current_end = end;
8339                }
8340            } else {
8341                unreachable!();
8342            }
8343        }
8344        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
8345        push_region(start_row, end_row);
8346        results
8347    }
8348
8349    pub fn highlight_text<T: 'static>(
8350        &mut self,
8351        ranges: Vec<Range<Anchor>>,
8352        style: HighlightStyle,
8353        cx: &mut ViewContext<Self>,
8354    ) {
8355        self.display_map.update(cx, |map, _| {
8356            map.highlight_text(TypeId::of::<T>(), ranges, style)
8357        });
8358        cx.notify();
8359    }
8360
8361    pub(crate) fn highlight_inlays<T: 'static>(
8362        &mut self,
8363        highlights: Vec<InlayHighlight>,
8364        style: HighlightStyle,
8365        cx: &mut ViewContext<Self>,
8366    ) {
8367        self.display_map.update(cx, |map, _| {
8368            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
8369        });
8370        cx.notify();
8371    }
8372
8373    pub fn text_highlights<'a, T: 'static>(
8374        &'a self,
8375        cx: &'a AppContext,
8376    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
8377        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
8378    }
8379
8380    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut ViewContext<Self>) {
8381        let cleared = self
8382            .display_map
8383            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
8384        if cleared {
8385            cx.notify();
8386        }
8387    }
8388
8389    pub fn show_local_cursors(&self, cx: &WindowContext) -> bool {
8390        (self.read_only(cx) || self.blink_manager.read(cx).visible())
8391            && self.focus_handle.is_focused(cx)
8392    }
8393
8394    fn on_buffer_changed(&mut self, _: Model<MultiBuffer>, cx: &mut ViewContext<Self>) {
8395        cx.notify();
8396    }
8397
8398    fn on_buffer_event(
8399        &mut self,
8400        multibuffer: Model<MultiBuffer>,
8401        event: &multi_buffer::Event,
8402        cx: &mut ViewContext<Self>,
8403    ) {
8404        match event {
8405            multi_buffer::Event::Edited {
8406                singleton_buffer_edited,
8407            } => {
8408                self.refresh_active_diagnostics(cx);
8409                self.refresh_code_actions(cx);
8410                if self.has_active_copilot_suggestion(cx) {
8411                    self.update_visible_copilot_suggestion(cx);
8412                }
8413                cx.emit(EditorEvent::BufferEdited);
8414                cx.emit(SearchEvent::MatchesInvalidated);
8415
8416                if *singleton_buffer_edited {
8417                    if let Some(project) = &self.project {
8418                        let project = project.read(cx);
8419                        let languages_affected = multibuffer
8420                            .read(cx)
8421                            .all_buffers()
8422                            .into_iter()
8423                            .filter_map(|buffer| {
8424                                let buffer = buffer.read(cx);
8425                                let language = buffer.language()?;
8426                                if project.is_local()
8427                                    && project.language_servers_for_buffer(buffer, cx).count() == 0
8428                                {
8429                                    None
8430                                } else {
8431                                    Some(language)
8432                                }
8433                            })
8434                            .cloned()
8435                            .collect::<HashSet<_>>();
8436                        if !languages_affected.is_empty() {
8437                            self.refresh_inlay_hints(
8438                                InlayHintRefreshReason::BufferEdited(languages_affected),
8439                                cx,
8440                            );
8441                        }
8442                    }
8443                }
8444
8445                let Some(project) = &self.project else { return };
8446                let telemetry = project.read(cx).client().telemetry().clone();
8447                telemetry.log_edit_event("editor");
8448            }
8449            multi_buffer::Event::ExcerptsAdded {
8450                buffer,
8451                predecessor,
8452                excerpts,
8453            } => {
8454                cx.emit(EditorEvent::ExcerptsAdded {
8455                    buffer: buffer.clone(),
8456                    predecessor: *predecessor,
8457                    excerpts: excerpts.clone(),
8458                });
8459                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
8460            }
8461            multi_buffer::Event::ExcerptsRemoved { ids } => {
8462                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
8463                cx.emit(EditorEvent::ExcerptsRemoved { ids: ids.clone() })
8464            }
8465            multi_buffer::Event::Reparsed => cx.emit(EditorEvent::Reparsed),
8466            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
8467            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
8468            multi_buffer::Event::FileHandleChanged | multi_buffer::Event::Reloaded => {
8469                cx.emit(EditorEvent::TitleChanged)
8470            }
8471            multi_buffer::Event::DiffBaseChanged => cx.emit(EditorEvent::DiffBaseChanged),
8472            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
8473            multi_buffer::Event::DiagnosticsUpdated => {
8474                self.refresh_active_diagnostics(cx);
8475            }
8476            _ => {}
8477        };
8478    }
8479
8480    fn on_display_map_changed(&mut self, _: Model<DisplayMap>, cx: &mut ViewContext<Self>) {
8481        cx.notify();
8482    }
8483
8484    fn settings_changed(&mut self, cx: &mut ViewContext<Self>) {
8485        self.refresh_copilot_suggestions(true, cx);
8486        self.refresh_inlay_hints(
8487            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
8488                self.selections.newest_anchor().head(),
8489                &self.buffer.read(cx).snapshot(cx),
8490                cx,
8491            )),
8492            cx,
8493        );
8494        cx.notify();
8495    }
8496
8497    pub fn set_searchable(&mut self, searchable: bool) {
8498        self.searchable = searchable;
8499    }
8500
8501    pub fn searchable(&self) -> bool {
8502        self.searchable
8503    }
8504
8505    fn open_excerpts(&mut self, _: &OpenExcerpts, cx: &mut ViewContext<Self>) {
8506        let buffer = self.buffer.read(cx);
8507        if buffer.is_singleton() {
8508            cx.propagate();
8509            return;
8510        }
8511
8512        let Some(workspace) = self.workspace() else {
8513            cx.propagate();
8514            return;
8515        };
8516
8517        let mut new_selections_by_buffer = HashMap::default();
8518        for selection in self.selections.all::<usize>(cx) {
8519            for (buffer, mut range, _) in
8520                buffer.range_to_buffer_ranges(selection.start..selection.end, cx)
8521            {
8522                if selection.reversed {
8523                    mem::swap(&mut range.start, &mut range.end);
8524                }
8525                new_selections_by_buffer
8526                    .entry(buffer)
8527                    .or_insert(Vec::new())
8528                    .push(range)
8529            }
8530        }
8531
8532        self.push_to_nav_history(self.selections.newest_anchor().head(), None, cx);
8533
8534        // We defer the pane interaction because we ourselves are a workspace item
8535        // and activating a new item causes the pane to call a method on us reentrantly,
8536        // which panics if we're on the stack.
8537        cx.window_context().defer(move |cx| {
8538            workspace.update(cx, |workspace, cx| {
8539                let pane = workspace.active_pane().clone();
8540                pane.update(cx, |pane, _| pane.disable_history());
8541
8542                for (buffer, ranges) in new_selections_by_buffer.into_iter() {
8543                    let editor = workspace.open_project_item::<Self>(buffer, cx);
8544                    editor.update(cx, |editor, cx| {
8545                        editor.change_selections(Some(Autoscroll::newest()), cx, |s| {
8546                            s.select_ranges(ranges);
8547                        });
8548                    });
8549                }
8550
8551                pane.update(cx, |pane, _| pane.enable_history());
8552            })
8553        });
8554    }
8555
8556    fn jump(
8557        &mut self,
8558        path: ProjectPath,
8559        position: Point,
8560        anchor: language::Anchor,
8561        cx: &mut ViewContext<Self>,
8562    ) {
8563        let workspace = self.workspace();
8564        cx.spawn(|_, mut cx| async move {
8565            let workspace = workspace.ok_or_else(|| anyhow!("cannot jump without workspace"))?;
8566            let editor = workspace.update(&mut cx, |workspace, cx| {
8567                workspace.open_path(path, None, true, cx)
8568            })?;
8569            let editor = editor
8570                .await?
8571                .downcast::<Editor>()
8572                .ok_or_else(|| anyhow!("opened item was not an editor"))?
8573                .downgrade();
8574            editor.update(&mut cx, |editor, cx| {
8575                let buffer = editor
8576                    .buffer()
8577                    .read(cx)
8578                    .as_singleton()
8579                    .ok_or_else(|| anyhow!("cannot jump in a multi-buffer"))?;
8580                let buffer = buffer.read(cx);
8581                let cursor = if buffer.can_resolve(&anchor) {
8582                    language::ToPoint::to_point(&anchor, buffer)
8583                } else {
8584                    buffer.clip_point(position, Bias::Left)
8585                };
8586
8587                let nav_history = editor.nav_history.take();
8588                editor.change_selections(Some(Autoscroll::newest()), cx, |s| {
8589                    s.select_ranges([cursor..cursor]);
8590                });
8591                editor.nav_history = nav_history;
8592
8593                anyhow::Ok(())
8594            })??;
8595
8596            anyhow::Ok(())
8597        })
8598        .detach_and_log_err(cx);
8599    }
8600
8601    fn marked_text_ranges(&self, cx: &AppContext) -> Option<Vec<Range<OffsetUtf16>>> {
8602        let snapshot = self.buffer.read(cx).read(cx);
8603        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
8604        Some(
8605            ranges
8606                .iter()
8607                .map(move |range| {
8608                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
8609                })
8610                .collect(),
8611        )
8612    }
8613
8614    fn selection_replacement_ranges(
8615        &self,
8616        range: Range<OffsetUtf16>,
8617        cx: &AppContext,
8618    ) -> Vec<Range<OffsetUtf16>> {
8619        let selections = self.selections.all::<OffsetUtf16>(cx);
8620        let newest_selection = selections
8621            .iter()
8622            .max_by_key(|selection| selection.id)
8623            .unwrap();
8624        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
8625        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
8626        let snapshot = self.buffer.read(cx).read(cx);
8627        selections
8628            .into_iter()
8629            .map(|mut selection| {
8630                selection.start.0 =
8631                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
8632                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
8633                snapshot.clip_offset_utf16(selection.start, Bias::Left)
8634                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
8635            })
8636            .collect()
8637    }
8638
8639    fn report_copilot_event(
8640        &self,
8641        suggestion_id: Option<String>,
8642        suggestion_accepted: bool,
8643        cx: &AppContext,
8644    ) {
8645        let Some(project) = &self.project else { return };
8646
8647        // If None, we are either getting suggestions in a new, unsaved file, or in a file without an extension
8648        let file_extension = self
8649            .buffer
8650            .read(cx)
8651            .as_singleton()
8652            .and_then(|b| b.read(cx).file())
8653            .and_then(|file| Path::new(file.file_name(cx)).extension())
8654            .and_then(|e| e.to_str())
8655            .map(|a| a.to_string());
8656
8657        let telemetry = project.read(cx).client().telemetry().clone();
8658
8659        telemetry.report_copilot_event(suggestion_id, suggestion_accepted, file_extension)
8660    }
8661
8662    #[cfg(any(test, feature = "test-support"))]
8663    fn report_editor_event(
8664        &self,
8665        _operation: &'static str,
8666        _file_extension: Option<String>,
8667        _cx: &AppContext,
8668    ) {
8669    }
8670
8671    #[cfg(not(any(test, feature = "test-support")))]
8672    fn report_editor_event(
8673        &self,
8674        operation: &'static str,
8675        file_extension: Option<String>,
8676        cx: &AppContext,
8677    ) {
8678        let Some(project) = &self.project else { return };
8679
8680        // If None, we are in a file without an extension
8681        let file = self
8682            .buffer
8683            .read(cx)
8684            .as_singleton()
8685            .and_then(|b| b.read(cx).file());
8686        let file_extension = file_extension.or(file
8687            .as_ref()
8688            .and_then(|file| Path::new(file.file_name(cx)).extension())
8689            .and_then(|e| e.to_str())
8690            .map(|a| a.to_string()));
8691
8692        let vim_mode = cx
8693            .global::<SettingsStore>()
8694            .raw_user_settings()
8695            .get("vim_mode")
8696            == Some(&serde_json::Value::Bool(true));
8697        let copilot_enabled = all_language_settings(file, cx).copilot_enabled(None, None);
8698        let copilot_enabled_for_language = self
8699            .buffer
8700            .read(cx)
8701            .settings_at(0, cx)
8702            .show_copilot_suggestions;
8703
8704        let telemetry = project.read(cx).client().telemetry().clone();
8705        telemetry.report_editor_event(
8706            file_extension,
8707            vim_mode,
8708            operation,
8709            copilot_enabled,
8710            copilot_enabled_for_language,
8711        )
8712    }
8713
8714    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
8715    /// with each line being an array of {text, highlight} objects.
8716    fn copy_highlight_json(&mut self, _: &CopyHighlightJson, cx: &mut ViewContext<Self>) {
8717        let Some(buffer) = self.buffer.read(cx).as_singleton() else {
8718            return;
8719        };
8720
8721        #[derive(Serialize)]
8722        struct Chunk<'a> {
8723            text: String,
8724            highlight: Option<&'a str>,
8725        }
8726
8727        let snapshot = buffer.read(cx).snapshot();
8728        let range = self
8729            .selected_text_range(cx)
8730            .and_then(|selected_range| {
8731                if selected_range.is_empty() {
8732                    None
8733                } else {
8734                    Some(selected_range)
8735                }
8736            })
8737            .unwrap_or_else(|| 0..snapshot.len());
8738
8739        let chunks = snapshot.chunks(range, true);
8740        let mut lines = Vec::new();
8741        let mut line: VecDeque<Chunk> = VecDeque::new();
8742
8743        let Some(style) = self.style.as_ref() else {
8744            return;
8745        };
8746
8747        for chunk in chunks {
8748            let highlight = chunk
8749                .syntax_highlight_id
8750                .and_then(|id| id.name(&style.syntax));
8751            let mut chunk_lines = chunk.text.split("\n").peekable();
8752            while let Some(text) = chunk_lines.next() {
8753                let mut merged_with_last_token = false;
8754                if let Some(last_token) = line.back_mut() {
8755                    if last_token.highlight == highlight {
8756                        last_token.text.push_str(text);
8757                        merged_with_last_token = true;
8758                    }
8759                }
8760
8761                if !merged_with_last_token {
8762                    line.push_back(Chunk {
8763                        text: text.into(),
8764                        highlight,
8765                    });
8766                }
8767
8768                if chunk_lines.peek().is_some() {
8769                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
8770                        line.pop_front();
8771                    }
8772                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
8773                        line.pop_back();
8774                    }
8775
8776                    lines.push(mem::take(&mut line));
8777                }
8778            }
8779        }
8780
8781        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
8782            return;
8783        };
8784        cx.write_to_clipboard(ClipboardItem::new(lines));
8785    }
8786
8787    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
8788        &self.inlay_hint_cache
8789    }
8790
8791    pub fn replay_insert_event(
8792        &mut self,
8793        text: &str,
8794        relative_utf16_range: Option<Range<isize>>,
8795        cx: &mut ViewContext<Self>,
8796    ) {
8797        if !self.input_enabled {
8798            cx.emit(EditorEvent::InputIgnored { text: text.into() });
8799            return;
8800        }
8801        if let Some(relative_utf16_range) = relative_utf16_range {
8802            let selections = self.selections.all::<OffsetUtf16>(cx);
8803            self.change_selections(None, cx, |s| {
8804                let new_ranges = selections.into_iter().map(|range| {
8805                    let start = OffsetUtf16(
8806                        range
8807                            .head()
8808                            .0
8809                            .saturating_add_signed(relative_utf16_range.start),
8810                    );
8811                    let end = OffsetUtf16(
8812                        range
8813                            .head()
8814                            .0
8815                            .saturating_add_signed(relative_utf16_range.end),
8816                    );
8817                    start..end
8818                });
8819                s.select_ranges(new_ranges);
8820            });
8821        }
8822
8823        self.handle_input(text, cx);
8824    }
8825
8826    pub fn supports_inlay_hints(&self, cx: &AppContext) -> bool {
8827        let Some(project) = self.project.as_ref() else {
8828            return false;
8829        };
8830        let project = project.read(cx);
8831
8832        let mut supports = false;
8833        self.buffer().read(cx).for_each_buffer(|buffer| {
8834            if !supports {
8835                supports = project
8836                    .language_servers_for_buffer(buffer.read(cx), cx)
8837                    .any(
8838                        |(_, server)| match server.capabilities().inlay_hint_provider {
8839                            Some(lsp::OneOf::Left(enabled)) => enabled,
8840                            Some(lsp::OneOf::Right(_)) => true,
8841                            None => false,
8842                        },
8843                    )
8844            }
8845        });
8846        supports
8847    }
8848
8849    pub fn focus(&self, cx: &mut WindowContext) {
8850        cx.focus(&self.focus_handle)
8851    }
8852
8853    pub fn is_focused(&self, cx: &WindowContext) -> bool {
8854        self.focus_handle.is_focused(cx)
8855    }
8856
8857    fn handle_focus(&mut self, cx: &mut ViewContext<Self>) {
8858        cx.emit(EditorEvent::Focused);
8859
8860        if let Some(rename) = self.pending_rename.as_ref() {
8861            let rename_editor_focus_handle = rename.editor.read(cx).focus_handle.clone();
8862            cx.focus(&rename_editor_focus_handle);
8863        } else {
8864            self.blink_manager.update(cx, BlinkManager::enable);
8865            self.show_cursor_names(cx);
8866            self.buffer.update(cx, |buffer, cx| {
8867                buffer.finalize_last_transaction(cx);
8868                if self.leader_peer_id.is_none() {
8869                    buffer.set_active_selections(
8870                        &self.selections.disjoint_anchors(),
8871                        self.selections.line_mode,
8872                        self.cursor_shape,
8873                        cx,
8874                    );
8875                }
8876            });
8877        }
8878    }
8879
8880    pub fn handle_blur(&mut self, cx: &mut ViewContext<Self>) {
8881        self.blink_manager.update(cx, BlinkManager::disable);
8882        self.buffer
8883            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
8884        self.hide_context_menu(cx);
8885        hide_hover(self, cx);
8886        cx.emit(EditorEvent::Blurred);
8887        cx.notify();
8888    }
8889
8890    pub fn register_action<A: Action>(
8891        &mut self,
8892        listener: impl Fn(&A, &mut WindowContext) + 'static,
8893    ) -> &mut Self {
8894        let listener = Arc::new(listener);
8895
8896        self.editor_actions.push(Box::new(move |cx| {
8897            let _view = cx.view().clone();
8898            let cx = cx.window_context();
8899            let listener = listener.clone();
8900            cx.on_action(TypeId::of::<A>(), move |action, phase, cx| {
8901                let action = action.downcast_ref().unwrap();
8902                if phase == DispatchPhase::Bubble {
8903                    listener(action, cx)
8904                }
8905            })
8906        }));
8907        self
8908    }
8909}
8910
8911pub trait CollaborationHub {
8912    fn collaborators<'a>(&self, cx: &'a AppContext) -> &'a HashMap<PeerId, Collaborator>;
8913    fn user_participant_indices<'a>(
8914        &self,
8915        cx: &'a AppContext,
8916    ) -> &'a HashMap<u64, ParticipantIndex>;
8917    fn user_names(&self, cx: &AppContext) -> HashMap<u64, SharedString>;
8918}
8919
8920impl CollaborationHub for Model<Project> {
8921    fn collaborators<'a>(&self, cx: &'a AppContext) -> &'a HashMap<PeerId, Collaborator> {
8922        self.read(cx).collaborators()
8923    }
8924
8925    fn user_participant_indices<'a>(
8926        &self,
8927        cx: &'a AppContext,
8928    ) -> &'a HashMap<u64, ParticipantIndex> {
8929        self.read(cx).user_store().read(cx).participant_indices()
8930    }
8931
8932    fn user_names(&self, cx: &AppContext) -> HashMap<u64, SharedString> {
8933        let this = self.read(cx);
8934        let user_ids = this.collaborators().values().map(|c| c.user_id);
8935        this.user_store().read_with(cx, |user_store, cx| {
8936            user_store.participant_names(user_ids, cx)
8937        })
8938    }
8939}
8940
8941pub trait CompletionProvider {
8942    fn completions(
8943        &self,
8944        buffer: &Model<Buffer>,
8945        buffer_position: text::Anchor,
8946        cx: &mut ViewContext<Editor>,
8947    ) -> Task<Result<Vec<Completion>>>;
8948
8949    fn resolve_completions(
8950        &self,
8951        completion_indices: Vec<usize>,
8952        completions: Arc<RwLock<Box<[Completion]>>>,
8953        cx: &mut ViewContext<Editor>,
8954    ) -> Task<Result<bool>>;
8955
8956    fn apply_additional_edits_for_completion(
8957        &self,
8958        buffer: Model<Buffer>,
8959        completion: Completion,
8960        push_to_history: bool,
8961        cx: &mut ViewContext<Editor>,
8962    ) -> Task<Result<Option<language::Transaction>>>;
8963}
8964
8965impl CompletionProvider for Model<Project> {
8966    fn completions(
8967        &self,
8968        buffer: &Model<Buffer>,
8969        buffer_position: text::Anchor,
8970        cx: &mut ViewContext<Editor>,
8971    ) -> Task<Result<Vec<Completion>>> {
8972        self.update(cx, |project, cx| {
8973            project.completions(&buffer, buffer_position, cx)
8974        })
8975    }
8976
8977    fn resolve_completions(
8978        &self,
8979        completion_indices: Vec<usize>,
8980        completions: Arc<RwLock<Box<[Completion]>>>,
8981        cx: &mut ViewContext<Editor>,
8982    ) -> Task<Result<bool>> {
8983        self.update(cx, |project, cx| {
8984            project.resolve_completions(completion_indices, completions, cx)
8985        })
8986    }
8987
8988    fn apply_additional_edits_for_completion(
8989        &self,
8990        buffer: Model<Buffer>,
8991        completion: Completion,
8992        push_to_history: bool,
8993        cx: &mut ViewContext<Editor>,
8994    ) -> Task<Result<Option<language::Transaction>>> {
8995        self.update(cx, |project, cx| {
8996            project.apply_additional_edits_for_completion(buffer, completion, push_to_history, cx)
8997        })
8998    }
8999}
9000
9001fn inlay_hint_settings(
9002    location: Anchor,
9003    snapshot: &MultiBufferSnapshot,
9004    cx: &mut ViewContext<'_, Editor>,
9005) -> InlayHintSettings {
9006    let file = snapshot.file_at(location);
9007    let language = snapshot.language_at(location);
9008    let settings = all_language_settings(file, cx);
9009    settings
9010        .language(language.map(|l| l.name()).as_deref())
9011        .inlay_hints
9012}
9013
9014fn consume_contiguous_rows(
9015    contiguous_row_selections: &mut Vec<Selection<Point>>,
9016    selection: &Selection<Point>,
9017    display_map: &DisplaySnapshot,
9018    selections: &mut std::iter::Peekable<std::slice::Iter<Selection<Point>>>,
9019) -> (u32, u32) {
9020    contiguous_row_selections.push(selection.clone());
9021    let start_row = selection.start.row;
9022    let mut end_row = ending_row(selection, display_map);
9023
9024    while let Some(next_selection) = selections.peek() {
9025        if next_selection.start.row <= end_row {
9026            end_row = ending_row(next_selection, display_map);
9027            contiguous_row_selections.push(selections.next().unwrap().clone());
9028        } else {
9029            break;
9030        }
9031    }
9032    (start_row, end_row)
9033}
9034
9035fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> u32 {
9036    if next_selection.end.column > 0 || next_selection.is_empty() {
9037        display_map.next_line_boundary(next_selection.end).0.row + 1
9038    } else {
9039        next_selection.end.row
9040    }
9041}
9042
9043impl EditorSnapshot {
9044    pub fn remote_selections_in_range<'a>(
9045        &'a self,
9046        range: &'a Range<Anchor>,
9047        collaboration_hub: &dyn CollaborationHub,
9048        cx: &'a AppContext,
9049    ) -> impl 'a + Iterator<Item = RemoteSelection> {
9050        let participant_names = collaboration_hub.user_names(cx);
9051        let participant_indices = collaboration_hub.user_participant_indices(cx);
9052        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
9053        let collaborators_by_replica_id = collaborators_by_peer_id
9054            .iter()
9055            .map(|(_, collaborator)| (collaborator.replica_id, collaborator))
9056            .collect::<HashMap<_, _>>();
9057        self.buffer_snapshot
9058            .remote_selections_in_range(range)
9059            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
9060                let collaborator = collaborators_by_replica_id.get(&replica_id)?;
9061                let participant_index = participant_indices.get(&collaborator.user_id).copied();
9062                let user_name = participant_names.get(&collaborator.user_id).cloned();
9063                Some(RemoteSelection {
9064                    replica_id,
9065                    selection,
9066                    cursor_shape,
9067                    line_mode,
9068                    participant_index,
9069                    peer_id: collaborator.peer_id,
9070                    user_name,
9071                })
9072            })
9073    }
9074
9075    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
9076        self.display_snapshot.buffer_snapshot.language_at(position)
9077    }
9078
9079    pub fn is_focused(&self) -> bool {
9080        self.is_focused
9081    }
9082
9083    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
9084        self.placeholder_text.as_ref()
9085    }
9086
9087    pub fn scroll_position(&self) -> gpui::Point<f32> {
9088        self.scroll_anchor.scroll_position(&self.display_snapshot)
9089    }
9090
9091    pub fn gutter_dimensions(
9092        &self,
9093        font_id: FontId,
9094        font_size: Pixels,
9095        em_width: Pixels,
9096        max_line_number_width: Pixels,
9097        cx: &AppContext,
9098    ) -> GutterDimensions {
9099        if self.show_gutter {
9100            let descent = cx.text_system().descent(font_id, font_size);
9101            let gutter_padding_factor = 4.0;
9102            let gutter_padding = (em_width * gutter_padding_factor).round();
9103            // Avoid flicker-like gutter resizes when the line number gains another digit and only resize the gutter on files with N*10^5 lines.
9104            let min_width_for_number_on_gutter = em_width * 4.0;
9105            let gutter_width =
9106                max_line_number_width.max(min_width_for_number_on_gutter) + gutter_padding * 2.0;
9107            let gutter_margin = -descent;
9108
9109            GutterDimensions {
9110                padding: gutter_padding,
9111                width: gutter_width,
9112                margin: gutter_margin,
9113            }
9114        } else {
9115            GutterDimensions::default()
9116        }
9117    }
9118}
9119
9120impl Deref for EditorSnapshot {
9121    type Target = DisplaySnapshot;
9122
9123    fn deref(&self) -> &Self::Target {
9124        &self.display_snapshot
9125    }
9126}
9127
9128#[derive(Clone, Debug, PartialEq, Eq)]
9129pub enum EditorEvent {
9130    InputIgnored {
9131        text: Arc<str>,
9132    },
9133    InputHandled {
9134        utf16_range_to_replace: Option<Range<isize>>,
9135        text: Arc<str>,
9136    },
9137    ExcerptsAdded {
9138        buffer: Model<Buffer>,
9139        predecessor: ExcerptId,
9140        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
9141    },
9142    ExcerptsRemoved {
9143        ids: Vec<ExcerptId>,
9144    },
9145    BufferEdited,
9146    Edited,
9147    Reparsed,
9148    Focused,
9149    Blurred,
9150    DirtyChanged,
9151    Saved,
9152    TitleChanged,
9153    DiffBaseChanged,
9154    SelectionsChanged {
9155        local: bool,
9156    },
9157    ScrollPositionChanged {
9158        local: bool,
9159        autoscroll: bool,
9160    },
9161    Closed,
9162}
9163
9164impl EventEmitter<EditorEvent> for Editor {}
9165
9166impl FocusableView for Editor {
9167    fn focus_handle(&self, _cx: &AppContext) -> FocusHandle {
9168        self.focus_handle.clone()
9169    }
9170}
9171
9172impl Render for Editor {
9173    fn render<'a>(&mut self, cx: &mut ViewContext<'a, Self>) -> impl IntoElement {
9174        let settings = ThemeSettings::get_global(cx);
9175        let text_style = match self.mode {
9176            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
9177                color: cx.theme().colors().editor_foreground,
9178                font_family: settings.ui_font.family.clone(),
9179                font_features: settings.ui_font.features,
9180                font_size: rems(0.875).into(),
9181                font_weight: FontWeight::NORMAL,
9182                font_style: FontStyle::Normal,
9183                line_height: relative(settings.buffer_line_height.value()),
9184                background_color: None,
9185                underline: None,
9186                white_space: WhiteSpace::Normal,
9187            },
9188
9189            EditorMode::Full => TextStyle {
9190                color: cx.theme().colors().editor_foreground,
9191                font_family: settings.buffer_font.family.clone(),
9192                font_features: settings.buffer_font.features,
9193                font_size: settings.buffer_font_size(cx).into(),
9194                font_weight: FontWeight::NORMAL,
9195                font_style: FontStyle::Normal,
9196                line_height: relative(settings.buffer_line_height.value()),
9197                background_color: None,
9198                underline: None,
9199                white_space: WhiteSpace::Normal,
9200            },
9201        };
9202
9203        let background = match self.mode {
9204            EditorMode::SingleLine => cx.theme().system().transparent,
9205            EditorMode::AutoHeight { max_lines: _ } => cx.theme().system().transparent,
9206            EditorMode::Full => cx.theme().colors().editor_background,
9207        };
9208
9209        EditorElement::new(
9210            cx.view(),
9211            EditorStyle {
9212                background,
9213                local_player: cx.theme().players().local(),
9214                text: text_style,
9215                scrollbar_width: px(12.),
9216                syntax: cx.theme().syntax().clone(),
9217                status: cx.theme().status().clone(),
9218                inlays_style: HighlightStyle {
9219                    color: Some(cx.theme().status().hint),
9220                    font_weight: Some(FontWeight::BOLD),
9221                    ..HighlightStyle::default()
9222                },
9223                suggestions_style: HighlightStyle {
9224                    color: Some(cx.theme().status().predictive),
9225                    ..HighlightStyle::default()
9226                },
9227            },
9228        )
9229    }
9230}
9231
9232impl ViewInputHandler for Editor {
9233    fn text_for_range(
9234        &mut self,
9235        range_utf16: Range<usize>,
9236        cx: &mut ViewContext<Self>,
9237    ) -> Option<String> {
9238        Some(
9239            self.buffer
9240                .read(cx)
9241                .read(cx)
9242                .text_for_range(OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end))
9243                .collect(),
9244        )
9245    }
9246
9247    fn selected_text_range(&mut self, cx: &mut ViewContext<Self>) -> Option<Range<usize>> {
9248        // Prevent the IME menu from appearing when holding down an alphabetic key
9249        // while input is disabled.
9250        if !self.input_enabled {
9251            return None;
9252        }
9253
9254        let range = self.selections.newest::<OffsetUtf16>(cx).range();
9255        Some(range.start.0..range.end.0)
9256    }
9257
9258    fn marked_text_range(&self, cx: &mut ViewContext<Self>) -> Option<Range<usize>> {
9259        let snapshot = self.buffer.read(cx).read(cx);
9260        let range = self.text_highlights::<InputComposition>(cx)?.1.get(0)?;
9261        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
9262    }
9263
9264    fn unmark_text(&mut self, cx: &mut ViewContext<Self>) {
9265        self.clear_highlights::<InputComposition>(cx);
9266        self.ime_transaction.take();
9267    }
9268
9269    fn replace_text_in_range(
9270        &mut self,
9271        range_utf16: Option<Range<usize>>,
9272        text: &str,
9273        cx: &mut ViewContext<Self>,
9274    ) {
9275        if !self.input_enabled {
9276            cx.emit(EditorEvent::InputIgnored { text: text.into() });
9277            return;
9278        }
9279
9280        self.transact(cx, |this, cx| {
9281            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
9282                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
9283                Some(this.selection_replacement_ranges(range_utf16, cx))
9284            } else {
9285                this.marked_text_ranges(cx)
9286            };
9287
9288            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
9289                let newest_selection_id = this.selections.newest_anchor().id;
9290                this.selections
9291                    .all::<OffsetUtf16>(cx)
9292                    .iter()
9293                    .zip(ranges_to_replace.iter())
9294                    .find_map(|(selection, range)| {
9295                        if selection.id == newest_selection_id {
9296                            Some(
9297                                (range.start.0 as isize - selection.head().0 as isize)
9298                                    ..(range.end.0 as isize - selection.head().0 as isize),
9299                            )
9300                        } else {
9301                            None
9302                        }
9303                    })
9304            });
9305
9306            cx.emit(EditorEvent::InputHandled {
9307                utf16_range_to_replace: range_to_replace,
9308                text: text.into(),
9309            });
9310
9311            if let Some(new_selected_ranges) = new_selected_ranges {
9312                this.change_selections(None, cx, |selections| {
9313                    selections.select_ranges(new_selected_ranges)
9314                });
9315            }
9316
9317            this.handle_input(text, cx);
9318        });
9319
9320        if let Some(transaction) = self.ime_transaction {
9321            self.buffer.update(cx, |buffer, cx| {
9322                buffer.group_until_transaction(transaction, cx);
9323            });
9324        }
9325
9326        self.unmark_text(cx);
9327    }
9328
9329    fn replace_and_mark_text_in_range(
9330        &mut self,
9331        range_utf16: Option<Range<usize>>,
9332        text: &str,
9333        new_selected_range_utf16: Option<Range<usize>>,
9334        cx: &mut ViewContext<Self>,
9335    ) {
9336        if !self.input_enabled {
9337            cx.emit(EditorEvent::InputIgnored { text: text.into() });
9338            return;
9339        }
9340
9341        let transaction = self.transact(cx, |this, cx| {
9342            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
9343                let snapshot = this.buffer.read(cx).read(cx);
9344                if let Some(relative_range_utf16) = range_utf16.as_ref() {
9345                    for marked_range in &mut marked_ranges {
9346                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
9347                        marked_range.start.0 += relative_range_utf16.start;
9348                        marked_range.start =
9349                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
9350                        marked_range.end =
9351                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
9352                    }
9353                }
9354                Some(marked_ranges)
9355            } else if let Some(range_utf16) = range_utf16 {
9356                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
9357                Some(this.selection_replacement_ranges(range_utf16, cx))
9358            } else {
9359                None
9360            };
9361
9362            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
9363                let newest_selection_id = this.selections.newest_anchor().id;
9364                this.selections
9365                    .all::<OffsetUtf16>(cx)
9366                    .iter()
9367                    .zip(ranges_to_replace.iter())
9368                    .find_map(|(selection, range)| {
9369                        if selection.id == newest_selection_id {
9370                            Some(
9371                                (range.start.0 as isize - selection.head().0 as isize)
9372                                    ..(range.end.0 as isize - selection.head().0 as isize),
9373                            )
9374                        } else {
9375                            None
9376                        }
9377                    })
9378            });
9379
9380            cx.emit(EditorEvent::InputHandled {
9381                utf16_range_to_replace: range_to_replace,
9382                text: text.into(),
9383            });
9384
9385            if let Some(ranges) = ranges_to_replace {
9386                this.change_selections(None, cx, |s| s.select_ranges(ranges));
9387            }
9388
9389            let marked_ranges = {
9390                let snapshot = this.buffer.read(cx).read(cx);
9391                this.selections
9392                    .disjoint_anchors()
9393                    .iter()
9394                    .map(|selection| {
9395                        selection.start.bias_left(&*snapshot)..selection.end.bias_right(&*snapshot)
9396                    })
9397                    .collect::<Vec<_>>()
9398            };
9399
9400            if text.is_empty() {
9401                this.unmark_text(cx);
9402            } else {
9403                this.highlight_text::<InputComposition>(
9404                    marked_ranges.clone(),
9405                    HighlightStyle::default(), // todo!() this.style(cx).composition_mark,
9406                    cx,
9407                );
9408            }
9409
9410            this.handle_input(text, cx);
9411
9412            if let Some(new_selected_range) = new_selected_range_utf16 {
9413                let snapshot = this.buffer.read(cx).read(cx);
9414                let new_selected_ranges = marked_ranges
9415                    .into_iter()
9416                    .map(|marked_range| {
9417                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
9418                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
9419                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
9420                        snapshot.clip_offset_utf16(new_start, Bias::Left)
9421                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
9422                    })
9423                    .collect::<Vec<_>>();
9424
9425                drop(snapshot);
9426                this.change_selections(None, cx, |selections| {
9427                    selections.select_ranges(new_selected_ranges)
9428                });
9429            }
9430        });
9431
9432        self.ime_transaction = self.ime_transaction.or(transaction);
9433        if let Some(transaction) = self.ime_transaction {
9434            self.buffer.update(cx, |buffer, cx| {
9435                buffer.group_until_transaction(transaction, cx);
9436            });
9437        }
9438
9439        if self.text_highlights::<InputComposition>(cx).is_none() {
9440            self.ime_transaction.take();
9441        }
9442    }
9443
9444    fn bounds_for_range(
9445        &mut self,
9446        range_utf16: Range<usize>,
9447        element_bounds: gpui::Bounds<Pixels>,
9448        cx: &mut ViewContext<Self>,
9449    ) -> Option<gpui::Bounds<Pixels>> {
9450        let text_layout_details = self.text_layout_details(cx);
9451        let style = &text_layout_details.editor_style;
9452        let font_id = cx.text_system().resolve_font(&style.text.font());
9453        let font_size = style.text.font_size.to_pixels(cx.rem_size());
9454        let line_height = style.text.line_height_in_pixels(cx.rem_size());
9455        let em_width = cx
9456            .text_system()
9457            .typographic_bounds(font_id, font_size, 'm')
9458            .unwrap()
9459            .size
9460            .width;
9461
9462        let snapshot = self.snapshot(cx);
9463        let scroll_position = snapshot.scroll_position();
9464        let scroll_left = scroll_position.x * em_width;
9465
9466        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
9467        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
9468            + self.gutter_width;
9469        let y = line_height * (start.row() as f32 - scroll_position.y);
9470
9471        Some(Bounds {
9472            origin: element_bounds.origin + point(x, y),
9473            size: size(em_width, line_height),
9474        })
9475    }
9476}
9477
9478trait SelectionExt {
9479    fn offset_range(&self, buffer: &MultiBufferSnapshot) -> Range<usize>;
9480    fn point_range(&self, buffer: &MultiBufferSnapshot) -> Range<Point>;
9481    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
9482    fn spanned_rows(&self, include_end_if_at_line_start: bool, map: &DisplaySnapshot)
9483        -> Range<u32>;
9484}
9485
9486impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
9487    fn point_range(&self, buffer: &MultiBufferSnapshot) -> Range<Point> {
9488        let start = self.start.to_point(buffer);
9489        let end = self.end.to_point(buffer);
9490        if self.reversed {
9491            end..start
9492        } else {
9493            start..end
9494        }
9495    }
9496
9497    fn offset_range(&self, buffer: &MultiBufferSnapshot) -> Range<usize> {
9498        let start = self.start.to_offset(buffer);
9499        let end = self.end.to_offset(buffer);
9500        if self.reversed {
9501            end..start
9502        } else {
9503            start..end
9504        }
9505    }
9506
9507    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
9508        let start = self
9509            .start
9510            .to_point(&map.buffer_snapshot)
9511            .to_display_point(map);
9512        let end = self
9513            .end
9514            .to_point(&map.buffer_snapshot)
9515            .to_display_point(map);
9516        if self.reversed {
9517            end..start
9518        } else {
9519            start..end
9520        }
9521    }
9522
9523    fn spanned_rows(
9524        &self,
9525        include_end_if_at_line_start: bool,
9526        map: &DisplaySnapshot,
9527    ) -> Range<u32> {
9528        let start = self.start.to_point(&map.buffer_snapshot);
9529        let mut end = self.end.to_point(&map.buffer_snapshot);
9530        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
9531            end.row -= 1;
9532        }
9533
9534        let buffer_start = map.prev_line_boundary(start).0;
9535        let buffer_end = map.next_line_boundary(end).0;
9536        buffer_start.row..buffer_end.row + 1
9537    }
9538}
9539
9540impl<T: InvalidationRegion> InvalidationStack<T> {
9541    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
9542    where
9543        S: Clone + ToOffset,
9544    {
9545        while let Some(region) = self.last() {
9546            let all_selections_inside_invalidation_ranges =
9547                if selections.len() == region.ranges().len() {
9548                    selections
9549                        .iter()
9550                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
9551                        .all(|(selection, invalidation_range)| {
9552                            let head = selection.head().to_offset(buffer);
9553                            invalidation_range.start <= head && invalidation_range.end >= head
9554                        })
9555                } else {
9556                    false
9557                };
9558
9559            if all_selections_inside_invalidation_ranges {
9560                break;
9561            } else {
9562                self.pop();
9563            }
9564        }
9565    }
9566}
9567
9568impl<T> Default for InvalidationStack<T> {
9569    fn default() -> Self {
9570        Self(Default::default())
9571    }
9572}
9573
9574impl<T> Deref for InvalidationStack<T> {
9575    type Target = Vec<T>;
9576
9577    fn deref(&self) -> &Self::Target {
9578        &self.0
9579    }
9580}
9581
9582impl<T> DerefMut for InvalidationStack<T> {
9583    fn deref_mut(&mut self) -> &mut Self::Target {
9584        &mut self.0
9585    }
9586}
9587
9588impl InvalidationRegion for SnippetState {
9589    fn ranges(&self) -> &[Range<Anchor>] {
9590        &self.ranges[self.active_index]
9591    }
9592}
9593
9594pub fn diagnostic_block_renderer(diagnostic: Diagnostic, _is_valid: bool) -> RenderBlock {
9595    let (text_without_backticks, code_ranges) = highlight_diagnostic_message(&diagnostic);
9596
9597    Arc::new(move |cx: &mut BlockContext| {
9598        let group_id: SharedString = cx.block_id.to_string().into();
9599
9600        let mut text_style = cx.text_style().clone();
9601        text_style.color = diagnostic_style(diagnostic.severity, true, cx.theme().status());
9602
9603        h_flex()
9604            .id(cx.block_id)
9605            .group(group_id.clone())
9606            .relative()
9607            .size_full()
9608            .pl(cx.gutter_width)
9609            .w(cx.max_width + cx.gutter_width)
9610            .child(div().flex().w(cx.anchor_x - cx.gutter_width).flex_shrink())
9611            .child(div().flex().flex_shrink_0().child(
9612                StyledText::new(text_without_backticks.clone()).with_highlights(
9613                    &text_style,
9614                    code_ranges.iter().map(|range| {
9615                        (
9616                            range.clone(),
9617                            HighlightStyle {
9618                                font_weight: Some(FontWeight::BOLD),
9619                                ..Default::default()
9620                            },
9621                        )
9622                    }),
9623                ),
9624            ))
9625            .child(
9626                IconButton::new(("copy-block", cx.block_id), IconName::Copy)
9627                    .icon_color(Color::Muted)
9628                    .size(ButtonSize::Compact)
9629                    .style(ButtonStyle::Transparent)
9630                    .visible_on_hover(group_id)
9631                    .on_click({
9632                        let message = diagnostic.message.clone();
9633                        move |_click, cx| cx.write_to_clipboard(ClipboardItem::new(message.clone()))
9634                    })
9635                    .tooltip(|cx| Tooltip::text("Copy diagnostic message", cx)),
9636            )
9637            .into_any_element()
9638    })
9639}
9640
9641pub fn highlight_diagnostic_message(diagnostic: &Diagnostic) -> (SharedString, Vec<Range<usize>>) {
9642    let mut text_without_backticks = String::new();
9643    let mut code_ranges = Vec::new();
9644
9645    if let Some(source) = &diagnostic.source {
9646        text_without_backticks.push_str(&source);
9647        code_ranges.push(0..source.len());
9648        text_without_backticks.push_str(": ");
9649    }
9650
9651    let mut prev_offset = 0;
9652    let mut in_code_block = false;
9653    for (ix, _) in diagnostic
9654        .message
9655        .match_indices('`')
9656        .chain([(diagnostic.message.len(), "")])
9657    {
9658        let prev_len = text_without_backticks.len();
9659        text_without_backticks.push_str(&diagnostic.message[prev_offset..ix]);
9660        prev_offset = ix + 1;
9661        if in_code_block {
9662            code_ranges.push(prev_len..text_without_backticks.len());
9663            in_code_block = false;
9664        } else {
9665            in_code_block = true;
9666        }
9667    }
9668
9669    (text_without_backticks.into(), code_ranges)
9670}
9671
9672fn diagnostic_style(severity: DiagnosticSeverity, valid: bool, colors: &StatusColors) -> Hsla {
9673    match (severity, valid) {
9674        (DiagnosticSeverity::ERROR, true) => colors.error,
9675        (DiagnosticSeverity::ERROR, false) => colors.error,
9676        (DiagnosticSeverity::WARNING, true) => colors.warning,
9677        (DiagnosticSeverity::WARNING, false) => colors.warning,
9678        (DiagnosticSeverity::INFORMATION, true) => colors.info,
9679        (DiagnosticSeverity::INFORMATION, false) => colors.info,
9680        (DiagnosticSeverity::HINT, true) => colors.info,
9681        (DiagnosticSeverity::HINT, false) => colors.info,
9682        _ => colors.ignored,
9683    }
9684}
9685
9686pub fn styled_runs_for_code_label<'a>(
9687    label: &'a CodeLabel,
9688    syntax_theme: &'a theme::SyntaxTheme,
9689) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
9690    let fade_out = HighlightStyle {
9691        fade_out: Some(0.35),
9692        ..Default::default()
9693    };
9694
9695    let mut prev_end = label.filter_range.end;
9696    label
9697        .runs
9698        .iter()
9699        .enumerate()
9700        .flat_map(move |(ix, (range, highlight_id))| {
9701            let style = if let Some(style) = highlight_id.style(syntax_theme) {
9702                style
9703            } else {
9704                return Default::default();
9705            };
9706            let mut muted_style = style;
9707            muted_style.highlight(fade_out);
9708
9709            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
9710            if range.start >= label.filter_range.end {
9711                if range.start > prev_end {
9712                    runs.push((prev_end..range.start, fade_out));
9713                }
9714                runs.push((range.clone(), muted_style));
9715            } else if range.end <= label.filter_range.end {
9716                runs.push((range.clone(), style));
9717            } else {
9718                runs.push((range.start..label.filter_range.end, style));
9719                runs.push((label.filter_range.end..range.end, muted_style));
9720            }
9721            prev_end = cmp::max(prev_end, range.end);
9722
9723            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
9724                runs.push((prev_end..label.text.len(), fade_out));
9725            }
9726
9727            runs
9728        })
9729}
9730
9731pub(crate) fn split_words<'a>(text: &'a str) -> impl std::iter::Iterator<Item = &'a str> + 'a {
9732    let mut index = 0;
9733    let mut codepoints = text.char_indices().peekable();
9734
9735    std::iter::from_fn(move || {
9736        let start_index = index;
9737        while let Some((new_index, codepoint)) = codepoints.next() {
9738            index = new_index + codepoint.len_utf8();
9739            let current_upper = codepoint.is_uppercase();
9740            let next_upper = codepoints
9741                .peek()
9742                .map(|(_, c)| c.is_uppercase())
9743                .unwrap_or(false);
9744
9745            if !current_upper && next_upper {
9746                return Some(&text[start_index..index]);
9747            }
9748        }
9749
9750        index = text.len();
9751        if start_index < text.len() {
9752            return Some(&text[start_index..]);
9753        }
9754        None
9755    })
9756    .flat_map(|word| word.split_inclusive('_'))
9757    .flat_map(|word| word.split_inclusive('-'))
9758}
9759
9760trait RangeToAnchorExt {
9761    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
9762}
9763
9764impl<T: ToOffset> RangeToAnchorExt for Range<T> {
9765    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
9766        snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
9767    }
9768}