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