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