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