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