editor.rs

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