editor.rs

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