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