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