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