editor.rs

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