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