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