editor.rs

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