editor.rs

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