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