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