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