editor.rs

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