editor.rs

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