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