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