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