editor.rs

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