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