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