editor.rs

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