editor.rs

    1#![allow(rustdoc::private_intra_doc_links)]
    2//! This is the place where everything editor-related is stored (data-wise) and displayed (ui-wise).
    3//! The main point of interest in this crate is [`Editor`] type, which is used in every other Zed part as a user input element.
    4//! It comes in different flavors: single line, multiline and a fixed height one.
    5//!
    6//! Editor contains of multiple large submodules:
    7//! * [`element`] — the place where all rendering happens
    8//! * [`display_map`] - chunks up text in the editor into the logical blocks, establishes coordinates and mapping between each of them.
    9//!   Contains all metadata related to text transformations (folds, fake inlay text insertions, soft wraps, tab markup, etc.).
   10//! * [`inlay_hint_cache`] - is a storage of inlay hints out of LSP requests, responsible for querying LSP and updating `display_map`'s state accordingly.
   11//!
   12//! All other submodules and structs are mostly concerned with holding editor data about the way it displays current buffer region(s).
   13//!
   14//! If you're looking to improve Vim mode, you should check out Vim crate that wraps Editor and overrides its behavior.
   15pub mod actions;
   16mod blink_manager;
   17mod clangd_ext;
   18pub mod code_context_menus;
   19pub mod display_map;
   20mod editor_settings;
   21mod element;
   22mod git;
   23mod highlight_matching_bracket;
   24mod hover_links;
   25pub mod hover_popover;
   26mod indent_guides;
   27mod inlay_hint_cache;
   28pub mod items;
   29mod jsx_tag_auto_close;
   30mod linked_editing_ranges;
   31mod lsp_colors;
   32mod lsp_ext;
   33mod mouse_context_menu;
   34pub mod movement;
   35mod persistence;
   36mod proposed_changes_editor;
   37mod rust_analyzer_ext;
   38pub mod scroll;
   39mod selections_collection;
   40pub mod tasks;
   41
   42#[cfg(test)]
   43mod code_completion_tests;
   44#[cfg(test)]
   45mod edit_prediction_tests;
   46#[cfg(test)]
   47mod editor_tests;
   48mod signature_help;
   49#[cfg(any(test, feature = "test-support"))]
   50pub mod test;
   51
   52pub(crate) use actions::*;
   53pub use display_map::{ChunkRenderer, ChunkRendererContext, DisplayPoint, FoldPlaceholder};
   54pub use edit_prediction::Direction;
   55pub use editor_settings::{
   56    CurrentLineHighlight, DocumentColorsRenderMode, EditorSettings, HideMouseMode,
   57    ScrollBeyondLastLine, ScrollbarAxes, SearchSettings, ShowMinimap,
   58};
   59pub use element::{
   60    CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition,
   61};
   62pub use git::blame::BlameRenderer;
   63pub use hover_popover::hover_markdown_style;
   64pub use items::MAX_TAB_TITLE_LEN;
   65pub use lsp::CompletionContext;
   66pub use lsp_ext::lsp_tasks;
   67pub use multi_buffer::{
   68    Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, PathKey,
   69    RowInfo, ToOffset, ToPoint,
   70};
   71pub use proposed_changes_editor::{
   72    ProposedChangeLocation, ProposedChangesEditor, ProposedChangesEditorToolbar,
   73};
   74pub use text::Bias;
   75
   76use ::git::{
   77    Restore,
   78    blame::{BlameEntry, ParsedCommitMessage},
   79};
   80use aho_corasick::AhoCorasick;
   81use anyhow::{Context as _, Result, anyhow};
   82use blink_manager::BlinkManager;
   83use buffer_diff::DiffHunkStatus;
   84use client::{Collaborator, ParticipantIndex, parse_zed_link};
   85use clock::ReplicaId;
   86use code_context_menus::{
   87    AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu,
   88    CompletionsMenu, ContextMenuOrigin,
   89};
   90use collections::{BTreeMap, HashMap, HashSet, VecDeque};
   91use convert_case::{Case, Casing};
   92use dap::TelemetrySpawnLocation;
   93use display_map::*;
   94use edit_prediction::{EditPredictionProvider, EditPredictionProviderHandle};
   95use editor_settings::{GoToDefinitionFallback, Minimap as MinimapSettings};
   96use element::{AcceptEditPredictionBinding, LineWithInvisibles, PositionMap, layout_line};
   97use futures::{
   98    FutureExt, StreamExt as _,
   99    future::{self, Shared, join},
  100    stream::FuturesUnordered,
  101};
  102use fuzzy::{StringMatch, StringMatchCandidate};
  103use git::blame::{GitBlame, GlobalBlameRenderer};
  104use gpui::{
  105    Action, Animation, AnimationExt, AnyElement, App, AppContext, AsyncWindowContext,
  106    AvailableSpace, Background, Bounds, ClickEvent, ClipboardEntry, ClipboardItem, Context,
  107    DispatchPhase, Edges, Entity, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent,
  108    Focusable, FontId, FontWeight, Global, HighlightStyle, Hsla, KeyContext, Modifiers,
  109    MouseButton, MouseDownEvent, PaintQuad, ParentElement, Pixels, Render, ScrollHandle,
  110    SharedString, Size, Stateful, Styled, Subscription, Task, TextStyle, TextStyleRefinement,
  111    UTF16Selection, UnderlineStyle, UniformListScrollHandle, WeakEntity, WeakFocusHandle, Window,
  112    div, point, prelude::*, pulsating_between, px, relative, size,
  113};
  114use hover_links::{HoverLink, HoveredLinkState, InlayHighlight, find_file};
  115use hover_popover::{HoverState, hide_hover};
  116use indent_guides::ActiveIndentGuidesState;
  117use inlay_hint_cache::{InlayHintCache, InlaySplice, InvalidationStrategy};
  118use itertools::{Either, Itertools};
  119use language::{
  120    AutoindentMode, BlockCommentConfig, BracketMatch, BracketPair, Buffer, BufferRow,
  121    BufferSnapshot, Capability, CharClassifier, CharKind, CharScopeContext, CodeLabel, CursorShape,
  122    DiagnosticEntryRef, DiffOptions, EditPredictionsMode, EditPreview, HighlightedText, IndentKind,
  123    IndentSize, Language, OffsetRangeExt, Point, Runnable, RunnableRange, Selection, SelectionGoal,
  124    TextObject, TransactionId, TreeSitterOptions, WordsQuery,
  125    language_settings::{
  126        self, InlayHintSettings, LspInsertMode, RewrapBehavior, WordsCompletionMode,
  127        all_language_settings, language_settings,
  128    },
  129    point_from_lsp, point_to_lsp, text_diff_with_options,
  130};
  131use linked_editing_ranges::refresh_linked_ranges;
  132use lsp::{
  133    CodeActionKind, CompletionItemKind, CompletionTriggerKind, InsertTextFormat, InsertTextMode,
  134    LanguageServerId,
  135};
  136use lsp_colors::LspColorData;
  137use markdown::Markdown;
  138use mouse_context_menu::MouseContextMenu;
  139use movement::TextLayoutDetails;
  140use multi_buffer::{
  141    ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow,
  142    ToOffsetUtf16,
  143};
  144use parking_lot::Mutex;
  145use persistence::DB;
  146use project::{
  147    BreakpointWithPosition, CodeAction, Completion, CompletionDisplayOptions, CompletionIntent,
  148    CompletionResponse, CompletionSource, DisableAiSettings, DocumentHighlight, InlayHint,
  149    Location, LocationLink, PrepareRenameResponse, Project, ProjectItem, ProjectPath,
  150    ProjectTransaction, TaskSourceKind,
  151    debugger::{
  152        breakpoint_store::{
  153            Breakpoint, BreakpointEditAction, BreakpointSessionState, BreakpointState,
  154            BreakpointStore, BreakpointStoreEvent,
  155        },
  156        session::{Session, SessionEvent},
  157    },
  158    git_store::{GitStoreEvent, RepositoryEvent},
  159    lsp_store::{CompletionDocumentation, FormatTrigger, LspFormatTarget, OpenLspBufferHandle},
  160    project_settings::{DiagnosticSeverity, GoToDiagnosticSeverityFilter, ProjectSettings},
  161};
  162use rand::seq::SliceRandom;
  163use rpc::{ErrorCode, ErrorExt, proto::PeerId};
  164use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager};
  165use selections_collection::{MutableSelectionsCollection, SelectionsCollection};
  166use serde::{Deserialize, Serialize};
  167use settings::{GitGutterSetting, Settings, SettingsLocation, SettingsStore, update_settings_file};
  168use smallvec::{SmallVec, smallvec};
  169use snippet::Snippet;
  170use std::{
  171    any::{Any, TypeId},
  172    borrow::Cow,
  173    cell::{OnceCell, RefCell},
  174    cmp::{self, Ordering, Reverse},
  175    iter::{self, Peekable},
  176    mem,
  177    num::NonZeroU32,
  178    ops::{ControlFlow, Deref, DerefMut, Not, Range, RangeInclusive},
  179    path::{Path, PathBuf},
  180    rc::Rc,
  181    sync::Arc,
  182    time::{Duration, Instant},
  183};
  184use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};
  185use text::{BufferId, FromAnchor, OffsetUtf16, Rope, ToOffset as _};
  186use theme::{
  187    ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, Theme, ThemeSettings,
  188    observe_buffer_font_size_adjustment,
  189};
  190use ui::{
  191    ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName,
  192    IconSize, Indicator, Key, Tooltip, h_flex, prelude::*, scrollbars::ScrollbarAutoHide,
  193};
  194use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};
  195use workspace::{
  196    CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, OpenInTerminal, OpenTerminal,
  197    RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection, TabBarSettings, Toast,
  198    ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  199    item::{ItemBufferKind, ItemHandle, PreviewTabsSettings, SaveOptions},
  200    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  201    searchable::SearchEvent,
  202};
  203
  204use crate::{
  205    code_context_menus::CompletionsMenuSource,
  206    editor_settings::MultiCursorModifier,
  207    hover_links::{find_url, find_url_from_range},
  208    scroll::{ScrollOffset, ScrollPixelOffset},
  209    selections_collection::resolve_selections_wrapping_blocks,
  210    signature_help::{SignatureHelpHiddenBy, SignatureHelpState},
  211};
  212
  213pub const FILE_HEADER_HEIGHT: u32 = 2;
  214pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  215const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  216const MAX_LINE_LEN: usize = 1024;
  217const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  218const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  219pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  220#[doc(hidden)]
  221pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  222pub const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  223
  224pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  225pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  226pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  227pub const FETCH_COLORS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(150);
  228
  229pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  230pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  231pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  232
  233pub type RenderDiffHunkControlsFn = Arc<
  234    dyn Fn(
  235        u32,
  236        &DiffHunkStatus,
  237        Range<Anchor>,
  238        bool,
  239        Pixels,
  240        &Entity<Editor>,
  241        &mut Window,
  242        &mut App,
  243    ) -> AnyElement,
  244>;
  245
  246enum ReportEditorEvent {
  247    Saved { auto_saved: bool },
  248    EditorOpened,
  249    Closed,
  250}
  251
  252impl ReportEditorEvent {
  253    pub fn event_type(&self) -> &'static str {
  254        match self {
  255            Self::Saved { .. } => "Editor Saved",
  256            Self::EditorOpened => "Editor Opened",
  257            Self::Closed => "Editor Closed",
  258        }
  259    }
  260}
  261
  262struct InlineValueCache {
  263    enabled: bool,
  264    inlays: Vec<InlayId>,
  265    refresh_task: Task<Option<()>>,
  266}
  267
  268impl InlineValueCache {
  269    fn new(enabled: bool) -> Self {
  270        Self {
  271            enabled,
  272            inlays: Vec::new(),
  273            refresh_task: Task::ready(None),
  274        }
  275    }
  276}
  277
  278#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
  279pub enum InlayId {
  280    EditPrediction(u32),
  281    DebuggerValue(u32),
  282    // LSP
  283    Hint(u32),
  284    Color(u32),
  285}
  286
  287impl InlayId {
  288    fn id(&self) -> u32 {
  289        match self {
  290            Self::EditPrediction(id) => *id,
  291            Self::DebuggerValue(id) => *id,
  292            Self::Hint(id) => *id,
  293            Self::Color(id) => *id,
  294        }
  295    }
  296}
  297
  298pub enum ActiveDebugLine {}
  299pub enum DebugStackFrameLine {}
  300enum DocumentHighlightRead {}
  301enum DocumentHighlightWrite {}
  302enum InputComposition {}
  303pub enum PendingInput {}
  304enum SelectedTextHighlight {}
  305
  306pub enum ConflictsOuter {}
  307pub enum ConflictsOurs {}
  308pub enum ConflictsTheirs {}
  309pub enum ConflictsOursMarker {}
  310pub enum ConflictsTheirsMarker {}
  311
  312#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  313pub enum Navigated {
  314    Yes,
  315    No,
  316}
  317
  318impl Navigated {
  319    pub fn from_bool(yes: bool) -> Navigated {
  320        if yes { Navigated::Yes } else { Navigated::No }
  321    }
  322}
  323
  324#[derive(Debug, Clone, PartialEq, Eq)]
  325enum DisplayDiffHunk {
  326    Folded {
  327        display_row: DisplayRow,
  328    },
  329    Unfolded {
  330        is_created_file: bool,
  331        diff_base_byte_range: Range<usize>,
  332        display_row_range: Range<DisplayRow>,
  333        multi_buffer_range: Range<Anchor>,
  334        status: DiffHunkStatus,
  335    },
  336}
  337
  338pub enum HideMouseCursorOrigin {
  339    TypingAction,
  340    MovementAction,
  341}
  342
  343pub fn init_settings(cx: &mut App) {
  344    EditorSettings::register(cx);
  345}
  346
  347pub fn init(cx: &mut App) {
  348    init_settings(cx);
  349
  350    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  351
  352    workspace::register_project_item::<Editor>(cx);
  353    workspace::FollowableViewRegistry::register::<Editor>(cx);
  354    workspace::register_serializable_item::<Editor>(cx);
  355
  356    cx.observe_new(
  357        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  358            workspace.register_action(Editor::new_file);
  359            workspace.register_action(Editor::new_file_split);
  360            workspace.register_action(Editor::new_file_vertical);
  361            workspace.register_action(Editor::new_file_horizontal);
  362            workspace.register_action(Editor::cancel_language_server_work);
  363            workspace.register_action(Editor::toggle_focus);
  364        },
  365    )
  366    .detach();
  367
  368    cx.on_action(move |_: &workspace::NewFile, cx| {
  369        let app_state = workspace::AppState::global(cx);
  370        if let Some(app_state) = app_state.upgrade() {
  371            workspace::open_new(
  372                Default::default(),
  373                app_state,
  374                cx,
  375                |workspace, window, cx| {
  376                    Editor::new_file(workspace, &Default::default(), window, cx)
  377                },
  378            )
  379            .detach();
  380        }
  381    });
  382    cx.on_action(move |_: &workspace::NewWindow, cx| {
  383        let app_state = workspace::AppState::global(cx);
  384        if let Some(app_state) = app_state.upgrade() {
  385            workspace::open_new(
  386                Default::default(),
  387                app_state,
  388                cx,
  389                |workspace, window, cx| {
  390                    cx.activate(true);
  391                    Editor::new_file(workspace, &Default::default(), window, cx)
  392                },
  393            )
  394            .detach();
  395        }
  396    });
  397}
  398
  399pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  400    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  401}
  402
  403pub trait DiagnosticRenderer {
  404    fn render_group(
  405        &self,
  406        diagnostic_group: Vec<DiagnosticEntryRef<'_, Point>>,
  407        buffer_id: BufferId,
  408        snapshot: EditorSnapshot,
  409        editor: WeakEntity<Editor>,
  410        cx: &mut App,
  411    ) -> Vec<BlockProperties<Anchor>>;
  412
  413    fn render_hover(
  414        &self,
  415        diagnostic_group: Vec<DiagnosticEntryRef<'_, Point>>,
  416        range: Range<Point>,
  417        buffer_id: BufferId,
  418        cx: &mut App,
  419    ) -> Option<Entity<markdown::Markdown>>;
  420
  421    fn open_link(
  422        &self,
  423        editor: &mut Editor,
  424        link: SharedString,
  425        window: &mut Window,
  426        cx: &mut Context<Editor>,
  427    );
  428}
  429
  430pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  431
  432impl GlobalDiagnosticRenderer {
  433    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  434        cx.try_global::<Self>().map(|g| g.0.clone())
  435    }
  436}
  437
  438impl gpui::Global for GlobalDiagnosticRenderer {}
  439pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  440    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  441}
  442
  443pub struct SearchWithinRange;
  444
  445trait InvalidationRegion {
  446    fn ranges(&self) -> &[Range<Anchor>];
  447}
  448
  449#[derive(Clone, Debug, PartialEq)]
  450pub enum SelectPhase {
  451    Begin {
  452        position: DisplayPoint,
  453        add: bool,
  454        click_count: usize,
  455    },
  456    BeginColumnar {
  457        position: DisplayPoint,
  458        reset: bool,
  459        mode: ColumnarMode,
  460        goal_column: u32,
  461    },
  462    Extend {
  463        position: DisplayPoint,
  464        click_count: usize,
  465    },
  466    Update {
  467        position: DisplayPoint,
  468        goal_column: u32,
  469        scroll_delta: gpui::Point<f32>,
  470    },
  471    End,
  472}
  473
  474#[derive(Clone, Debug, PartialEq)]
  475pub enum ColumnarMode {
  476    FromMouse,
  477    FromSelection,
  478}
  479
  480#[derive(Clone, Debug)]
  481pub enum SelectMode {
  482    Character,
  483    Word(Range<Anchor>),
  484    Line(Range<Anchor>),
  485    All,
  486}
  487
  488#[derive(Clone, PartialEq, Eq, Debug)]
  489pub enum EditorMode {
  490    SingleLine,
  491    AutoHeight {
  492        min_lines: usize,
  493        max_lines: Option<usize>,
  494    },
  495    Full {
  496        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  497        scale_ui_elements_with_buffer_font_size: bool,
  498        /// When set to `true`, the editor will render a background for the active line.
  499        show_active_line_background: bool,
  500        /// When set to `true`, the editor's height will be determined by its content.
  501        sized_by_content: bool,
  502    },
  503    Minimap {
  504        parent: WeakEntity<Editor>,
  505    },
  506}
  507
  508impl EditorMode {
  509    pub fn full() -> Self {
  510        Self::Full {
  511            scale_ui_elements_with_buffer_font_size: true,
  512            show_active_line_background: true,
  513            sized_by_content: false,
  514        }
  515    }
  516
  517    #[inline]
  518    pub fn is_full(&self) -> bool {
  519        matches!(self, Self::Full { .. })
  520    }
  521
  522    #[inline]
  523    pub fn is_single_line(&self) -> bool {
  524        matches!(self, Self::SingleLine { .. })
  525    }
  526
  527    #[inline]
  528    fn is_minimap(&self) -> bool {
  529        matches!(self, Self::Minimap { .. })
  530    }
  531}
  532
  533#[derive(Copy, Clone, Debug)]
  534pub enum SoftWrap {
  535    /// Prefer not to wrap at all.
  536    ///
  537    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  538    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  539    GitDiff,
  540    /// Prefer a single line generally, unless an overly long line is encountered.
  541    None,
  542    /// Soft wrap lines that exceed the editor width.
  543    EditorWidth,
  544    /// Soft wrap lines at the preferred line length.
  545    Column(u32),
  546    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  547    Bounded(u32),
  548}
  549
  550#[derive(Clone)]
  551pub struct EditorStyle {
  552    pub background: Hsla,
  553    pub border: Hsla,
  554    pub local_player: PlayerColor,
  555    pub text: TextStyle,
  556    pub scrollbar_width: Pixels,
  557    pub syntax: Arc<SyntaxTheme>,
  558    pub status: StatusColors,
  559    pub inlay_hints_style: HighlightStyle,
  560    pub edit_prediction_styles: EditPredictionStyles,
  561    pub unnecessary_code_fade: f32,
  562    pub show_underlines: bool,
  563}
  564
  565impl Default for EditorStyle {
  566    fn default() -> Self {
  567        Self {
  568            background: Hsla::default(),
  569            border: Hsla::default(),
  570            local_player: PlayerColor::default(),
  571            text: TextStyle::default(),
  572            scrollbar_width: Pixels::default(),
  573            syntax: Default::default(),
  574            // HACK: Status colors don't have a real default.
  575            // We should look into removing the status colors from the editor
  576            // style and retrieve them directly from the theme.
  577            status: StatusColors::dark(),
  578            inlay_hints_style: HighlightStyle::default(),
  579            edit_prediction_styles: EditPredictionStyles {
  580                insertion: HighlightStyle::default(),
  581                whitespace: HighlightStyle::default(),
  582            },
  583            unnecessary_code_fade: Default::default(),
  584            show_underlines: true,
  585        }
  586    }
  587}
  588
  589pub fn make_inlay_hints_style(cx: &mut App) -> HighlightStyle {
  590    let show_background = language_settings::language_settings(None, None, cx)
  591        .inlay_hints
  592        .show_background;
  593
  594    let mut style = cx.theme().syntax().get("hint");
  595
  596    if style.color.is_none() {
  597        style.color = Some(cx.theme().status().hint);
  598    }
  599
  600    if !show_background {
  601        style.background_color = None;
  602        return style;
  603    }
  604
  605    if style.background_color.is_none() {
  606        style.background_color = Some(cx.theme().status().hint_background);
  607    }
  608
  609    style
  610}
  611
  612pub fn make_suggestion_styles(cx: &mut App) -> EditPredictionStyles {
  613    EditPredictionStyles {
  614        insertion: HighlightStyle {
  615            color: Some(cx.theme().status().predictive),
  616            ..HighlightStyle::default()
  617        },
  618        whitespace: HighlightStyle {
  619            background_color: Some(cx.theme().status().created_background),
  620            ..HighlightStyle::default()
  621        },
  622    }
  623}
  624
  625type CompletionId = usize;
  626
  627pub(crate) enum EditDisplayMode {
  628    TabAccept,
  629    DiffPopover,
  630    Inline,
  631}
  632
  633enum EditPrediction {
  634    Edit {
  635        edits: Vec<(Range<Anchor>, String)>,
  636        edit_preview: Option<EditPreview>,
  637        display_mode: EditDisplayMode,
  638        snapshot: BufferSnapshot,
  639    },
  640    /// Move to a specific location in the active editor
  641    MoveWithin {
  642        target: Anchor,
  643        snapshot: BufferSnapshot,
  644    },
  645    /// Move to a specific location in a different editor (not the active one)
  646    MoveOutside {
  647        target: language::Anchor,
  648        snapshot: BufferSnapshot,
  649    },
  650}
  651
  652struct EditPredictionState {
  653    inlay_ids: Vec<InlayId>,
  654    completion: EditPrediction,
  655    completion_id: Option<SharedString>,
  656    invalidation_range: Option<Range<Anchor>>,
  657}
  658
  659enum EditPredictionSettings {
  660    Disabled,
  661    Enabled {
  662        show_in_menu: bool,
  663        preview_requires_modifier: bool,
  664    },
  665}
  666
  667enum EditPredictionHighlight {}
  668
  669#[derive(Debug, Clone)]
  670struct InlineDiagnostic {
  671    message: SharedString,
  672    group_id: usize,
  673    is_primary: bool,
  674    start: Point,
  675    severity: lsp::DiagnosticSeverity,
  676}
  677
  678pub enum MenuEditPredictionsPolicy {
  679    Never,
  680    ByProvider,
  681}
  682
  683pub enum EditPredictionPreview {
  684    /// Modifier is not pressed
  685    Inactive { released_too_fast: bool },
  686    /// Modifier pressed
  687    Active {
  688        since: Instant,
  689        previous_scroll_position: Option<ScrollAnchor>,
  690    },
  691}
  692
  693impl EditPredictionPreview {
  694    pub fn released_too_fast(&self) -> bool {
  695        match self {
  696            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  697            EditPredictionPreview::Active { .. } => false,
  698        }
  699    }
  700
  701    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  702        if let EditPredictionPreview::Active {
  703            previous_scroll_position,
  704            ..
  705        } = self
  706        {
  707            *previous_scroll_position = scroll_position;
  708        }
  709    }
  710}
  711
  712pub struct ContextMenuOptions {
  713    pub min_entries_visible: usize,
  714    pub max_entries_visible: usize,
  715    pub placement: Option<ContextMenuPlacement>,
  716}
  717
  718#[derive(Debug, Clone, PartialEq, Eq)]
  719pub enum ContextMenuPlacement {
  720    Above,
  721    Below,
  722}
  723
  724#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  725struct EditorActionId(usize);
  726
  727impl EditorActionId {
  728    pub fn post_inc(&mut self) -> Self {
  729        let answer = self.0;
  730
  731        *self = Self(answer + 1);
  732
  733        Self(answer)
  734    }
  735}
  736
  737// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  738// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  739
  740type BackgroundHighlight = (fn(&Theme) -> Hsla, Arc<[Range<Anchor>]>);
  741type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
  742
  743#[derive(Default)]
  744struct ScrollbarMarkerState {
  745    scrollbar_size: Size<Pixels>,
  746    dirty: bool,
  747    markers: Arc<[PaintQuad]>,
  748    pending_refresh: Option<Task<Result<()>>>,
  749}
  750
  751impl ScrollbarMarkerState {
  752    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  753        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  754    }
  755}
  756
  757#[derive(Clone, Copy, PartialEq, Eq)]
  758pub enum MinimapVisibility {
  759    Disabled,
  760    Enabled {
  761        /// The configuration currently present in the users settings.
  762        setting_configuration: bool,
  763        /// Whether to override the currently set visibility from the users setting.
  764        toggle_override: bool,
  765    },
  766}
  767
  768impl MinimapVisibility {
  769    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  770        if mode.is_full() {
  771            Self::Enabled {
  772                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  773                toggle_override: false,
  774            }
  775        } else {
  776            Self::Disabled
  777        }
  778    }
  779
  780    fn hidden(&self) -> Self {
  781        match *self {
  782            Self::Enabled {
  783                setting_configuration,
  784                ..
  785            } => Self::Enabled {
  786                setting_configuration,
  787                toggle_override: setting_configuration,
  788            },
  789            Self::Disabled => Self::Disabled,
  790        }
  791    }
  792
  793    fn disabled(&self) -> bool {
  794        matches!(*self, Self::Disabled)
  795    }
  796
  797    fn settings_visibility(&self) -> bool {
  798        match *self {
  799            Self::Enabled {
  800                setting_configuration,
  801                ..
  802            } => setting_configuration,
  803            _ => false,
  804        }
  805    }
  806
  807    fn visible(&self) -> bool {
  808        match *self {
  809            Self::Enabled {
  810                setting_configuration,
  811                toggle_override,
  812            } => setting_configuration ^ toggle_override,
  813            _ => false,
  814        }
  815    }
  816
  817    fn toggle_visibility(&self) -> Self {
  818        match *self {
  819            Self::Enabled {
  820                toggle_override,
  821                setting_configuration,
  822            } => Self::Enabled {
  823                setting_configuration,
  824                toggle_override: !toggle_override,
  825            },
  826            Self::Disabled => Self::Disabled,
  827        }
  828    }
  829}
  830
  831#[derive(Clone, Debug)]
  832struct RunnableTasks {
  833    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  834    offset: multi_buffer::Anchor,
  835    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  836    column: u32,
  837    // Values of all named captures, including those starting with '_'
  838    extra_variables: HashMap<String, String>,
  839    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  840    context_range: Range<BufferOffset>,
  841}
  842
  843impl RunnableTasks {
  844    fn resolve<'a>(
  845        &'a self,
  846        cx: &'a task::TaskContext,
  847    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  848        self.templates.iter().filter_map(|(kind, template)| {
  849            template
  850                .resolve_task(&kind.to_id_base(), cx)
  851                .map(|task| (kind.clone(), task))
  852        })
  853    }
  854}
  855
  856#[derive(Clone)]
  857pub struct ResolvedTasks {
  858    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  859    position: Anchor,
  860}
  861
  862#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  863struct BufferOffset(usize);
  864
  865/// Addons allow storing per-editor state in other crates (e.g. Vim)
  866pub trait Addon: 'static {
  867    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  868
  869    fn render_buffer_header_controls(
  870        &self,
  871        _: &ExcerptInfo,
  872        _: &Window,
  873        _: &App,
  874    ) -> Option<AnyElement> {
  875        None
  876    }
  877
  878    fn to_any(&self) -> &dyn std::any::Any;
  879
  880    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  881        None
  882    }
  883}
  884
  885struct ChangeLocation {
  886    current: Option<Vec<Anchor>>,
  887    original: Vec<Anchor>,
  888}
  889impl ChangeLocation {
  890    fn locations(&self) -> &[Anchor] {
  891        self.current.as_ref().unwrap_or(&self.original)
  892    }
  893}
  894
  895/// A set of caret positions, registered when the editor was edited.
  896pub struct ChangeList {
  897    changes: Vec<ChangeLocation>,
  898    /// Currently "selected" change.
  899    position: Option<usize>,
  900}
  901
  902impl ChangeList {
  903    pub fn new() -> Self {
  904        Self {
  905            changes: Vec::new(),
  906            position: None,
  907        }
  908    }
  909
  910    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  911    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  912    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  913        if self.changes.is_empty() {
  914            return None;
  915        }
  916
  917        let prev = self.position.unwrap_or(self.changes.len());
  918        let next = if direction == Direction::Prev {
  919            prev.saturating_sub(count)
  920        } else {
  921            (prev + count).min(self.changes.len() - 1)
  922        };
  923        self.position = Some(next);
  924        self.changes.get(next).map(|change| change.locations())
  925    }
  926
  927    /// Adds a new change to the list, resetting the change list position.
  928    pub fn push_to_change_list(&mut self, group: bool, new_positions: Vec<Anchor>) {
  929        self.position.take();
  930        if let Some(last) = self.changes.last_mut()
  931            && group
  932        {
  933            last.current = Some(new_positions)
  934        } else {
  935            self.changes.push(ChangeLocation {
  936                original: new_positions,
  937                current: None,
  938            });
  939        }
  940    }
  941
  942    pub fn last(&self) -> Option<&[Anchor]> {
  943        self.changes.last().map(|change| change.locations())
  944    }
  945
  946    pub fn last_before_grouping(&self) -> Option<&[Anchor]> {
  947        self.changes.last().map(|change| change.original.as_slice())
  948    }
  949
  950    pub fn invert_last_group(&mut self) {
  951        if let Some(last) = self.changes.last_mut()
  952            && let Some(current) = last.current.as_mut()
  953        {
  954            mem::swap(&mut last.original, current);
  955        }
  956    }
  957}
  958
  959#[derive(Clone)]
  960struct InlineBlamePopoverState {
  961    scroll_handle: ScrollHandle,
  962    commit_message: Option<ParsedCommitMessage>,
  963    markdown: Entity<Markdown>,
  964}
  965
  966struct InlineBlamePopover {
  967    position: gpui::Point<Pixels>,
  968    hide_task: Option<Task<()>>,
  969    popover_bounds: Option<Bounds<Pixels>>,
  970    popover_state: InlineBlamePopoverState,
  971    keyboard_grace: bool,
  972}
  973
  974enum SelectionDragState {
  975    /// State when no drag related activity is detected.
  976    None,
  977    /// State when the mouse is down on a selection that is about to be dragged.
  978    ReadyToDrag {
  979        selection: Selection<Anchor>,
  980        click_position: gpui::Point<Pixels>,
  981        mouse_down_time: Instant,
  982    },
  983    /// State when the mouse is dragging the selection in the editor.
  984    Dragging {
  985        selection: Selection<Anchor>,
  986        drop_cursor: Selection<Anchor>,
  987        hide_drop_cursor: bool,
  988    },
  989}
  990
  991enum ColumnarSelectionState {
  992    FromMouse {
  993        selection_tail: Anchor,
  994        display_point: Option<DisplayPoint>,
  995    },
  996    FromSelection {
  997        selection_tail: Anchor,
  998    },
  999}
 1000
 1001/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
 1002/// a breakpoint on them.
 1003#[derive(Clone, Copy, Debug, PartialEq, Eq)]
 1004struct PhantomBreakpointIndicator {
 1005    display_row: DisplayRow,
 1006    /// There's a small debounce between hovering over the line and showing the indicator.
 1007    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
 1008    is_active: bool,
 1009    collides_with_existing_breakpoint: bool,
 1010}
 1011
 1012/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
 1013///
 1014/// See the [module level documentation](self) for more information.
 1015pub struct Editor {
 1016    focus_handle: FocusHandle,
 1017    last_focused_descendant: Option<WeakFocusHandle>,
 1018    /// The text buffer being edited
 1019    buffer: Entity<MultiBuffer>,
 1020    /// Map of how text in the buffer should be displayed.
 1021    /// Handles soft wraps, folds, fake inlay text insertions, etc.
 1022    pub display_map: Entity<DisplayMap>,
 1023    placeholder_display_map: Option<Entity<DisplayMap>>,
 1024    pub selections: SelectionsCollection,
 1025    pub scroll_manager: ScrollManager,
 1026    /// When inline assist editors are linked, they all render cursors because
 1027    /// typing enters text into each of them, even the ones that aren't focused.
 1028    pub(crate) show_cursor_when_unfocused: bool,
 1029    columnar_selection_state: Option<ColumnarSelectionState>,
 1030    add_selections_state: Option<AddSelectionsState>,
 1031    select_next_state: Option<SelectNextState>,
 1032    select_prev_state: Option<SelectNextState>,
 1033    selection_history: SelectionHistory,
 1034    defer_selection_effects: bool,
 1035    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
 1036    autoclose_regions: Vec<AutocloseRegion>,
 1037    snippet_stack: InvalidationStack<SnippetState>,
 1038    select_syntax_node_history: SelectSyntaxNodeHistory,
 1039    ime_transaction: Option<TransactionId>,
 1040    pub diagnostics_max_severity: DiagnosticSeverity,
 1041    active_diagnostics: ActiveDiagnostic,
 1042    show_inline_diagnostics: bool,
 1043    inline_diagnostics_update: Task<()>,
 1044    inline_diagnostics_enabled: bool,
 1045    diagnostics_enabled: bool,
 1046    word_completions_enabled: bool,
 1047    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
 1048    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
 1049    hard_wrap: Option<usize>,
 1050    project: Option<Entity<Project>>,
 1051    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
 1052    completion_provider: Option<Rc<dyn CompletionProvider>>,
 1053    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 1054    blink_manager: Entity<BlinkManager>,
 1055    show_cursor_names: bool,
 1056    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1057    pub show_local_selections: bool,
 1058    mode: EditorMode,
 1059    show_breadcrumbs: bool,
 1060    show_gutter: bool,
 1061    show_scrollbars: ScrollbarAxes,
 1062    minimap_visibility: MinimapVisibility,
 1063    offset_content: bool,
 1064    disable_expand_excerpt_buttons: bool,
 1065    show_line_numbers: Option<bool>,
 1066    use_relative_line_numbers: Option<bool>,
 1067    show_git_diff_gutter: Option<bool>,
 1068    show_code_actions: Option<bool>,
 1069    show_runnables: Option<bool>,
 1070    show_breakpoints: Option<bool>,
 1071    show_wrap_guides: Option<bool>,
 1072    show_indent_guides: Option<bool>,
 1073    highlight_order: usize,
 1074    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1075    background_highlights: HashMap<HighlightKey, BackgroundHighlight>,
 1076    gutter_highlights: HashMap<TypeId, GutterHighlight>,
 1077    scrollbar_marker_state: ScrollbarMarkerState,
 1078    active_indent_guides_state: ActiveIndentGuidesState,
 1079    nav_history: Option<ItemNavHistory>,
 1080    context_menu: RefCell<Option<CodeContextMenu>>,
 1081    context_menu_options: Option<ContextMenuOptions>,
 1082    mouse_context_menu: Option<MouseContextMenu>,
 1083    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1084    inline_blame_popover: Option<InlineBlamePopover>,
 1085    inline_blame_popover_show_task: Option<Task<()>>,
 1086    signature_help_state: SignatureHelpState,
 1087    auto_signature_help: Option<bool>,
 1088    find_all_references_task_sources: Vec<Anchor>,
 1089    next_completion_id: CompletionId,
 1090    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1091    code_actions_task: Option<Task<Result<()>>>,
 1092    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1093    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1094    document_highlights_task: Option<Task<()>>,
 1095    linked_editing_range_task: Option<Task<Option<()>>>,
 1096    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1097    pending_rename: Option<RenameState>,
 1098    searchable: bool,
 1099    cursor_shape: CursorShape,
 1100    current_line_highlight: Option<CurrentLineHighlight>,
 1101    collapse_matches: bool,
 1102    autoindent_mode: Option<AutoindentMode>,
 1103    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1104    input_enabled: bool,
 1105    use_modal_editing: bool,
 1106    read_only: bool,
 1107    leader_id: Option<CollaboratorId>,
 1108    remote_id: Option<ViewId>,
 1109    pub hover_state: HoverState,
 1110    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1111    gutter_hovered: bool,
 1112    hovered_link_state: Option<HoveredLinkState>,
 1113    edit_prediction_provider: Option<RegisteredEditPredictionProvider>,
 1114    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1115    active_edit_prediction: Option<EditPredictionState>,
 1116    /// Used to prevent flickering as the user types while the menu is open
 1117    stale_edit_prediction_in_menu: Option<EditPredictionState>,
 1118    edit_prediction_settings: EditPredictionSettings,
 1119    edit_predictions_hidden_for_vim_mode: bool,
 1120    show_edit_predictions_override: Option<bool>,
 1121    menu_edit_predictions_policy: MenuEditPredictionsPolicy,
 1122    edit_prediction_preview: EditPredictionPreview,
 1123    edit_prediction_indent_conflict: bool,
 1124    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1125    inlay_hint_cache: InlayHintCache,
 1126    next_inlay_id: u32,
 1127    next_color_inlay_id: u32,
 1128    _subscriptions: Vec<Subscription>,
 1129    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1130    gutter_dimensions: GutterDimensions,
 1131    style: Option<EditorStyle>,
 1132    text_style_refinement: Option<TextStyleRefinement>,
 1133    next_editor_action_id: EditorActionId,
 1134    editor_actions: Rc<
 1135        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1136    >,
 1137    use_autoclose: bool,
 1138    use_auto_surround: bool,
 1139    auto_replace_emoji_shortcode: bool,
 1140    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1141    show_git_blame_gutter: bool,
 1142    show_git_blame_inline: bool,
 1143    show_git_blame_inline_delay_task: Option<Task<()>>,
 1144    git_blame_inline_enabled: bool,
 1145    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1146    serialize_dirty_buffers: bool,
 1147    show_selection_menu: Option<bool>,
 1148    blame: Option<Entity<GitBlame>>,
 1149    blame_subscription: Option<Subscription>,
 1150    custom_context_menu: Option<
 1151        Box<
 1152            dyn 'static
 1153                + Fn(
 1154                    &mut Self,
 1155                    DisplayPoint,
 1156                    &mut Window,
 1157                    &mut Context<Self>,
 1158                ) -> Option<Entity<ui::ContextMenu>>,
 1159        >,
 1160    >,
 1161    last_bounds: Option<Bounds<Pixels>>,
 1162    last_position_map: Option<Rc<PositionMap>>,
 1163    expect_bounds_change: Option<Bounds<Pixels>>,
 1164    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1165    tasks_update_task: Option<Task<()>>,
 1166    breakpoint_store: Option<Entity<BreakpointStore>>,
 1167    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1168    hovered_diff_hunk_row: Option<DisplayRow>,
 1169    pull_diagnostics_task: Task<()>,
 1170    in_project_search: bool,
 1171    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1172    breadcrumb_header: Option<String>,
 1173    focused_block: Option<FocusedBlock>,
 1174    next_scroll_position: NextScrollCursorCenterTopBottom,
 1175    addons: HashMap<TypeId, Box<dyn Addon>>,
 1176    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1177    load_diff_task: Option<Shared<Task<()>>>,
 1178    /// Whether we are temporarily displaying a diff other than git's
 1179    temporary_diff_override: bool,
 1180    selection_mark_mode: bool,
 1181    toggle_fold_multiple_buffers: Task<()>,
 1182    _scroll_cursor_center_top_bottom_task: Task<()>,
 1183    serialize_selections: Task<()>,
 1184    serialize_folds: Task<()>,
 1185    mouse_cursor_hidden: bool,
 1186    minimap: Option<Entity<Self>>,
 1187    hide_mouse_mode: HideMouseMode,
 1188    pub change_list: ChangeList,
 1189    inline_value_cache: InlineValueCache,
 1190    selection_drag_state: SelectionDragState,
 1191    colors: Option<LspColorData>,
 1192    post_scroll_update: Task<()>,
 1193    refresh_colors_task: Task<()>,
 1194    folding_newlines: Task<()>,
 1195    pub lookup_key: Option<Box<dyn Any + Send + Sync>>,
 1196}
 1197
 1198#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1199enum NextScrollCursorCenterTopBottom {
 1200    #[default]
 1201    Center,
 1202    Top,
 1203    Bottom,
 1204}
 1205
 1206impl NextScrollCursorCenterTopBottom {
 1207    fn next(&self) -> Self {
 1208        match self {
 1209            Self::Center => Self::Top,
 1210            Self::Top => Self::Bottom,
 1211            Self::Bottom => Self::Center,
 1212        }
 1213    }
 1214}
 1215
 1216#[derive(Clone)]
 1217pub struct EditorSnapshot {
 1218    pub mode: EditorMode,
 1219    show_gutter: bool,
 1220    show_line_numbers: Option<bool>,
 1221    show_git_diff_gutter: Option<bool>,
 1222    show_code_actions: Option<bool>,
 1223    show_runnables: Option<bool>,
 1224    show_breakpoints: Option<bool>,
 1225    git_blame_gutter_max_author_length: Option<usize>,
 1226    pub display_snapshot: DisplaySnapshot,
 1227    pub placeholder_display_snapshot: Option<DisplaySnapshot>,
 1228    is_focused: bool,
 1229    scroll_anchor: ScrollAnchor,
 1230    ongoing_scroll: OngoingScroll,
 1231    current_line_highlight: CurrentLineHighlight,
 1232    gutter_hovered: bool,
 1233}
 1234
 1235#[derive(Default, Debug, Clone, Copy)]
 1236pub struct GutterDimensions {
 1237    pub left_padding: Pixels,
 1238    pub right_padding: Pixels,
 1239    pub width: Pixels,
 1240    pub margin: Pixels,
 1241    pub git_blame_entries_width: Option<Pixels>,
 1242}
 1243
 1244impl GutterDimensions {
 1245    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1246        Self {
 1247            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1248            ..Default::default()
 1249        }
 1250    }
 1251
 1252    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1253        -cx.text_system().descent(font_id, font_size)
 1254    }
 1255    /// The full width of the space taken up by the gutter.
 1256    pub fn full_width(&self) -> Pixels {
 1257        self.margin + self.width
 1258    }
 1259
 1260    /// The width of the space reserved for the fold indicators,
 1261    /// use alongside 'justify_end' and `gutter_width` to
 1262    /// right align content with the line numbers
 1263    pub fn fold_area_width(&self) -> Pixels {
 1264        self.margin + self.right_padding
 1265    }
 1266}
 1267
 1268struct CharacterDimensions {
 1269    em_width: Pixels,
 1270    em_advance: Pixels,
 1271    line_height: Pixels,
 1272}
 1273
 1274#[derive(Debug)]
 1275pub struct RemoteSelection {
 1276    pub replica_id: ReplicaId,
 1277    pub selection: Selection<Anchor>,
 1278    pub cursor_shape: CursorShape,
 1279    pub collaborator_id: CollaboratorId,
 1280    pub line_mode: bool,
 1281    pub user_name: Option<SharedString>,
 1282    pub color: PlayerColor,
 1283}
 1284
 1285#[derive(Clone, Debug)]
 1286struct SelectionHistoryEntry {
 1287    selections: Arc<[Selection<Anchor>]>,
 1288    select_next_state: Option<SelectNextState>,
 1289    select_prev_state: Option<SelectNextState>,
 1290    add_selections_state: Option<AddSelectionsState>,
 1291}
 1292
 1293#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 1294enum SelectionHistoryMode {
 1295    Normal,
 1296    Undoing,
 1297    Redoing,
 1298    Skipping,
 1299}
 1300
 1301#[derive(Clone, PartialEq, Eq, Hash)]
 1302struct HoveredCursor {
 1303    replica_id: ReplicaId,
 1304    selection_id: usize,
 1305}
 1306
 1307impl Default for SelectionHistoryMode {
 1308    fn default() -> Self {
 1309        Self::Normal
 1310    }
 1311}
 1312
 1313#[derive(Debug)]
 1314/// SelectionEffects controls the side-effects of updating the selection.
 1315///
 1316/// The default behaviour does "what you mostly want":
 1317/// - it pushes to the nav history if the cursor moved by >10 lines
 1318/// - it re-triggers completion requests
 1319/// - it scrolls to fit
 1320///
 1321/// You might want to modify these behaviours. For example when doing a "jump"
 1322/// like go to definition, we always want to add to nav history; but when scrolling
 1323/// in vim mode we never do.
 1324///
 1325/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1326/// move.
 1327#[derive(Clone)]
 1328pub struct SelectionEffects {
 1329    nav_history: Option<bool>,
 1330    completions: bool,
 1331    scroll: Option<Autoscroll>,
 1332}
 1333
 1334impl Default for SelectionEffects {
 1335    fn default() -> Self {
 1336        Self {
 1337            nav_history: None,
 1338            completions: true,
 1339            scroll: Some(Autoscroll::fit()),
 1340        }
 1341    }
 1342}
 1343impl SelectionEffects {
 1344    pub fn scroll(scroll: Autoscroll) -> Self {
 1345        Self {
 1346            scroll: Some(scroll),
 1347            ..Default::default()
 1348        }
 1349    }
 1350
 1351    pub fn no_scroll() -> Self {
 1352        Self {
 1353            scroll: None,
 1354            ..Default::default()
 1355        }
 1356    }
 1357
 1358    pub fn completions(self, completions: bool) -> Self {
 1359        Self {
 1360            completions,
 1361            ..self
 1362        }
 1363    }
 1364
 1365    pub fn nav_history(self, nav_history: bool) -> Self {
 1366        Self {
 1367            nav_history: Some(nav_history),
 1368            ..self
 1369        }
 1370    }
 1371}
 1372
 1373struct DeferredSelectionEffectsState {
 1374    changed: bool,
 1375    effects: SelectionEffects,
 1376    old_cursor_position: Anchor,
 1377    history_entry: SelectionHistoryEntry,
 1378}
 1379
 1380#[derive(Default)]
 1381struct SelectionHistory {
 1382    #[allow(clippy::type_complexity)]
 1383    selections_by_transaction:
 1384        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1385    mode: SelectionHistoryMode,
 1386    undo_stack: VecDeque<SelectionHistoryEntry>,
 1387    redo_stack: VecDeque<SelectionHistoryEntry>,
 1388}
 1389
 1390impl SelectionHistory {
 1391    #[track_caller]
 1392    fn insert_transaction(
 1393        &mut self,
 1394        transaction_id: TransactionId,
 1395        selections: Arc<[Selection<Anchor>]>,
 1396    ) {
 1397        if selections.is_empty() {
 1398            log::error!(
 1399                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1400                std::panic::Location::caller()
 1401            );
 1402            return;
 1403        }
 1404        self.selections_by_transaction
 1405            .insert(transaction_id, (selections, None));
 1406    }
 1407
 1408    #[allow(clippy::type_complexity)]
 1409    fn transaction(
 1410        &self,
 1411        transaction_id: TransactionId,
 1412    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1413        self.selections_by_transaction.get(&transaction_id)
 1414    }
 1415
 1416    #[allow(clippy::type_complexity)]
 1417    fn transaction_mut(
 1418        &mut self,
 1419        transaction_id: TransactionId,
 1420    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1421        self.selections_by_transaction.get_mut(&transaction_id)
 1422    }
 1423
 1424    fn push(&mut self, entry: SelectionHistoryEntry) {
 1425        if !entry.selections.is_empty() {
 1426            match self.mode {
 1427                SelectionHistoryMode::Normal => {
 1428                    self.push_undo(entry);
 1429                    self.redo_stack.clear();
 1430                }
 1431                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1432                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1433                SelectionHistoryMode::Skipping => {}
 1434            }
 1435        }
 1436    }
 1437
 1438    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1439        if self
 1440            .undo_stack
 1441            .back()
 1442            .is_none_or(|e| e.selections != entry.selections)
 1443        {
 1444            self.undo_stack.push_back(entry);
 1445            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1446                self.undo_stack.pop_front();
 1447            }
 1448        }
 1449    }
 1450
 1451    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1452        if self
 1453            .redo_stack
 1454            .back()
 1455            .is_none_or(|e| e.selections != entry.selections)
 1456        {
 1457            self.redo_stack.push_back(entry);
 1458            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1459                self.redo_stack.pop_front();
 1460            }
 1461        }
 1462    }
 1463}
 1464
 1465#[derive(Clone, Copy)]
 1466pub struct RowHighlightOptions {
 1467    pub autoscroll: bool,
 1468    pub include_gutter: bool,
 1469}
 1470
 1471impl Default for RowHighlightOptions {
 1472    fn default() -> Self {
 1473        Self {
 1474            autoscroll: Default::default(),
 1475            include_gutter: true,
 1476        }
 1477    }
 1478}
 1479
 1480struct RowHighlight {
 1481    index: usize,
 1482    range: Range<Anchor>,
 1483    color: Hsla,
 1484    options: RowHighlightOptions,
 1485    type_id: TypeId,
 1486}
 1487
 1488#[derive(Clone, Debug)]
 1489struct AddSelectionsState {
 1490    groups: Vec<AddSelectionsGroup>,
 1491}
 1492
 1493#[derive(Clone, Debug)]
 1494struct AddSelectionsGroup {
 1495    above: bool,
 1496    stack: Vec<usize>,
 1497}
 1498
 1499#[derive(Clone)]
 1500struct SelectNextState {
 1501    query: AhoCorasick,
 1502    wordwise: bool,
 1503    done: bool,
 1504}
 1505
 1506impl std::fmt::Debug for SelectNextState {
 1507    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1508        f.debug_struct(std::any::type_name::<Self>())
 1509            .field("wordwise", &self.wordwise)
 1510            .field("done", &self.done)
 1511            .finish()
 1512    }
 1513}
 1514
 1515#[derive(Debug)]
 1516struct AutocloseRegion {
 1517    selection_id: usize,
 1518    range: Range<Anchor>,
 1519    pair: BracketPair,
 1520}
 1521
 1522#[derive(Debug)]
 1523struct SnippetState {
 1524    ranges: Vec<Vec<Range<Anchor>>>,
 1525    active_index: usize,
 1526    choices: Vec<Option<Vec<String>>>,
 1527}
 1528
 1529#[doc(hidden)]
 1530pub struct RenameState {
 1531    pub range: Range<Anchor>,
 1532    pub old_name: Arc<str>,
 1533    pub editor: Entity<Editor>,
 1534    block_id: CustomBlockId,
 1535}
 1536
 1537struct InvalidationStack<T>(Vec<T>);
 1538
 1539struct RegisteredEditPredictionProvider {
 1540    provider: Arc<dyn EditPredictionProviderHandle>,
 1541    _subscription: Subscription,
 1542}
 1543
 1544#[derive(Debug, PartialEq, Eq)]
 1545pub struct ActiveDiagnosticGroup {
 1546    pub active_range: Range<Anchor>,
 1547    pub active_message: String,
 1548    pub group_id: usize,
 1549    pub blocks: HashSet<CustomBlockId>,
 1550}
 1551
 1552#[derive(Debug, PartialEq, Eq)]
 1553
 1554pub(crate) enum ActiveDiagnostic {
 1555    None,
 1556    All,
 1557    Group(ActiveDiagnosticGroup),
 1558}
 1559
 1560#[derive(Serialize, Deserialize, Clone, Debug)]
 1561pub struct ClipboardSelection {
 1562    /// The number of bytes in this selection.
 1563    pub len: usize,
 1564    /// Whether this was a full-line selection.
 1565    pub is_entire_line: bool,
 1566    /// The indentation of the first line when this content was originally copied.
 1567    pub first_line_indent: u32,
 1568}
 1569
 1570// selections, scroll behavior, was newest selection reversed
 1571type SelectSyntaxNodeHistoryState = (
 1572    Box<[Selection<usize>]>,
 1573    SelectSyntaxNodeScrollBehavior,
 1574    bool,
 1575);
 1576
 1577#[derive(Default)]
 1578struct SelectSyntaxNodeHistory {
 1579    stack: Vec<SelectSyntaxNodeHistoryState>,
 1580    // disable temporarily to allow changing selections without losing the stack
 1581    pub disable_clearing: bool,
 1582}
 1583
 1584impl SelectSyntaxNodeHistory {
 1585    pub fn try_clear(&mut self) {
 1586        if !self.disable_clearing {
 1587            self.stack.clear();
 1588        }
 1589    }
 1590
 1591    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1592        self.stack.push(selection);
 1593    }
 1594
 1595    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1596        self.stack.pop()
 1597    }
 1598}
 1599
 1600enum SelectSyntaxNodeScrollBehavior {
 1601    CursorTop,
 1602    FitSelection,
 1603    CursorBottom,
 1604}
 1605
 1606#[derive(Debug)]
 1607pub(crate) struct NavigationData {
 1608    cursor_anchor: Anchor,
 1609    cursor_position: Point,
 1610    scroll_anchor: ScrollAnchor,
 1611    scroll_top_row: u32,
 1612}
 1613
 1614#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1615pub enum GotoDefinitionKind {
 1616    Symbol,
 1617    Declaration,
 1618    Type,
 1619    Implementation,
 1620}
 1621
 1622#[derive(Debug, Clone)]
 1623enum InlayHintRefreshReason {
 1624    ModifiersChanged(bool),
 1625    Toggle(bool),
 1626    SettingsChange(InlayHintSettings),
 1627    NewLinesShown,
 1628    BufferEdited(HashSet<Arc<Language>>),
 1629    RefreshRequested,
 1630    ExcerptsRemoved(Vec<ExcerptId>),
 1631}
 1632
 1633impl InlayHintRefreshReason {
 1634    fn description(&self) -> &'static str {
 1635        match self {
 1636            Self::ModifiersChanged(_) => "modifiers changed",
 1637            Self::Toggle(_) => "toggle",
 1638            Self::SettingsChange(_) => "settings change",
 1639            Self::NewLinesShown => "new lines shown",
 1640            Self::BufferEdited(_) => "buffer edited",
 1641            Self::RefreshRequested => "refresh requested",
 1642            Self::ExcerptsRemoved(_) => "excerpts removed",
 1643        }
 1644    }
 1645}
 1646
 1647pub enum FormatTarget {
 1648    Buffers(HashSet<Entity<Buffer>>),
 1649    Ranges(Vec<Range<MultiBufferPoint>>),
 1650}
 1651
 1652pub(crate) struct FocusedBlock {
 1653    id: BlockId,
 1654    focus_handle: WeakFocusHandle,
 1655}
 1656
 1657#[derive(Clone)]
 1658enum JumpData {
 1659    MultiBufferRow {
 1660        row: MultiBufferRow,
 1661        line_offset_from_top: u32,
 1662    },
 1663    MultiBufferPoint {
 1664        excerpt_id: ExcerptId,
 1665        position: Point,
 1666        anchor: text::Anchor,
 1667        line_offset_from_top: u32,
 1668    },
 1669}
 1670
 1671pub enum MultibufferSelectionMode {
 1672    First,
 1673    All,
 1674}
 1675
 1676#[derive(Clone, Copy, Debug, Default)]
 1677pub struct RewrapOptions {
 1678    pub override_language_settings: bool,
 1679    pub preserve_existing_whitespace: bool,
 1680}
 1681
 1682impl Editor {
 1683    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1684        let buffer = cx.new(|cx| Buffer::local("", cx));
 1685        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1686        Self::new(EditorMode::SingleLine, buffer, None, window, cx)
 1687    }
 1688
 1689    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1690        let buffer = cx.new(|cx| Buffer::local("", cx));
 1691        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1692        Self::new(EditorMode::full(), buffer, None, window, cx)
 1693    }
 1694
 1695    pub fn auto_height(
 1696        min_lines: usize,
 1697        max_lines: usize,
 1698        window: &mut Window,
 1699        cx: &mut Context<Self>,
 1700    ) -> Self {
 1701        let buffer = cx.new(|cx| Buffer::local("", cx));
 1702        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1703        Self::new(
 1704            EditorMode::AutoHeight {
 1705                min_lines,
 1706                max_lines: Some(max_lines),
 1707            },
 1708            buffer,
 1709            None,
 1710            window,
 1711            cx,
 1712        )
 1713    }
 1714
 1715    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1716    /// The editor grows as tall as needed to fit its content.
 1717    pub fn auto_height_unbounded(
 1718        min_lines: usize,
 1719        window: &mut Window,
 1720        cx: &mut Context<Self>,
 1721    ) -> Self {
 1722        let buffer = cx.new(|cx| Buffer::local("", cx));
 1723        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1724        Self::new(
 1725            EditorMode::AutoHeight {
 1726                min_lines,
 1727                max_lines: None,
 1728            },
 1729            buffer,
 1730            None,
 1731            window,
 1732            cx,
 1733        )
 1734    }
 1735
 1736    pub fn for_buffer(
 1737        buffer: Entity<Buffer>,
 1738        project: Option<Entity<Project>>,
 1739        window: &mut Window,
 1740        cx: &mut Context<Self>,
 1741    ) -> Self {
 1742        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1743        Self::new(EditorMode::full(), buffer, project, window, cx)
 1744    }
 1745
 1746    pub fn for_multibuffer(
 1747        buffer: Entity<MultiBuffer>,
 1748        project: Option<Entity<Project>>,
 1749        window: &mut Window,
 1750        cx: &mut Context<Self>,
 1751    ) -> Self {
 1752        Self::new(EditorMode::full(), buffer, project, window, cx)
 1753    }
 1754
 1755    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1756        let mut clone = Self::new(
 1757            self.mode.clone(),
 1758            self.buffer.clone(),
 1759            self.project.clone(),
 1760            window,
 1761            cx,
 1762        );
 1763        self.display_map.update(cx, |display_map, cx| {
 1764            let snapshot = display_map.snapshot(cx);
 1765            clone.display_map.update(cx, |display_map, cx| {
 1766                display_map.set_state(&snapshot, cx);
 1767            });
 1768        });
 1769        clone.folds_did_change(cx);
 1770        clone.selections.clone_state(&self.selections);
 1771        clone.scroll_manager.clone_state(&self.scroll_manager);
 1772        clone.searchable = self.searchable;
 1773        clone.read_only = self.read_only;
 1774        clone
 1775    }
 1776
 1777    pub fn new(
 1778        mode: EditorMode,
 1779        buffer: Entity<MultiBuffer>,
 1780        project: Option<Entity<Project>>,
 1781        window: &mut Window,
 1782        cx: &mut Context<Self>,
 1783    ) -> Self {
 1784        Editor::new_internal(mode, buffer, project, None, window, cx)
 1785    }
 1786
 1787    fn new_internal(
 1788        mode: EditorMode,
 1789        multi_buffer: Entity<MultiBuffer>,
 1790        project: Option<Entity<Project>>,
 1791        display_map: Option<Entity<DisplayMap>>,
 1792        window: &mut Window,
 1793        cx: &mut Context<Self>,
 1794    ) -> Self {
 1795        debug_assert!(
 1796            display_map.is_none() || mode.is_minimap(),
 1797            "Providing a display map for a new editor is only intended for the minimap and might have unintended side effects otherwise!"
 1798        );
 1799
 1800        let full_mode = mode.is_full();
 1801        let is_minimap = mode.is_minimap();
 1802        let diagnostics_max_severity = if full_mode {
 1803            EditorSettings::get_global(cx)
 1804                .diagnostics_max_severity
 1805                .unwrap_or(DiagnosticSeverity::Hint)
 1806        } else {
 1807            DiagnosticSeverity::Off
 1808        };
 1809        let style = window.text_style();
 1810        let font_size = style.font_size.to_pixels(window.rem_size());
 1811        let editor = cx.entity().downgrade();
 1812        let fold_placeholder = FoldPlaceholder {
 1813            constrain_width: false,
 1814            render: Arc::new(move |fold_id, fold_range, cx| {
 1815                let editor = editor.clone();
 1816                div()
 1817                    .id(fold_id)
 1818                    .bg(cx.theme().colors().ghost_element_background)
 1819                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1820                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1821                    .rounded_xs()
 1822                    .size_full()
 1823                    .cursor_pointer()
 1824                    .child("")
 1825                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1826                    .on_click(move |_, _window, cx| {
 1827                        editor
 1828                            .update(cx, |editor, cx| {
 1829                                editor.unfold_ranges(
 1830                                    &[fold_range.start..fold_range.end],
 1831                                    true,
 1832                                    false,
 1833                                    cx,
 1834                                );
 1835                                cx.stop_propagation();
 1836                            })
 1837                            .ok();
 1838                    })
 1839                    .into_any()
 1840            }),
 1841            merge_adjacent: true,
 1842            ..FoldPlaceholder::default()
 1843        };
 1844        let display_map = display_map.unwrap_or_else(|| {
 1845            cx.new(|cx| {
 1846                DisplayMap::new(
 1847                    multi_buffer.clone(),
 1848                    style.font(),
 1849                    font_size,
 1850                    None,
 1851                    FILE_HEADER_HEIGHT,
 1852                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1853                    fold_placeholder,
 1854                    diagnostics_max_severity,
 1855                    cx,
 1856                )
 1857            })
 1858        });
 1859
 1860        let selections = SelectionsCollection::new(display_map.clone(), multi_buffer.clone());
 1861
 1862        let blink_manager = cx.new(|cx| {
 1863            let mut blink_manager = BlinkManager::new(CURSOR_BLINK_INTERVAL, cx);
 1864            if is_minimap {
 1865                blink_manager.disable(cx);
 1866            }
 1867            blink_manager
 1868        });
 1869
 1870        let soft_wrap_mode_override =
 1871            matches!(mode, EditorMode::SingleLine).then(|| language_settings::SoftWrap::None);
 1872
 1873        let mut project_subscriptions = Vec::new();
 1874        if full_mode && let Some(project) = project.as_ref() {
 1875            project_subscriptions.push(cx.subscribe_in(
 1876                project,
 1877                window,
 1878                |editor, _, event, window, cx| match event {
 1879                    project::Event::RefreshCodeLens => {
 1880                        // we always query lens with actions, without storing them, always refreshing them
 1881                    }
 1882                    project::Event::RefreshInlayHints => {
 1883                        editor.refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1884                    }
 1885                    project::Event::LanguageServerRemoved(..) => {
 1886                        if editor.tasks_update_task.is_none() {
 1887                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1888                        }
 1889                        editor.registered_buffers.clear();
 1890                        editor.register_visible_buffers(cx);
 1891                    }
 1892                    project::Event::LanguageServerAdded(..) => {
 1893                        if editor.tasks_update_task.is_none() {
 1894                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1895                        }
 1896                    }
 1897                    project::Event::SnippetEdit(id, snippet_edits) => {
 1898                        if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1899                            let focus_handle = editor.focus_handle(cx);
 1900                            if focus_handle.is_focused(window) {
 1901                                let snapshot = buffer.read(cx).snapshot();
 1902                                for (range, snippet) in snippet_edits {
 1903                                    let editor_range =
 1904                                        language::range_from_lsp(*range).to_offset(&snapshot);
 1905                                    editor
 1906                                        .insert_snippet(
 1907                                            &[editor_range],
 1908                                            snippet.clone(),
 1909                                            window,
 1910                                            cx,
 1911                                        )
 1912                                        .ok();
 1913                                }
 1914                            }
 1915                        }
 1916                    }
 1917                    project::Event::LanguageServerBufferRegistered { buffer_id, .. } => {
 1918                        let buffer_id = *buffer_id;
 1919                        if editor.buffer().read(cx).buffer(buffer_id).is_some() {
 1920                            let registered = editor.register_buffer(buffer_id, cx);
 1921                            if registered {
 1922                                editor.update_lsp_data(Some(buffer_id), window, cx);
 1923                                editor.refresh_inlay_hints(
 1924                                    InlayHintRefreshReason::RefreshRequested,
 1925                                    cx,
 1926                                );
 1927                                refresh_linked_ranges(editor, window, cx);
 1928                                editor.refresh_code_actions(window, cx);
 1929                                editor.refresh_document_highlights(cx);
 1930                            }
 1931                        }
 1932                    }
 1933
 1934                    project::Event::EntryRenamed(transaction) => {
 1935                        let Some(workspace) = editor.workspace() else {
 1936                            return;
 1937                        };
 1938                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 1939                        else {
 1940                            return;
 1941                        };
 1942                        if active_editor.entity_id() == cx.entity_id() {
 1943                            let edited_buffers_already_open = {
 1944                                let other_editors: Vec<Entity<Editor>> = workspace
 1945                                    .read(cx)
 1946                                    .panes()
 1947                                    .iter()
 1948                                    .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
 1949                                    .filter(|editor| editor.entity_id() != cx.entity_id())
 1950                                    .collect();
 1951
 1952                                transaction.0.keys().all(|buffer| {
 1953                                    other_editors.iter().any(|editor| {
 1954                                        let multi_buffer = editor.read(cx).buffer();
 1955                                        multi_buffer.read(cx).is_singleton()
 1956                                            && multi_buffer.read(cx).as_singleton().map_or(
 1957                                                false,
 1958                                                |singleton| {
 1959                                                    singleton.entity_id() == buffer.entity_id()
 1960                                                },
 1961                                            )
 1962                                    })
 1963                                })
 1964                            };
 1965
 1966                            if !edited_buffers_already_open {
 1967                                let workspace = workspace.downgrade();
 1968                                let transaction = transaction.clone();
 1969                                cx.defer_in(window, move |_, window, cx| {
 1970                                    cx.spawn_in(window, async move |editor, cx| {
 1971                                        Self::open_project_transaction(
 1972                                            &editor,
 1973                                            workspace,
 1974                                            transaction,
 1975                                            "Rename".to_string(),
 1976                                            cx,
 1977                                        )
 1978                                        .await
 1979                                        .ok()
 1980                                    })
 1981                                    .detach();
 1982                                });
 1983                            }
 1984                        }
 1985                    }
 1986
 1987                    _ => {}
 1988                },
 1989            ));
 1990            if let Some(task_inventory) = project
 1991                .read(cx)
 1992                .task_store()
 1993                .read(cx)
 1994                .task_inventory()
 1995                .cloned()
 1996            {
 1997                project_subscriptions.push(cx.observe_in(
 1998                    &task_inventory,
 1999                    window,
 2000                    |editor, _, window, cx| {
 2001                        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2002                    },
 2003                ));
 2004            };
 2005
 2006            project_subscriptions.push(cx.subscribe_in(
 2007                &project.read(cx).breakpoint_store(),
 2008                window,
 2009                |editor, _, event, window, cx| match event {
 2010                    BreakpointStoreEvent::ClearDebugLines => {
 2011                        editor.clear_row_highlights::<ActiveDebugLine>();
 2012                        editor.refresh_inline_values(cx);
 2013                    }
 2014                    BreakpointStoreEvent::SetDebugLine => {
 2015                        if editor.go_to_active_debug_line(window, cx) {
 2016                            cx.stop_propagation();
 2017                        }
 2018
 2019                        editor.refresh_inline_values(cx);
 2020                    }
 2021                    _ => {}
 2022                },
 2023            ));
 2024            let git_store = project.read(cx).git_store().clone();
 2025            let project = project.clone();
 2026            project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 2027                if let GitStoreEvent::RepositoryUpdated(
 2028                    _,
 2029                    RepositoryEvent::Updated {
 2030                        new_instance: true, ..
 2031                    },
 2032                    _,
 2033                ) = event
 2034                {
 2035                    this.load_diff_task = Some(
 2036                        update_uncommitted_diff_for_buffer(
 2037                            cx.entity(),
 2038                            &project,
 2039                            this.buffer.read(cx).all_buffers(),
 2040                            this.buffer.clone(),
 2041                            cx,
 2042                        )
 2043                        .shared(),
 2044                    );
 2045                }
 2046            }));
 2047        }
 2048
 2049        let buffer_snapshot = multi_buffer.read(cx).snapshot(cx);
 2050
 2051        let inlay_hint_settings =
 2052            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 2053        let focus_handle = cx.focus_handle();
 2054        if !is_minimap {
 2055            cx.on_focus(&focus_handle, window, Self::handle_focus)
 2056                .detach();
 2057            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 2058                .detach();
 2059            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 2060                .detach();
 2061            cx.on_blur(&focus_handle, window, Self::handle_blur)
 2062                .detach();
 2063            cx.observe_pending_input(window, Self::observe_pending_input)
 2064                .detach();
 2065        }
 2066
 2067        let show_indent_guides =
 2068            if matches!(mode, EditorMode::SingleLine | EditorMode::Minimap { .. }) {
 2069                Some(false)
 2070            } else {
 2071                None
 2072            };
 2073
 2074        let breakpoint_store = match (&mode, project.as_ref()) {
 2075            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 2076            _ => None,
 2077        };
 2078
 2079        let mut code_action_providers = Vec::new();
 2080        let mut load_uncommitted_diff = None;
 2081        if let Some(project) = project.clone() {
 2082            load_uncommitted_diff = Some(
 2083                update_uncommitted_diff_for_buffer(
 2084                    cx.entity(),
 2085                    &project,
 2086                    multi_buffer.read(cx).all_buffers(),
 2087                    multi_buffer.clone(),
 2088                    cx,
 2089                )
 2090                .shared(),
 2091            );
 2092            code_action_providers.push(Rc::new(project) as Rc<_>);
 2093        }
 2094
 2095        let mut editor = Self {
 2096            focus_handle,
 2097            show_cursor_when_unfocused: false,
 2098            last_focused_descendant: None,
 2099            buffer: multi_buffer.clone(),
 2100            display_map: display_map.clone(),
 2101            placeholder_display_map: None,
 2102            selections,
 2103            scroll_manager: ScrollManager::new(cx),
 2104            columnar_selection_state: None,
 2105            add_selections_state: None,
 2106            select_next_state: None,
 2107            select_prev_state: None,
 2108            selection_history: SelectionHistory::default(),
 2109            defer_selection_effects: false,
 2110            deferred_selection_effects_state: None,
 2111            autoclose_regions: Vec::new(),
 2112            snippet_stack: InvalidationStack::default(),
 2113            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2114            ime_transaction: None,
 2115            active_diagnostics: ActiveDiagnostic::None,
 2116            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2117            inline_diagnostics_update: Task::ready(()),
 2118            inline_diagnostics: Vec::new(),
 2119            soft_wrap_mode_override,
 2120            diagnostics_max_severity,
 2121            hard_wrap: None,
 2122            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2123            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2124            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2125            project,
 2126            blink_manager: blink_manager.clone(),
 2127            show_local_selections: true,
 2128            show_scrollbars: ScrollbarAxes {
 2129                horizontal: full_mode,
 2130                vertical: full_mode,
 2131            },
 2132            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2133            offset_content: !matches!(mode, EditorMode::SingleLine),
 2134            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2135            show_gutter: full_mode,
 2136            show_line_numbers: (!full_mode).then_some(false),
 2137            use_relative_line_numbers: None,
 2138            disable_expand_excerpt_buttons: !full_mode,
 2139            show_git_diff_gutter: None,
 2140            show_code_actions: None,
 2141            show_runnables: None,
 2142            show_breakpoints: None,
 2143            show_wrap_guides: None,
 2144            show_indent_guides,
 2145            highlight_order: 0,
 2146            highlighted_rows: HashMap::default(),
 2147            background_highlights: HashMap::default(),
 2148            gutter_highlights: HashMap::default(),
 2149            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2150            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2151            nav_history: None,
 2152            context_menu: RefCell::new(None),
 2153            context_menu_options: None,
 2154            mouse_context_menu: None,
 2155            completion_tasks: Vec::new(),
 2156            inline_blame_popover: None,
 2157            inline_blame_popover_show_task: None,
 2158            signature_help_state: SignatureHelpState::default(),
 2159            auto_signature_help: None,
 2160            find_all_references_task_sources: Vec::new(),
 2161            next_completion_id: 0,
 2162            next_inlay_id: 0,
 2163            code_action_providers,
 2164            available_code_actions: None,
 2165            code_actions_task: None,
 2166            quick_selection_highlight_task: None,
 2167            debounced_selection_highlight_task: None,
 2168            document_highlights_task: None,
 2169            linked_editing_range_task: None,
 2170            pending_rename: None,
 2171            searchable: !is_minimap,
 2172            cursor_shape: EditorSettings::get_global(cx)
 2173                .cursor_shape
 2174                .unwrap_or_default(),
 2175            current_line_highlight: None,
 2176            autoindent_mode: Some(AutoindentMode::EachLine),
 2177            collapse_matches: false,
 2178            workspace: None,
 2179            input_enabled: !is_minimap,
 2180            use_modal_editing: full_mode,
 2181            read_only: is_minimap,
 2182            use_autoclose: true,
 2183            use_auto_surround: true,
 2184            auto_replace_emoji_shortcode: false,
 2185            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2186            leader_id: None,
 2187            remote_id: None,
 2188            hover_state: HoverState::default(),
 2189            pending_mouse_down: None,
 2190            hovered_link_state: None,
 2191            edit_prediction_provider: None,
 2192            active_edit_prediction: None,
 2193            stale_edit_prediction_in_menu: None,
 2194            edit_prediction_preview: EditPredictionPreview::Inactive {
 2195                released_too_fast: false,
 2196            },
 2197            inline_diagnostics_enabled: full_mode,
 2198            diagnostics_enabled: full_mode,
 2199            word_completions_enabled: full_mode,
 2200            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2201            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 2202            gutter_hovered: false,
 2203            pixel_position_of_newest_cursor: None,
 2204            last_bounds: None,
 2205            last_position_map: None,
 2206            expect_bounds_change: None,
 2207            gutter_dimensions: GutterDimensions::default(),
 2208            style: None,
 2209            show_cursor_names: false,
 2210            hovered_cursors: HashMap::default(),
 2211            next_editor_action_id: EditorActionId::default(),
 2212            editor_actions: Rc::default(),
 2213            edit_predictions_hidden_for_vim_mode: false,
 2214            show_edit_predictions_override: None,
 2215            menu_edit_predictions_policy: MenuEditPredictionsPolicy::ByProvider,
 2216            edit_prediction_settings: EditPredictionSettings::Disabled,
 2217            edit_prediction_indent_conflict: false,
 2218            edit_prediction_requires_modifier_in_indent_conflict: true,
 2219            custom_context_menu: None,
 2220            show_git_blame_gutter: false,
 2221            show_git_blame_inline: false,
 2222            show_selection_menu: None,
 2223            show_git_blame_inline_delay_task: None,
 2224            git_blame_inline_enabled: full_mode
 2225                && ProjectSettings::get_global(cx).git.inline_blame.enabled,
 2226            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2227            serialize_dirty_buffers: !is_minimap
 2228                && ProjectSettings::get_global(cx)
 2229                    .session
 2230                    .restore_unsaved_buffers,
 2231            blame: None,
 2232            blame_subscription: None,
 2233            tasks: BTreeMap::default(),
 2234
 2235            breakpoint_store,
 2236            gutter_breakpoint_indicator: (None, None),
 2237            hovered_diff_hunk_row: None,
 2238            _subscriptions: (!is_minimap)
 2239                .then(|| {
 2240                    vec![
 2241                        cx.observe(&multi_buffer, Self::on_buffer_changed),
 2242                        cx.subscribe_in(&multi_buffer, window, Self::on_buffer_event),
 2243                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2244                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2245                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2246                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2247                        cx.observe_window_activation(window, |editor, window, cx| {
 2248                            let active = window.is_window_active();
 2249                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2250                                if active {
 2251                                    blink_manager.enable(cx);
 2252                                } else {
 2253                                    blink_manager.disable(cx);
 2254                                }
 2255                            });
 2256                            if active {
 2257                                editor.show_mouse_cursor(cx);
 2258                            }
 2259                        }),
 2260                    ]
 2261                })
 2262                .unwrap_or_default(),
 2263            tasks_update_task: None,
 2264            pull_diagnostics_task: Task::ready(()),
 2265            colors: None,
 2266            refresh_colors_task: Task::ready(()),
 2267            next_color_inlay_id: 0,
 2268            post_scroll_update: Task::ready(()),
 2269            linked_edit_ranges: Default::default(),
 2270            in_project_search: false,
 2271            previous_search_ranges: None,
 2272            breadcrumb_header: None,
 2273            focused_block: None,
 2274            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2275            addons: HashMap::default(),
 2276            registered_buffers: HashMap::default(),
 2277            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2278            selection_mark_mode: false,
 2279            toggle_fold_multiple_buffers: Task::ready(()),
 2280            serialize_selections: Task::ready(()),
 2281            serialize_folds: Task::ready(()),
 2282            text_style_refinement: None,
 2283            load_diff_task: load_uncommitted_diff,
 2284            temporary_diff_override: false,
 2285            mouse_cursor_hidden: false,
 2286            minimap: None,
 2287            hide_mouse_mode: EditorSettings::get_global(cx)
 2288                .hide_mouse
 2289                .unwrap_or_default(),
 2290            change_list: ChangeList::new(),
 2291            mode,
 2292            selection_drag_state: SelectionDragState::None,
 2293            folding_newlines: Task::ready(()),
 2294            lookup_key: None,
 2295        };
 2296
 2297        if is_minimap {
 2298            return editor;
 2299        }
 2300
 2301        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2302            editor
 2303                ._subscriptions
 2304                .push(cx.observe(breakpoints, |_, _, cx| {
 2305                    cx.notify();
 2306                }));
 2307        }
 2308        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2309        editor._subscriptions.extend(project_subscriptions);
 2310
 2311        editor._subscriptions.push(cx.subscribe_in(
 2312            &cx.entity(),
 2313            window,
 2314            |editor, _, e: &EditorEvent, window, cx| match e {
 2315                EditorEvent::ScrollPositionChanged { local, .. } => {
 2316                    if *local {
 2317                        let new_anchor = editor.scroll_manager.anchor();
 2318                        let snapshot = editor.snapshot(window, cx);
 2319                        editor.update_restoration_data(cx, move |data| {
 2320                            data.scroll_position = (
 2321                                new_anchor.top_row(snapshot.buffer_snapshot()),
 2322                                new_anchor.offset,
 2323                            );
 2324                        });
 2325                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2326                        editor.inline_blame_popover.take();
 2327                    }
 2328                }
 2329                EditorEvent::Edited { .. } => {
 2330                    if !vim_enabled(cx) {
 2331                        let display_map = editor.display_snapshot(cx);
 2332                        let selections = editor.selections.all_adjusted_display(&display_map);
 2333                        let pop_state = editor
 2334                            .change_list
 2335                            .last()
 2336                            .map(|previous| {
 2337                                previous.len() == selections.len()
 2338                                    && previous.iter().enumerate().all(|(ix, p)| {
 2339                                        p.to_display_point(&display_map).row()
 2340                                            == selections[ix].head().row()
 2341                                    })
 2342                            })
 2343                            .unwrap_or(false);
 2344                        let new_positions = selections
 2345                            .into_iter()
 2346                            .map(|s| display_map.display_point_to_anchor(s.head(), Bias::Left))
 2347                            .collect();
 2348                        editor
 2349                            .change_list
 2350                            .push_to_change_list(pop_state, new_positions);
 2351                    }
 2352                }
 2353                _ => (),
 2354            },
 2355        ));
 2356
 2357        if let Some(dap_store) = editor
 2358            .project
 2359            .as_ref()
 2360            .map(|project| project.read(cx).dap_store())
 2361        {
 2362            let weak_editor = cx.weak_entity();
 2363
 2364            editor
 2365                ._subscriptions
 2366                .push(
 2367                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2368                        let session_entity = cx.entity();
 2369                        weak_editor
 2370                            .update(cx, |editor, cx| {
 2371                                editor._subscriptions.push(
 2372                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2373                                );
 2374                            })
 2375                            .ok();
 2376                    }),
 2377                );
 2378
 2379            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2380                editor
 2381                    ._subscriptions
 2382                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2383            }
 2384        }
 2385
 2386        // skip adding the initial selection to selection history
 2387        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2388        editor.end_selection(window, cx);
 2389        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2390
 2391        editor.scroll_manager.show_scrollbars(window, cx);
 2392        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &multi_buffer, cx);
 2393
 2394        if full_mode {
 2395            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2396            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2397
 2398            if editor.git_blame_inline_enabled {
 2399                editor.start_git_blame_inline(false, window, cx);
 2400            }
 2401
 2402            editor.go_to_active_debug_line(window, cx);
 2403
 2404            if let Some(buffer) = multi_buffer.read(cx).as_singleton() {
 2405                editor.register_buffer(buffer.read(cx).remote_id(), cx);
 2406            }
 2407
 2408            editor.minimap =
 2409                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2410            editor.colors = Some(LspColorData::new(cx));
 2411            editor.report_editor_event(ReportEditorEvent::EditorOpened, None, cx);
 2412        }
 2413
 2414        editor
 2415    }
 2416
 2417    pub fn display_snapshot(&self, cx: &mut App) -> DisplaySnapshot {
 2418        self.selections.display_map(cx)
 2419    }
 2420
 2421    pub fn deploy_mouse_context_menu(
 2422        &mut self,
 2423        position: gpui::Point<Pixels>,
 2424        context_menu: Entity<ContextMenu>,
 2425        window: &mut Window,
 2426        cx: &mut Context<Self>,
 2427    ) {
 2428        self.mouse_context_menu = Some(MouseContextMenu::new(
 2429            self,
 2430            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2431            context_menu,
 2432            window,
 2433            cx,
 2434        ));
 2435    }
 2436
 2437    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2438        self.mouse_context_menu
 2439            .as_ref()
 2440            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2441    }
 2442
 2443    pub fn is_range_selected(&mut self, range: &Range<Anchor>, cx: &mut Context<Self>) -> bool {
 2444        if self
 2445            .selections
 2446            .pending_anchor()
 2447            .is_some_and(|pending_selection| {
 2448                let snapshot = self.buffer().read(cx).snapshot(cx);
 2449                pending_selection.range().includes(range, &snapshot)
 2450            })
 2451        {
 2452            return true;
 2453        }
 2454
 2455        self.selections
 2456            .disjoint_in_range::<usize>(range.clone(), &self.display_snapshot(cx))
 2457            .into_iter()
 2458            .any(|selection| {
 2459                // This is needed to cover a corner case, if we just check for an existing
 2460                // selection in the fold range, having a cursor at the start of the fold
 2461                // marks it as selected. Non-empty selections don't cause this.
 2462                let length = selection.end - selection.start;
 2463                length > 0
 2464            })
 2465    }
 2466
 2467    pub fn key_context(&self, window: &mut Window, cx: &mut App) -> KeyContext {
 2468        self.key_context_internal(self.has_active_edit_prediction(), window, cx)
 2469    }
 2470
 2471    fn key_context_internal(
 2472        &self,
 2473        has_active_edit_prediction: bool,
 2474        window: &mut Window,
 2475        cx: &mut App,
 2476    ) -> KeyContext {
 2477        let mut key_context = KeyContext::new_with_defaults();
 2478        key_context.add("Editor");
 2479        let mode = match self.mode {
 2480            EditorMode::SingleLine => "single_line",
 2481            EditorMode::AutoHeight { .. } => "auto_height",
 2482            EditorMode::Minimap { .. } => "minimap",
 2483            EditorMode::Full { .. } => "full",
 2484        };
 2485
 2486        if EditorSettings::jupyter_enabled(cx) {
 2487            key_context.add("jupyter");
 2488        }
 2489
 2490        key_context.set("mode", mode);
 2491        if self.pending_rename.is_some() {
 2492            key_context.add("renaming");
 2493        }
 2494
 2495        match self.context_menu.borrow().as_ref() {
 2496            Some(CodeContextMenu::Completions(menu)) => {
 2497                if menu.visible() {
 2498                    key_context.add("menu");
 2499                    key_context.add("showing_completions");
 2500                }
 2501            }
 2502            Some(CodeContextMenu::CodeActions(menu)) => {
 2503                if menu.visible() {
 2504                    key_context.add("menu");
 2505                    key_context.add("showing_code_actions")
 2506                }
 2507            }
 2508            None => {}
 2509        }
 2510
 2511        if self.signature_help_state.has_multiple_signatures() {
 2512            key_context.add("showing_signature_help");
 2513        }
 2514
 2515        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2516        if !self.focus_handle(cx).contains_focused(window, cx)
 2517            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2518        {
 2519            for addon in self.addons.values() {
 2520                addon.extend_key_context(&mut key_context, cx)
 2521            }
 2522        }
 2523
 2524        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2525            if let Some(extension) = singleton_buffer.read(cx).file().and_then(|file| {
 2526                Some(
 2527                    file.full_path(cx)
 2528                        .extension()?
 2529                        .to_string_lossy()
 2530                        .into_owned(),
 2531                )
 2532            }) {
 2533                key_context.set("extension", extension);
 2534            }
 2535        } else {
 2536            key_context.add("multibuffer");
 2537        }
 2538
 2539        if has_active_edit_prediction {
 2540            if self.edit_prediction_in_conflict() {
 2541                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2542            } else {
 2543                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2544                key_context.add("copilot_suggestion");
 2545            }
 2546        }
 2547
 2548        if self.selection_mark_mode {
 2549            key_context.add("selection_mode");
 2550        }
 2551
 2552        let disjoint = self.selections.disjoint_anchors();
 2553        let snapshot = self.snapshot(window, cx);
 2554        let snapshot = snapshot.buffer_snapshot();
 2555        if self.mode == EditorMode::SingleLine
 2556            && let [selection] = disjoint
 2557            && selection.start == selection.end
 2558            && selection.end.to_offset(snapshot) == snapshot.len()
 2559        {
 2560            key_context.add("end_of_input");
 2561        }
 2562
 2563        key_context
 2564    }
 2565
 2566    pub fn last_bounds(&self) -> Option<&Bounds<Pixels>> {
 2567        self.last_bounds.as_ref()
 2568    }
 2569
 2570    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2571        if self.mouse_cursor_hidden {
 2572            self.mouse_cursor_hidden = false;
 2573            cx.notify();
 2574        }
 2575    }
 2576
 2577    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2578        let hide_mouse_cursor = match origin {
 2579            HideMouseCursorOrigin::TypingAction => {
 2580                matches!(
 2581                    self.hide_mouse_mode,
 2582                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2583                )
 2584            }
 2585            HideMouseCursorOrigin::MovementAction => {
 2586                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2587            }
 2588        };
 2589        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2590            self.mouse_cursor_hidden = hide_mouse_cursor;
 2591            cx.notify();
 2592        }
 2593    }
 2594
 2595    pub fn edit_prediction_in_conflict(&self) -> bool {
 2596        if !self.show_edit_predictions_in_menu() {
 2597            return false;
 2598        }
 2599
 2600        let showing_completions = self
 2601            .context_menu
 2602            .borrow()
 2603            .as_ref()
 2604            .is_some_and(|context| matches!(context, CodeContextMenu::Completions(_)));
 2605
 2606        showing_completions
 2607            || self.edit_prediction_requires_modifier()
 2608            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2609            // bindings to insert tab characters.
 2610            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2611    }
 2612
 2613    pub fn accept_edit_prediction_keybind(
 2614        &self,
 2615        accept_partial: bool,
 2616        window: &mut Window,
 2617        cx: &mut App,
 2618    ) -> AcceptEditPredictionBinding {
 2619        let key_context = self.key_context_internal(true, window, cx);
 2620        let in_conflict = self.edit_prediction_in_conflict();
 2621
 2622        let bindings = if accept_partial {
 2623            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2624        } else {
 2625            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2626        };
 2627
 2628        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2629        // just the first one.
 2630        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2631            !in_conflict
 2632                || binding
 2633                    .keystrokes()
 2634                    .first()
 2635                    .is_some_and(|keystroke| keystroke.modifiers().modified())
 2636        }))
 2637    }
 2638
 2639    pub fn new_file(
 2640        workspace: &mut Workspace,
 2641        _: &workspace::NewFile,
 2642        window: &mut Window,
 2643        cx: &mut Context<Workspace>,
 2644    ) {
 2645        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2646            "Failed to create buffer",
 2647            window,
 2648            cx,
 2649            |e, _, _| match e.error_code() {
 2650                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2651                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2652                e.error_tag("required").unwrap_or("the latest version")
 2653            )),
 2654                _ => None,
 2655            },
 2656        );
 2657    }
 2658
 2659    pub fn new_in_workspace(
 2660        workspace: &mut Workspace,
 2661        window: &mut Window,
 2662        cx: &mut Context<Workspace>,
 2663    ) -> Task<Result<Entity<Editor>>> {
 2664        let project = workspace.project().clone();
 2665        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2666
 2667        cx.spawn_in(window, async move |workspace, cx| {
 2668            let buffer = create.await?;
 2669            workspace.update_in(cx, |workspace, window, cx| {
 2670                let editor =
 2671                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2672                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2673                editor
 2674            })
 2675        })
 2676    }
 2677
 2678    fn new_file_vertical(
 2679        workspace: &mut Workspace,
 2680        _: &workspace::NewFileSplitVertical,
 2681        window: &mut Window,
 2682        cx: &mut Context<Workspace>,
 2683    ) {
 2684        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2685    }
 2686
 2687    fn new_file_horizontal(
 2688        workspace: &mut Workspace,
 2689        _: &workspace::NewFileSplitHorizontal,
 2690        window: &mut Window,
 2691        cx: &mut Context<Workspace>,
 2692    ) {
 2693        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2694    }
 2695
 2696    fn new_file_split(
 2697        workspace: &mut Workspace,
 2698        action: &workspace::NewFileSplit,
 2699        window: &mut Window,
 2700        cx: &mut Context<Workspace>,
 2701    ) {
 2702        Self::new_file_in_direction(workspace, action.0, window, cx)
 2703    }
 2704
 2705    fn new_file_in_direction(
 2706        workspace: &mut Workspace,
 2707        direction: SplitDirection,
 2708        window: &mut Window,
 2709        cx: &mut Context<Workspace>,
 2710    ) {
 2711        let project = workspace.project().clone();
 2712        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2713
 2714        cx.spawn_in(window, async move |workspace, cx| {
 2715            let buffer = create.await?;
 2716            workspace.update_in(cx, move |workspace, window, cx| {
 2717                workspace.split_item(
 2718                    direction,
 2719                    Box::new(
 2720                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2721                    ),
 2722                    window,
 2723                    cx,
 2724                )
 2725            })?;
 2726            anyhow::Ok(())
 2727        })
 2728        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2729            match e.error_code() {
 2730                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2731                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2732                e.error_tag("required").unwrap_or("the latest version")
 2733            )),
 2734                _ => None,
 2735            }
 2736        });
 2737    }
 2738
 2739    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2740        self.leader_id
 2741    }
 2742
 2743    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2744        &self.buffer
 2745    }
 2746
 2747    pub fn project(&self) -> Option<&Entity<Project>> {
 2748        self.project.as_ref()
 2749    }
 2750
 2751    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2752        self.workspace.as_ref()?.0.upgrade()
 2753    }
 2754
 2755    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2756        self.buffer().read(cx).title(cx)
 2757    }
 2758
 2759    pub fn snapshot(&self, window: &Window, cx: &mut App) -> EditorSnapshot {
 2760        let git_blame_gutter_max_author_length = self
 2761            .render_git_blame_gutter(cx)
 2762            .then(|| {
 2763                if let Some(blame) = self.blame.as_ref() {
 2764                    let max_author_length =
 2765                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2766                    Some(max_author_length)
 2767                } else {
 2768                    None
 2769                }
 2770            })
 2771            .flatten();
 2772
 2773        EditorSnapshot {
 2774            mode: self.mode.clone(),
 2775            show_gutter: self.show_gutter,
 2776            show_line_numbers: self.show_line_numbers,
 2777            show_git_diff_gutter: self.show_git_diff_gutter,
 2778            show_code_actions: self.show_code_actions,
 2779            show_runnables: self.show_runnables,
 2780            show_breakpoints: self.show_breakpoints,
 2781            git_blame_gutter_max_author_length,
 2782            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2783            placeholder_display_snapshot: self
 2784                .placeholder_display_map
 2785                .as_ref()
 2786                .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx))),
 2787            scroll_anchor: self.scroll_manager.anchor(),
 2788            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2789            is_focused: self.focus_handle.is_focused(window),
 2790            current_line_highlight: self
 2791                .current_line_highlight
 2792                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2793            gutter_hovered: self.gutter_hovered,
 2794        }
 2795    }
 2796
 2797    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2798        self.buffer.read(cx).language_at(point, cx)
 2799    }
 2800
 2801    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2802        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2803    }
 2804
 2805    pub fn active_excerpt(
 2806        &self,
 2807        cx: &App,
 2808    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2809        self.buffer
 2810            .read(cx)
 2811            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2812    }
 2813
 2814    pub fn mode(&self) -> &EditorMode {
 2815        &self.mode
 2816    }
 2817
 2818    pub fn set_mode(&mut self, mode: EditorMode) {
 2819        self.mode = mode;
 2820    }
 2821
 2822    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2823        self.collaboration_hub.as_deref()
 2824    }
 2825
 2826    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2827        self.collaboration_hub = Some(hub);
 2828    }
 2829
 2830    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2831        self.in_project_search = in_project_search;
 2832    }
 2833
 2834    pub fn set_custom_context_menu(
 2835        &mut self,
 2836        f: impl 'static
 2837        + Fn(
 2838            &mut Self,
 2839            DisplayPoint,
 2840            &mut Window,
 2841            &mut Context<Self>,
 2842        ) -> Option<Entity<ui::ContextMenu>>,
 2843    ) {
 2844        self.custom_context_menu = Some(Box::new(f))
 2845    }
 2846
 2847    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2848        self.completion_provider = provider;
 2849    }
 2850
 2851    #[cfg(any(test, feature = "test-support"))]
 2852    pub fn completion_provider(&self) -> Option<Rc<dyn CompletionProvider>> {
 2853        self.completion_provider.clone()
 2854    }
 2855
 2856    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2857        self.semantics_provider.clone()
 2858    }
 2859
 2860    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2861        self.semantics_provider = provider;
 2862    }
 2863
 2864    pub fn set_edit_prediction_provider<T>(
 2865        &mut self,
 2866        provider: Option<Entity<T>>,
 2867        window: &mut Window,
 2868        cx: &mut Context<Self>,
 2869    ) where
 2870        T: EditPredictionProvider,
 2871    {
 2872        self.edit_prediction_provider = provider.map(|provider| RegisteredEditPredictionProvider {
 2873            _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2874                if this.focus_handle.is_focused(window) {
 2875                    this.update_visible_edit_prediction(window, cx);
 2876                }
 2877            }),
 2878            provider: Arc::new(provider),
 2879        });
 2880        self.update_edit_prediction_settings(cx);
 2881        self.refresh_edit_prediction(false, false, window, cx);
 2882    }
 2883
 2884    pub fn placeholder_text(&self, cx: &mut App) -> Option<String> {
 2885        self.placeholder_display_map
 2886            .as_ref()
 2887            .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx)).text())
 2888    }
 2889
 2890    pub fn set_placeholder_text(
 2891        &mut self,
 2892        placeholder_text: &str,
 2893        window: &mut Window,
 2894        cx: &mut Context<Self>,
 2895    ) {
 2896        let multibuffer = cx
 2897            .new(|cx| MultiBuffer::singleton(cx.new(|cx| Buffer::local(placeholder_text, cx)), cx));
 2898
 2899        let style = window.text_style();
 2900
 2901        self.placeholder_display_map = Some(cx.new(|cx| {
 2902            DisplayMap::new(
 2903                multibuffer,
 2904                style.font(),
 2905                style.font_size.to_pixels(window.rem_size()),
 2906                None,
 2907                FILE_HEADER_HEIGHT,
 2908                MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 2909                Default::default(),
 2910                DiagnosticSeverity::Off,
 2911                cx,
 2912            )
 2913        }));
 2914        cx.notify();
 2915    }
 2916
 2917    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2918        self.cursor_shape = cursor_shape;
 2919
 2920        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2921        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2922
 2923        cx.notify();
 2924    }
 2925
 2926    pub fn set_current_line_highlight(
 2927        &mut self,
 2928        current_line_highlight: Option<CurrentLineHighlight>,
 2929    ) {
 2930        self.current_line_highlight = current_line_highlight;
 2931    }
 2932
 2933    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2934        self.collapse_matches = collapse_matches;
 2935    }
 2936
 2937    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2938        if self.collapse_matches {
 2939            return range.start..range.start;
 2940        }
 2941        range.clone()
 2942    }
 2943
 2944    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2945        if self.display_map.read(cx).clip_at_line_ends != clip {
 2946            self.display_map
 2947                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2948        }
 2949    }
 2950
 2951    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2952        self.input_enabled = input_enabled;
 2953    }
 2954
 2955    pub fn set_edit_predictions_hidden_for_vim_mode(
 2956        &mut self,
 2957        hidden: bool,
 2958        window: &mut Window,
 2959        cx: &mut Context<Self>,
 2960    ) {
 2961        if hidden != self.edit_predictions_hidden_for_vim_mode {
 2962            self.edit_predictions_hidden_for_vim_mode = hidden;
 2963            if hidden {
 2964                self.update_visible_edit_prediction(window, cx);
 2965            } else {
 2966                self.refresh_edit_prediction(true, false, window, cx);
 2967            }
 2968        }
 2969    }
 2970
 2971    pub fn set_menu_edit_predictions_policy(&mut self, value: MenuEditPredictionsPolicy) {
 2972        self.menu_edit_predictions_policy = value;
 2973    }
 2974
 2975    pub fn set_autoindent(&mut self, autoindent: bool) {
 2976        if autoindent {
 2977            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2978        } else {
 2979            self.autoindent_mode = None;
 2980        }
 2981    }
 2982
 2983    pub fn read_only(&self, cx: &App) -> bool {
 2984        self.read_only || self.buffer.read(cx).read_only()
 2985    }
 2986
 2987    pub fn set_read_only(&mut self, read_only: bool) {
 2988        self.read_only = read_only;
 2989    }
 2990
 2991    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2992        self.use_autoclose = autoclose;
 2993    }
 2994
 2995    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2996        self.use_auto_surround = auto_surround;
 2997    }
 2998
 2999    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 3000        self.auto_replace_emoji_shortcode = auto_replace;
 3001    }
 3002
 3003    pub fn toggle_edit_predictions(
 3004        &mut self,
 3005        _: &ToggleEditPrediction,
 3006        window: &mut Window,
 3007        cx: &mut Context<Self>,
 3008    ) {
 3009        if self.show_edit_predictions_override.is_some() {
 3010            self.set_show_edit_predictions(None, window, cx);
 3011        } else {
 3012            let show_edit_predictions = !self.edit_predictions_enabled();
 3013            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 3014        }
 3015    }
 3016
 3017    pub fn set_show_edit_predictions(
 3018        &mut self,
 3019        show_edit_predictions: Option<bool>,
 3020        window: &mut Window,
 3021        cx: &mut Context<Self>,
 3022    ) {
 3023        self.show_edit_predictions_override = show_edit_predictions;
 3024        self.update_edit_prediction_settings(cx);
 3025
 3026        if let Some(false) = show_edit_predictions {
 3027            self.discard_edit_prediction(false, cx);
 3028        } else {
 3029            self.refresh_edit_prediction(false, true, window, cx);
 3030        }
 3031    }
 3032
 3033    fn edit_predictions_disabled_in_scope(
 3034        &self,
 3035        buffer: &Entity<Buffer>,
 3036        buffer_position: language::Anchor,
 3037        cx: &App,
 3038    ) -> bool {
 3039        let snapshot = buffer.read(cx).snapshot();
 3040        let settings = snapshot.settings_at(buffer_position, cx);
 3041
 3042        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 3043            return false;
 3044        };
 3045
 3046        scope.override_name().is_some_and(|scope_name| {
 3047            settings
 3048                .edit_predictions_disabled_in
 3049                .iter()
 3050                .any(|s| s == scope_name)
 3051        })
 3052    }
 3053
 3054    pub fn set_use_modal_editing(&mut self, to: bool) {
 3055        self.use_modal_editing = to;
 3056    }
 3057
 3058    pub fn use_modal_editing(&self) -> bool {
 3059        self.use_modal_editing
 3060    }
 3061
 3062    fn selections_did_change(
 3063        &mut self,
 3064        local: bool,
 3065        old_cursor_position: &Anchor,
 3066        effects: SelectionEffects,
 3067        window: &mut Window,
 3068        cx: &mut Context<Self>,
 3069    ) {
 3070        window.invalidate_character_coordinates();
 3071
 3072        // Copy selections to primary selection buffer
 3073        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 3074        if local {
 3075            let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 3076            let buffer_handle = self.buffer.read(cx).read(cx);
 3077
 3078            let mut text = String::new();
 3079            for (index, selection) in selections.iter().enumerate() {
 3080                let text_for_selection = buffer_handle
 3081                    .text_for_range(selection.start..selection.end)
 3082                    .collect::<String>();
 3083
 3084                text.push_str(&text_for_selection);
 3085                if index != selections.len() - 1 {
 3086                    text.push('\n');
 3087                }
 3088            }
 3089
 3090            if !text.is_empty() {
 3091                cx.write_to_primary(ClipboardItem::new_string(text));
 3092            }
 3093        }
 3094
 3095        let selection_anchors = self.selections.disjoint_anchors_arc();
 3096
 3097        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 3098            self.buffer.update(cx, |buffer, cx| {
 3099                buffer.set_active_selections(
 3100                    &selection_anchors,
 3101                    self.selections.line_mode(),
 3102                    self.cursor_shape,
 3103                    cx,
 3104                )
 3105            });
 3106        }
 3107        let display_map = self
 3108            .display_map
 3109            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3110        let buffer = display_map.buffer_snapshot();
 3111        if self.selections.count() == 1 {
 3112            self.add_selections_state = None;
 3113        }
 3114        self.select_next_state = None;
 3115        self.select_prev_state = None;
 3116        self.select_syntax_node_history.try_clear();
 3117        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 3118        self.snippet_stack.invalidate(&selection_anchors, buffer);
 3119        self.take_rename(false, window, cx);
 3120
 3121        let newest_selection = self.selections.newest_anchor();
 3122        let new_cursor_position = newest_selection.head();
 3123        let selection_start = newest_selection.start;
 3124
 3125        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 3126            self.push_to_nav_history(
 3127                *old_cursor_position,
 3128                Some(new_cursor_position.to_point(buffer)),
 3129                false,
 3130                effects.nav_history == Some(true),
 3131                cx,
 3132            );
 3133        }
 3134
 3135        if local {
 3136            if let Some(buffer_id) = new_cursor_position.buffer_id {
 3137                self.register_buffer(buffer_id, cx);
 3138            }
 3139
 3140            let mut context_menu = self.context_menu.borrow_mut();
 3141            let completion_menu = match context_menu.as_ref() {
 3142                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3143                Some(CodeContextMenu::CodeActions(_)) => {
 3144                    *context_menu = None;
 3145                    None
 3146                }
 3147                None => None,
 3148            };
 3149            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3150            drop(context_menu);
 3151
 3152            if effects.completions
 3153                && let Some(completion_position) = completion_position
 3154            {
 3155                let start_offset = selection_start.to_offset(buffer);
 3156                let position_matches = start_offset == completion_position.to_offset(buffer);
 3157                let continue_showing = if position_matches {
 3158                    if self.snippet_stack.is_empty() {
 3159                        buffer.char_kind_before(start_offset, Some(CharScopeContext::Completion))
 3160                            == Some(CharKind::Word)
 3161                    } else {
 3162                        // Snippet choices can be shown even when the cursor is in whitespace.
 3163                        // Dismissing the menu with actions like backspace is handled by
 3164                        // invalidation regions.
 3165                        true
 3166                    }
 3167                } else {
 3168                    false
 3169                };
 3170
 3171                if continue_showing {
 3172                    self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 3173                } else {
 3174                    self.hide_context_menu(window, cx);
 3175                }
 3176            }
 3177
 3178            hide_hover(self, cx);
 3179
 3180            if old_cursor_position.to_display_point(&display_map).row()
 3181                != new_cursor_position.to_display_point(&display_map).row()
 3182            {
 3183                self.available_code_actions.take();
 3184            }
 3185            self.refresh_code_actions(window, cx);
 3186            self.refresh_document_highlights(cx);
 3187            refresh_linked_ranges(self, window, cx);
 3188
 3189            self.refresh_selected_text_highlights(false, window, cx);
 3190            self.refresh_matching_bracket_highlights(window, cx);
 3191            self.update_visible_edit_prediction(window, cx);
 3192            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3193            self.inline_blame_popover.take();
 3194            if self.git_blame_inline_enabled {
 3195                self.start_inline_blame_timer(window, cx);
 3196            }
 3197        }
 3198
 3199        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3200        cx.emit(EditorEvent::SelectionsChanged { local });
 3201
 3202        let selections = &self.selections.disjoint_anchors_arc();
 3203        if selections.len() == 1 {
 3204            cx.emit(SearchEvent::ActiveMatchChanged)
 3205        }
 3206        if local && let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3207            let inmemory_selections = selections
 3208                .iter()
 3209                .map(|s| {
 3210                    text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3211                        ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3212                })
 3213                .collect();
 3214            self.update_restoration_data(cx, |data| {
 3215                data.selections = inmemory_selections;
 3216            });
 3217
 3218            if WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
 3219                && let Some(workspace_id) =
 3220                    self.workspace.as_ref().and_then(|workspace| workspace.1)
 3221            {
 3222                let snapshot = self.buffer().read(cx).snapshot(cx);
 3223                let selections = selections.clone();
 3224                let background_executor = cx.background_executor().clone();
 3225                let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3226                self.serialize_selections = cx.background_spawn(async move {
 3227                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3228                    let db_selections = selections
 3229                        .iter()
 3230                        .map(|selection| {
 3231                            (
 3232                                selection.start.to_offset(&snapshot),
 3233                                selection.end.to_offset(&snapshot),
 3234                            )
 3235                        })
 3236                        .collect();
 3237
 3238                    DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3239                        .await
 3240                        .with_context(|| {
 3241                            format!(
 3242                                "persisting editor selections for editor {editor_id}, \
 3243                                workspace {workspace_id:?}"
 3244                            )
 3245                        })
 3246                        .log_err();
 3247                });
 3248            }
 3249        }
 3250
 3251        cx.notify();
 3252    }
 3253
 3254    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3255        use text::ToOffset as _;
 3256        use text::ToPoint as _;
 3257
 3258        if self.mode.is_minimap()
 3259            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3260        {
 3261            return;
 3262        }
 3263
 3264        if !self.buffer().read(cx).is_singleton() {
 3265            return;
 3266        }
 3267
 3268        let display_snapshot = self
 3269            .display_map
 3270            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3271        let Some((.., snapshot)) = display_snapshot.buffer_snapshot().as_singleton() else {
 3272            return;
 3273        };
 3274        let inmemory_folds = display_snapshot
 3275            .folds_in_range(0..display_snapshot.buffer_snapshot().len())
 3276            .map(|fold| {
 3277                fold.range.start.text_anchor.to_point(&snapshot)
 3278                    ..fold.range.end.text_anchor.to_point(&snapshot)
 3279            })
 3280            .collect();
 3281        self.update_restoration_data(cx, |data| {
 3282            data.folds = inmemory_folds;
 3283        });
 3284
 3285        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 3286            return;
 3287        };
 3288        let background_executor = cx.background_executor().clone();
 3289        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3290        let db_folds = display_snapshot
 3291            .folds_in_range(0..display_snapshot.buffer_snapshot().len())
 3292            .map(|fold| {
 3293                (
 3294                    fold.range.start.text_anchor.to_offset(&snapshot),
 3295                    fold.range.end.text_anchor.to_offset(&snapshot),
 3296                )
 3297            })
 3298            .collect();
 3299        self.serialize_folds = cx.background_spawn(async move {
 3300            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3301            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3302                .await
 3303                .with_context(|| {
 3304                    format!(
 3305                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3306                    )
 3307                })
 3308                .log_err();
 3309        });
 3310    }
 3311
 3312    pub fn sync_selections(
 3313        &mut self,
 3314        other: Entity<Editor>,
 3315        cx: &mut Context<Self>,
 3316    ) -> gpui::Subscription {
 3317        let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3318        if !other_selections.is_empty() {
 3319            self.selections.change_with(cx, |selections| {
 3320                selections.select_anchors(other_selections);
 3321            });
 3322        }
 3323
 3324        let other_subscription = cx.subscribe(&other, |this, other, other_evt, cx| {
 3325            if let EditorEvent::SelectionsChanged { local: true } = other_evt {
 3326                let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3327                if other_selections.is_empty() {
 3328                    return;
 3329                }
 3330                this.selections.change_with(cx, |selections| {
 3331                    selections.select_anchors(other_selections);
 3332                });
 3333            }
 3334        });
 3335
 3336        let this_subscription = cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| {
 3337            if let EditorEvent::SelectionsChanged { local: true } = this_evt {
 3338                let these_selections = this.selections.disjoint_anchors().to_vec();
 3339                if these_selections.is_empty() {
 3340                    return;
 3341                }
 3342                other.update(cx, |other_editor, cx| {
 3343                    other_editor.selections.change_with(cx, |selections| {
 3344                        selections.select_anchors(these_selections);
 3345                    })
 3346                });
 3347            }
 3348        });
 3349
 3350        Subscription::join(other_subscription, this_subscription)
 3351    }
 3352
 3353    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3354    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3355    /// effects of selection change occur at the end of the transaction.
 3356    pub fn change_selections<R>(
 3357        &mut self,
 3358        effects: SelectionEffects,
 3359        window: &mut Window,
 3360        cx: &mut Context<Self>,
 3361        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3362    ) -> R {
 3363        if let Some(state) = &mut self.deferred_selection_effects_state {
 3364            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3365            state.effects.completions = effects.completions;
 3366            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3367            let (changed, result) = self.selections.change_with(cx, change);
 3368            state.changed |= changed;
 3369            return result;
 3370        }
 3371        let mut state = DeferredSelectionEffectsState {
 3372            changed: false,
 3373            effects,
 3374            old_cursor_position: self.selections.newest_anchor().head(),
 3375            history_entry: SelectionHistoryEntry {
 3376                selections: self.selections.disjoint_anchors_arc(),
 3377                select_next_state: self.select_next_state.clone(),
 3378                select_prev_state: self.select_prev_state.clone(),
 3379                add_selections_state: self.add_selections_state.clone(),
 3380            },
 3381        };
 3382        let (changed, result) = self.selections.change_with(cx, change);
 3383        state.changed = state.changed || changed;
 3384        if self.defer_selection_effects {
 3385            self.deferred_selection_effects_state = Some(state);
 3386        } else {
 3387            self.apply_selection_effects(state, window, cx);
 3388        }
 3389        result
 3390    }
 3391
 3392    /// Defers the effects of selection change, so that the effects of multiple calls to
 3393    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3394    /// to selection history and the state of popovers based on selection position aren't
 3395    /// erroneously updated.
 3396    pub fn with_selection_effects_deferred<R>(
 3397        &mut self,
 3398        window: &mut Window,
 3399        cx: &mut Context<Self>,
 3400        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3401    ) -> R {
 3402        let already_deferred = self.defer_selection_effects;
 3403        self.defer_selection_effects = true;
 3404        let result = update(self, window, cx);
 3405        if !already_deferred {
 3406            self.defer_selection_effects = false;
 3407            if let Some(state) = self.deferred_selection_effects_state.take() {
 3408                self.apply_selection_effects(state, window, cx);
 3409            }
 3410        }
 3411        result
 3412    }
 3413
 3414    fn apply_selection_effects(
 3415        &mut self,
 3416        state: DeferredSelectionEffectsState,
 3417        window: &mut Window,
 3418        cx: &mut Context<Self>,
 3419    ) {
 3420        if state.changed {
 3421            self.selection_history.push(state.history_entry);
 3422
 3423            if let Some(autoscroll) = state.effects.scroll {
 3424                self.request_autoscroll(autoscroll, cx);
 3425            }
 3426
 3427            let old_cursor_position = &state.old_cursor_position;
 3428
 3429            self.selections_did_change(true, old_cursor_position, state.effects, window, cx);
 3430
 3431            if self.should_open_signature_help_automatically(old_cursor_position, cx) {
 3432                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3433            }
 3434        }
 3435    }
 3436
 3437    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3438    where
 3439        I: IntoIterator<Item = (Range<S>, T)>,
 3440        S: ToOffset,
 3441        T: Into<Arc<str>>,
 3442    {
 3443        if self.read_only(cx) {
 3444            return;
 3445        }
 3446
 3447        self.buffer
 3448            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3449    }
 3450
 3451    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3452    where
 3453        I: IntoIterator<Item = (Range<S>, T)>,
 3454        S: ToOffset,
 3455        T: Into<Arc<str>>,
 3456    {
 3457        if self.read_only(cx) {
 3458            return;
 3459        }
 3460
 3461        self.buffer.update(cx, |buffer, cx| {
 3462            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3463        });
 3464    }
 3465
 3466    pub fn edit_with_block_indent<I, S, T>(
 3467        &mut self,
 3468        edits: I,
 3469        original_indent_columns: Vec<Option<u32>>,
 3470        cx: &mut Context<Self>,
 3471    ) where
 3472        I: IntoIterator<Item = (Range<S>, T)>,
 3473        S: ToOffset,
 3474        T: Into<Arc<str>>,
 3475    {
 3476        if self.read_only(cx) {
 3477            return;
 3478        }
 3479
 3480        self.buffer.update(cx, |buffer, cx| {
 3481            buffer.edit(
 3482                edits,
 3483                Some(AutoindentMode::Block {
 3484                    original_indent_columns,
 3485                }),
 3486                cx,
 3487            )
 3488        });
 3489    }
 3490
 3491    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3492        self.hide_context_menu(window, cx);
 3493
 3494        match phase {
 3495            SelectPhase::Begin {
 3496                position,
 3497                add,
 3498                click_count,
 3499            } => self.begin_selection(position, add, click_count, window, cx),
 3500            SelectPhase::BeginColumnar {
 3501                position,
 3502                goal_column,
 3503                reset,
 3504                mode,
 3505            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3506            SelectPhase::Extend {
 3507                position,
 3508                click_count,
 3509            } => self.extend_selection(position, click_count, window, cx),
 3510            SelectPhase::Update {
 3511                position,
 3512                goal_column,
 3513                scroll_delta,
 3514            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3515            SelectPhase::End => self.end_selection(window, cx),
 3516        }
 3517    }
 3518
 3519    fn extend_selection(
 3520        &mut self,
 3521        position: DisplayPoint,
 3522        click_count: usize,
 3523        window: &mut Window,
 3524        cx: &mut Context<Self>,
 3525    ) {
 3526        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3527        let tail = self.selections.newest::<usize>(&display_map).tail();
 3528        let click_count = click_count.max(match self.selections.select_mode() {
 3529            SelectMode::Character => 1,
 3530            SelectMode::Word(_) => 2,
 3531            SelectMode::Line(_) => 3,
 3532            SelectMode::All => 4,
 3533        });
 3534        self.begin_selection(position, false, click_count, window, cx);
 3535
 3536        let tail_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3537
 3538        let current_selection = match self.selections.select_mode() {
 3539            SelectMode::Character | SelectMode::All => tail_anchor..tail_anchor,
 3540            SelectMode::Word(range) | SelectMode::Line(range) => range.clone(),
 3541        };
 3542
 3543        let mut pending_selection = self
 3544            .selections
 3545            .pending_anchor()
 3546            .cloned()
 3547            .expect("extend_selection not called with pending selection");
 3548
 3549        if pending_selection
 3550            .start
 3551            .cmp(&current_selection.start, display_map.buffer_snapshot())
 3552            == Ordering::Greater
 3553        {
 3554            pending_selection.start = current_selection.start;
 3555        }
 3556        if pending_selection
 3557            .end
 3558            .cmp(&current_selection.end, display_map.buffer_snapshot())
 3559            == Ordering::Less
 3560        {
 3561            pending_selection.end = current_selection.end;
 3562            pending_selection.reversed = true;
 3563        }
 3564
 3565        let mut pending_mode = self.selections.pending_mode().unwrap();
 3566        match &mut pending_mode {
 3567            SelectMode::Word(range) | SelectMode::Line(range) => *range = current_selection,
 3568            _ => {}
 3569        }
 3570
 3571        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3572            SelectionEffects::scroll(Autoscroll::fit())
 3573        } else {
 3574            SelectionEffects::no_scroll()
 3575        };
 3576
 3577        self.change_selections(effects, window, cx, |s| {
 3578            s.set_pending(pending_selection.clone(), pending_mode);
 3579            s.set_is_extending(true);
 3580        });
 3581    }
 3582
 3583    fn begin_selection(
 3584        &mut self,
 3585        position: DisplayPoint,
 3586        add: bool,
 3587        click_count: usize,
 3588        window: &mut Window,
 3589        cx: &mut Context<Self>,
 3590    ) {
 3591        if !self.focus_handle.is_focused(window) {
 3592            self.last_focused_descendant = None;
 3593            window.focus(&self.focus_handle);
 3594        }
 3595
 3596        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3597        let buffer = display_map.buffer_snapshot();
 3598        let position = display_map.clip_point(position, Bias::Left);
 3599
 3600        let start;
 3601        let end;
 3602        let mode;
 3603        let mut auto_scroll;
 3604        match click_count {
 3605            1 => {
 3606                start = buffer.anchor_before(position.to_point(&display_map));
 3607                end = start;
 3608                mode = SelectMode::Character;
 3609                auto_scroll = true;
 3610            }
 3611            2 => {
 3612                let position = display_map
 3613                    .clip_point(position, Bias::Left)
 3614                    .to_offset(&display_map, Bias::Left);
 3615                let (range, _) = buffer.surrounding_word(position, None);
 3616                start = buffer.anchor_before(range.start);
 3617                end = buffer.anchor_before(range.end);
 3618                mode = SelectMode::Word(start..end);
 3619                auto_scroll = true;
 3620            }
 3621            3 => {
 3622                let position = display_map
 3623                    .clip_point(position, Bias::Left)
 3624                    .to_point(&display_map);
 3625                let line_start = display_map.prev_line_boundary(position).0;
 3626                let next_line_start = buffer.clip_point(
 3627                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3628                    Bias::Left,
 3629                );
 3630                start = buffer.anchor_before(line_start);
 3631                end = buffer.anchor_before(next_line_start);
 3632                mode = SelectMode::Line(start..end);
 3633                auto_scroll = true;
 3634            }
 3635            _ => {
 3636                start = buffer.anchor_before(0);
 3637                end = buffer.anchor_before(buffer.len());
 3638                mode = SelectMode::All;
 3639                auto_scroll = false;
 3640            }
 3641        }
 3642        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3643
 3644        let point_to_delete: Option<usize> = {
 3645            let selected_points: Vec<Selection<Point>> =
 3646                self.selections.disjoint_in_range(start..end, &display_map);
 3647
 3648            if !add || click_count > 1 {
 3649                None
 3650            } else if !selected_points.is_empty() {
 3651                Some(selected_points[0].id)
 3652            } else {
 3653                let clicked_point_already_selected =
 3654                    self.selections.disjoint_anchors().iter().find(|selection| {
 3655                        selection.start.to_point(buffer) == start.to_point(buffer)
 3656                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3657                    });
 3658
 3659                clicked_point_already_selected.map(|selection| selection.id)
 3660            }
 3661        };
 3662
 3663        let selections_count = self.selections.count();
 3664        let effects = if auto_scroll {
 3665            SelectionEffects::default()
 3666        } else {
 3667            SelectionEffects::no_scroll()
 3668        };
 3669
 3670        self.change_selections(effects, window, cx, |s| {
 3671            if let Some(point_to_delete) = point_to_delete {
 3672                s.delete(point_to_delete);
 3673
 3674                if selections_count == 1 {
 3675                    s.set_pending_anchor_range(start..end, mode);
 3676                }
 3677            } else {
 3678                if !add {
 3679                    s.clear_disjoint();
 3680                }
 3681
 3682                s.set_pending_anchor_range(start..end, mode);
 3683            }
 3684        });
 3685    }
 3686
 3687    fn begin_columnar_selection(
 3688        &mut self,
 3689        position: DisplayPoint,
 3690        goal_column: u32,
 3691        reset: bool,
 3692        mode: ColumnarMode,
 3693        window: &mut Window,
 3694        cx: &mut Context<Self>,
 3695    ) {
 3696        if !self.focus_handle.is_focused(window) {
 3697            self.last_focused_descendant = None;
 3698            window.focus(&self.focus_handle);
 3699        }
 3700
 3701        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3702
 3703        if reset {
 3704            let pointer_position = display_map
 3705                .buffer_snapshot()
 3706                .anchor_before(position.to_point(&display_map));
 3707
 3708            self.change_selections(
 3709                SelectionEffects::scroll(Autoscroll::newest()),
 3710                window,
 3711                cx,
 3712                |s| {
 3713                    s.clear_disjoint();
 3714                    s.set_pending_anchor_range(
 3715                        pointer_position..pointer_position,
 3716                        SelectMode::Character,
 3717                    );
 3718                },
 3719            );
 3720        };
 3721
 3722        let tail = self.selections.newest::<Point>(&display_map).tail();
 3723        let selection_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3724        self.columnar_selection_state = match mode {
 3725            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3726                selection_tail: selection_anchor,
 3727                display_point: if reset {
 3728                    if position.column() != goal_column {
 3729                        Some(DisplayPoint::new(position.row(), goal_column))
 3730                    } else {
 3731                        None
 3732                    }
 3733                } else {
 3734                    None
 3735                },
 3736            }),
 3737            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3738                selection_tail: selection_anchor,
 3739            }),
 3740        };
 3741
 3742        if !reset {
 3743            self.select_columns(position, goal_column, &display_map, window, cx);
 3744        }
 3745    }
 3746
 3747    fn update_selection(
 3748        &mut self,
 3749        position: DisplayPoint,
 3750        goal_column: u32,
 3751        scroll_delta: gpui::Point<f32>,
 3752        window: &mut Window,
 3753        cx: &mut Context<Self>,
 3754    ) {
 3755        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3756
 3757        if self.columnar_selection_state.is_some() {
 3758            self.select_columns(position, goal_column, &display_map, window, cx);
 3759        } else if let Some(mut pending) = self.selections.pending_anchor().cloned() {
 3760            let buffer = display_map.buffer_snapshot();
 3761            let head;
 3762            let tail;
 3763            let mode = self.selections.pending_mode().unwrap();
 3764            match &mode {
 3765                SelectMode::Character => {
 3766                    head = position.to_point(&display_map);
 3767                    tail = pending.tail().to_point(buffer);
 3768                }
 3769                SelectMode::Word(original_range) => {
 3770                    let offset = display_map
 3771                        .clip_point(position, Bias::Left)
 3772                        .to_offset(&display_map, Bias::Left);
 3773                    let original_range = original_range.to_offset(buffer);
 3774
 3775                    let head_offset = if buffer.is_inside_word(offset, None)
 3776                        || original_range.contains(&offset)
 3777                    {
 3778                        let (word_range, _) = buffer.surrounding_word(offset, None);
 3779                        if word_range.start < original_range.start {
 3780                            word_range.start
 3781                        } else {
 3782                            word_range.end
 3783                        }
 3784                    } else {
 3785                        offset
 3786                    };
 3787
 3788                    head = head_offset.to_point(buffer);
 3789                    if head_offset <= original_range.start {
 3790                        tail = original_range.end.to_point(buffer);
 3791                    } else {
 3792                        tail = original_range.start.to_point(buffer);
 3793                    }
 3794                }
 3795                SelectMode::Line(original_range) => {
 3796                    let original_range = original_range.to_point(display_map.buffer_snapshot());
 3797
 3798                    let position = display_map
 3799                        .clip_point(position, Bias::Left)
 3800                        .to_point(&display_map);
 3801                    let line_start = display_map.prev_line_boundary(position).0;
 3802                    let next_line_start = buffer.clip_point(
 3803                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3804                        Bias::Left,
 3805                    );
 3806
 3807                    if line_start < original_range.start {
 3808                        head = line_start
 3809                    } else {
 3810                        head = next_line_start
 3811                    }
 3812
 3813                    if head <= original_range.start {
 3814                        tail = original_range.end;
 3815                    } else {
 3816                        tail = original_range.start;
 3817                    }
 3818                }
 3819                SelectMode::All => {
 3820                    return;
 3821                }
 3822            };
 3823
 3824            if head < tail {
 3825                pending.start = buffer.anchor_before(head);
 3826                pending.end = buffer.anchor_before(tail);
 3827                pending.reversed = true;
 3828            } else {
 3829                pending.start = buffer.anchor_before(tail);
 3830                pending.end = buffer.anchor_before(head);
 3831                pending.reversed = false;
 3832            }
 3833
 3834            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3835                s.set_pending(pending.clone(), mode);
 3836            });
 3837        } else {
 3838            log::error!("update_selection dispatched with no pending selection");
 3839            return;
 3840        }
 3841
 3842        self.apply_scroll_delta(scroll_delta, window, cx);
 3843        cx.notify();
 3844    }
 3845
 3846    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3847        self.columnar_selection_state.take();
 3848        if let Some(pending_mode) = self.selections.pending_mode() {
 3849            let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 3850            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3851                s.select(selections);
 3852                s.clear_pending();
 3853                if s.is_extending() {
 3854                    s.set_is_extending(false);
 3855                } else {
 3856                    s.set_select_mode(pending_mode);
 3857                }
 3858            });
 3859        }
 3860    }
 3861
 3862    fn select_columns(
 3863        &mut self,
 3864        head: DisplayPoint,
 3865        goal_column: u32,
 3866        display_map: &DisplaySnapshot,
 3867        window: &mut Window,
 3868        cx: &mut Context<Self>,
 3869    ) {
 3870        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 3871            return;
 3872        };
 3873
 3874        let tail = match columnar_state {
 3875            ColumnarSelectionState::FromMouse {
 3876                selection_tail,
 3877                display_point,
 3878            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(display_map)),
 3879            ColumnarSelectionState::FromSelection { selection_tail } => {
 3880                selection_tail.to_display_point(display_map)
 3881            }
 3882        };
 3883
 3884        let start_row = cmp::min(tail.row(), head.row());
 3885        let end_row = cmp::max(tail.row(), head.row());
 3886        let start_column = cmp::min(tail.column(), goal_column);
 3887        let end_column = cmp::max(tail.column(), goal_column);
 3888        let reversed = start_column < tail.column();
 3889
 3890        let selection_ranges = (start_row.0..=end_row.0)
 3891            .map(DisplayRow)
 3892            .filter_map(|row| {
 3893                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 3894                    || start_column <= display_map.line_len(row))
 3895                    && !display_map.is_block_line(row)
 3896                {
 3897                    let start = display_map
 3898                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3899                        .to_point(display_map);
 3900                    let end = display_map
 3901                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3902                        .to_point(display_map);
 3903                    if reversed {
 3904                        Some(end..start)
 3905                    } else {
 3906                        Some(start..end)
 3907                    }
 3908                } else {
 3909                    None
 3910                }
 3911            })
 3912            .collect::<Vec<_>>();
 3913        if selection_ranges.is_empty() {
 3914            return;
 3915        }
 3916
 3917        let ranges = match columnar_state {
 3918            ColumnarSelectionState::FromMouse { .. } => {
 3919                let mut non_empty_ranges = selection_ranges
 3920                    .iter()
 3921                    .filter(|selection_range| selection_range.start != selection_range.end)
 3922                    .peekable();
 3923                if non_empty_ranges.peek().is_some() {
 3924                    non_empty_ranges.cloned().collect()
 3925                } else {
 3926                    selection_ranges
 3927                }
 3928            }
 3929            _ => selection_ranges,
 3930        };
 3931
 3932        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3933            s.select_ranges(ranges);
 3934        });
 3935        cx.notify();
 3936    }
 3937
 3938    pub fn has_non_empty_selection(&self, snapshot: &DisplaySnapshot) -> bool {
 3939        self.selections
 3940            .all_adjusted(snapshot)
 3941            .iter()
 3942            .any(|selection| !selection.is_empty())
 3943    }
 3944
 3945    pub fn has_pending_nonempty_selection(&self) -> bool {
 3946        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3947            Some(Selection { start, end, .. }) => start != end,
 3948            None => false,
 3949        };
 3950
 3951        pending_nonempty_selection
 3952            || (self.columnar_selection_state.is_some()
 3953                && self.selections.disjoint_anchors().len() > 1)
 3954    }
 3955
 3956    pub fn has_pending_selection(&self) -> bool {
 3957        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 3958    }
 3959
 3960    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3961        self.selection_mark_mode = false;
 3962        self.selection_drag_state = SelectionDragState::None;
 3963
 3964        if self.clear_expanded_diff_hunks(cx) {
 3965            cx.notify();
 3966            return;
 3967        }
 3968        if self.dismiss_menus_and_popups(true, window, cx) {
 3969            return;
 3970        }
 3971
 3972        if self.mode.is_full()
 3973            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 3974        {
 3975            return;
 3976        }
 3977
 3978        cx.propagate();
 3979    }
 3980
 3981    pub fn dismiss_menus_and_popups(
 3982        &mut self,
 3983        is_user_requested: bool,
 3984        window: &mut Window,
 3985        cx: &mut Context<Self>,
 3986    ) -> bool {
 3987        if self.take_rename(false, window, cx).is_some() {
 3988            return true;
 3989        }
 3990
 3991        if self.hide_blame_popover(true, cx) {
 3992            return true;
 3993        }
 3994
 3995        if hide_hover(self, cx) {
 3996            return true;
 3997        }
 3998
 3999        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 4000            return true;
 4001        }
 4002
 4003        if self.hide_context_menu(window, cx).is_some() {
 4004            return true;
 4005        }
 4006
 4007        if self.mouse_context_menu.take().is_some() {
 4008            return true;
 4009        }
 4010
 4011        if is_user_requested && self.discard_edit_prediction(true, cx) {
 4012            return true;
 4013        }
 4014
 4015        if self.snippet_stack.pop().is_some() {
 4016            return true;
 4017        }
 4018
 4019        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 4020            self.dismiss_diagnostics(cx);
 4021            return true;
 4022        }
 4023
 4024        false
 4025    }
 4026
 4027    fn linked_editing_ranges_for(
 4028        &self,
 4029        selection: Range<text::Anchor>,
 4030        cx: &App,
 4031    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 4032        if self.linked_edit_ranges.is_empty() {
 4033            return None;
 4034        }
 4035        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 4036            selection.end.buffer_id.and_then(|end_buffer_id| {
 4037                if selection.start.buffer_id != Some(end_buffer_id) {
 4038                    return None;
 4039                }
 4040                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 4041                let snapshot = buffer.read(cx).snapshot();
 4042                self.linked_edit_ranges
 4043                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 4044                    .map(|ranges| (ranges, snapshot, buffer))
 4045            })?;
 4046        use text::ToOffset as TO;
 4047        // find offset from the start of current range to current cursor position
 4048        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 4049
 4050        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 4051        let start_difference = start_offset - start_byte_offset;
 4052        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 4053        let end_difference = end_offset - start_byte_offset;
 4054        // Current range has associated linked ranges.
 4055        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4056        for range in linked_ranges.iter() {
 4057            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 4058            let end_offset = start_offset + end_difference;
 4059            let start_offset = start_offset + start_difference;
 4060            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 4061                continue;
 4062            }
 4063            if self.selections.disjoint_anchor_ranges().any(|s| {
 4064                if s.start.buffer_id != selection.start.buffer_id
 4065                    || s.end.buffer_id != selection.end.buffer_id
 4066                {
 4067                    return false;
 4068                }
 4069                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 4070                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 4071            }) {
 4072                continue;
 4073            }
 4074            let start = buffer_snapshot.anchor_after(start_offset);
 4075            let end = buffer_snapshot.anchor_after(end_offset);
 4076            linked_edits
 4077                .entry(buffer.clone())
 4078                .or_default()
 4079                .push(start..end);
 4080        }
 4081        Some(linked_edits)
 4082    }
 4083
 4084    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4085        let text: Arc<str> = text.into();
 4086
 4087        if self.read_only(cx) {
 4088            return;
 4089        }
 4090
 4091        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4092
 4093        let selections = self.selections.all_adjusted(&self.display_snapshot(cx));
 4094        let mut bracket_inserted = false;
 4095        let mut edits = Vec::new();
 4096        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4097        let mut new_selections = Vec::with_capacity(selections.len());
 4098        let mut new_autoclose_regions = Vec::new();
 4099        let snapshot = self.buffer.read(cx).read(cx);
 4100        let mut clear_linked_edit_ranges = false;
 4101
 4102        for (selection, autoclose_region) in
 4103            self.selections_with_autoclose_regions(selections, &snapshot)
 4104        {
 4105            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 4106                // Determine if the inserted text matches the opening or closing
 4107                // bracket of any of this language's bracket pairs.
 4108                let mut bracket_pair = None;
 4109                let mut is_bracket_pair_start = false;
 4110                let mut is_bracket_pair_end = false;
 4111                if !text.is_empty() {
 4112                    let mut bracket_pair_matching_end = None;
 4113                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 4114                    //  and they are removing the character that triggered IME popup.
 4115                    for (pair, enabled) in scope.brackets() {
 4116                        if !pair.close && !pair.surround {
 4117                            continue;
 4118                        }
 4119
 4120                        if enabled && pair.start.ends_with(text.as_ref()) {
 4121                            let prefix_len = pair.start.len() - text.len();
 4122                            let preceding_text_matches_prefix = prefix_len == 0
 4123                                || (selection.start.column >= (prefix_len as u32)
 4124                                    && snapshot.contains_str_at(
 4125                                        Point::new(
 4126                                            selection.start.row,
 4127                                            selection.start.column - (prefix_len as u32),
 4128                                        ),
 4129                                        &pair.start[..prefix_len],
 4130                                    ));
 4131                            if preceding_text_matches_prefix {
 4132                                bracket_pair = Some(pair.clone());
 4133                                is_bracket_pair_start = true;
 4134                                break;
 4135                            }
 4136                        }
 4137                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 4138                        {
 4139                            // take first bracket pair matching end, but don't break in case a later bracket
 4140                            // pair matches start
 4141                            bracket_pair_matching_end = Some(pair.clone());
 4142                        }
 4143                    }
 4144                    if let Some(end) = bracket_pair_matching_end
 4145                        && bracket_pair.is_none()
 4146                    {
 4147                        bracket_pair = Some(end);
 4148                        is_bracket_pair_end = true;
 4149                    }
 4150                }
 4151
 4152                if let Some(bracket_pair) = bracket_pair {
 4153                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 4154                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 4155                    let auto_surround =
 4156                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 4157                    if selection.is_empty() {
 4158                        if is_bracket_pair_start {
 4159                            // If the inserted text is a suffix of an opening bracket and the
 4160                            // selection is preceded by the rest of the opening bracket, then
 4161                            // insert the closing bracket.
 4162                            let following_text_allows_autoclose = snapshot
 4163                                .chars_at(selection.start)
 4164                                .next()
 4165                                .is_none_or(|c| scope.should_autoclose_before(c));
 4166
 4167                            let preceding_text_allows_autoclose = selection.start.column == 0
 4168                                || snapshot
 4169                                    .reversed_chars_at(selection.start)
 4170                                    .next()
 4171                                    .is_none_or(|c| {
 4172                                        bracket_pair.start != bracket_pair.end
 4173                                            || !snapshot
 4174                                                .char_classifier_at(selection.start)
 4175                                                .is_word(c)
 4176                                    });
 4177
 4178                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4179                                && bracket_pair.start.len() == 1
 4180                            {
 4181                                let target = bracket_pair.start.chars().next().unwrap();
 4182                                let current_line_count = snapshot
 4183                                    .reversed_chars_at(selection.start)
 4184                                    .take_while(|&c| c != '\n')
 4185                                    .filter(|&c| c == target)
 4186                                    .count();
 4187                                current_line_count % 2 == 1
 4188                            } else {
 4189                                false
 4190                            };
 4191
 4192                            if autoclose
 4193                                && bracket_pair.close
 4194                                && following_text_allows_autoclose
 4195                                && preceding_text_allows_autoclose
 4196                                && !is_closing_quote
 4197                            {
 4198                                let anchor = snapshot.anchor_before(selection.end);
 4199                                new_selections.push((selection.map(|_| anchor), text.len()));
 4200                                new_autoclose_regions.push((
 4201                                    anchor,
 4202                                    text.len(),
 4203                                    selection.id,
 4204                                    bracket_pair.clone(),
 4205                                ));
 4206                                edits.push((
 4207                                    selection.range(),
 4208                                    format!("{}{}", text, bracket_pair.end).into(),
 4209                                ));
 4210                                bracket_inserted = true;
 4211                                continue;
 4212                            }
 4213                        }
 4214
 4215                        if let Some(region) = autoclose_region {
 4216                            // If the selection is followed by an auto-inserted closing bracket,
 4217                            // then don't insert that closing bracket again; just move the selection
 4218                            // past the closing bracket.
 4219                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4220                                && text.as_ref() == region.pair.end.as_str()
 4221                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4222                            if should_skip {
 4223                                let anchor = snapshot.anchor_after(selection.end);
 4224                                new_selections
 4225                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4226                                continue;
 4227                            }
 4228                        }
 4229
 4230                        let always_treat_brackets_as_autoclosed = snapshot
 4231                            .language_settings_at(selection.start, cx)
 4232                            .always_treat_brackets_as_autoclosed;
 4233                        if always_treat_brackets_as_autoclosed
 4234                            && is_bracket_pair_end
 4235                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4236                        {
 4237                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4238                            // and the inserted text is a closing bracket and the selection is followed
 4239                            // by the closing bracket then move the selection past the closing bracket.
 4240                            let anchor = snapshot.anchor_after(selection.end);
 4241                            new_selections.push((selection.map(|_| anchor), text.len()));
 4242                            continue;
 4243                        }
 4244                    }
 4245                    // If an opening bracket is 1 character long and is typed while
 4246                    // text is selected, then surround that text with the bracket pair.
 4247                    else if auto_surround
 4248                        && bracket_pair.surround
 4249                        && is_bracket_pair_start
 4250                        && bracket_pair.start.chars().count() == 1
 4251                    {
 4252                        edits.push((selection.start..selection.start, text.clone()));
 4253                        edits.push((
 4254                            selection.end..selection.end,
 4255                            bracket_pair.end.as_str().into(),
 4256                        ));
 4257                        bracket_inserted = true;
 4258                        new_selections.push((
 4259                            Selection {
 4260                                id: selection.id,
 4261                                start: snapshot.anchor_after(selection.start),
 4262                                end: snapshot.anchor_before(selection.end),
 4263                                reversed: selection.reversed,
 4264                                goal: selection.goal,
 4265                            },
 4266                            0,
 4267                        ));
 4268                        continue;
 4269                    }
 4270                }
 4271            }
 4272
 4273            if self.auto_replace_emoji_shortcode
 4274                && selection.is_empty()
 4275                && text.as_ref().ends_with(':')
 4276                && let Some(possible_emoji_short_code) =
 4277                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4278                && !possible_emoji_short_code.is_empty()
 4279                && let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code)
 4280            {
 4281                let emoji_shortcode_start = Point::new(
 4282                    selection.start.row,
 4283                    selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4284                );
 4285
 4286                // Remove shortcode from buffer
 4287                edits.push((
 4288                    emoji_shortcode_start..selection.start,
 4289                    "".to_string().into(),
 4290                ));
 4291                new_selections.push((
 4292                    Selection {
 4293                        id: selection.id,
 4294                        start: snapshot.anchor_after(emoji_shortcode_start),
 4295                        end: snapshot.anchor_before(selection.start),
 4296                        reversed: selection.reversed,
 4297                        goal: selection.goal,
 4298                    },
 4299                    0,
 4300                ));
 4301
 4302                // Insert emoji
 4303                let selection_start_anchor = snapshot.anchor_after(selection.start);
 4304                new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4305                edits.push((selection.start..selection.end, emoji.to_string().into()));
 4306
 4307                continue;
 4308            }
 4309
 4310            // If not handling any auto-close operation, then just replace the selected
 4311            // text with the given input and move the selection to the end of the
 4312            // newly inserted text.
 4313            let anchor = snapshot.anchor_after(selection.end);
 4314            if !self.linked_edit_ranges.is_empty() {
 4315                let start_anchor = snapshot.anchor_before(selection.start);
 4316
 4317                let is_word_char = text.chars().next().is_none_or(|char| {
 4318                    let classifier = snapshot
 4319                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4320                        .scope_context(Some(CharScopeContext::LinkedEdit));
 4321                    classifier.is_word(char)
 4322                });
 4323
 4324                if is_word_char {
 4325                    if let Some(ranges) = self
 4326                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4327                    {
 4328                        for (buffer, edits) in ranges {
 4329                            linked_edits
 4330                                .entry(buffer.clone())
 4331                                .or_default()
 4332                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4333                        }
 4334                    }
 4335                } else {
 4336                    clear_linked_edit_ranges = true;
 4337                }
 4338            }
 4339
 4340            new_selections.push((selection.map(|_| anchor), 0));
 4341            edits.push((selection.start..selection.end, text.clone()));
 4342        }
 4343
 4344        drop(snapshot);
 4345
 4346        self.transact(window, cx, |this, window, cx| {
 4347            if clear_linked_edit_ranges {
 4348                this.linked_edit_ranges.clear();
 4349            }
 4350            let initial_buffer_versions =
 4351                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4352
 4353            this.buffer.update(cx, |buffer, cx| {
 4354                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4355            });
 4356            for (buffer, edits) in linked_edits {
 4357                buffer.update(cx, |buffer, cx| {
 4358                    let snapshot = buffer.snapshot();
 4359                    let edits = edits
 4360                        .into_iter()
 4361                        .map(|(range, text)| {
 4362                            use text::ToPoint as TP;
 4363                            let end_point = TP::to_point(&range.end, &snapshot);
 4364                            let start_point = TP::to_point(&range.start, &snapshot);
 4365                            (start_point..end_point, text)
 4366                        })
 4367                        .sorted_by_key(|(range, _)| range.start);
 4368                    buffer.edit(edits, None, cx);
 4369                })
 4370            }
 4371            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4372            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4373            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4374            let new_selections =
 4375                resolve_selections_wrapping_blocks::<usize, _>(new_anchor_selections, &map)
 4376                    .zip(new_selection_deltas)
 4377                    .map(|(selection, delta)| Selection {
 4378                        id: selection.id,
 4379                        start: selection.start + delta,
 4380                        end: selection.end + delta,
 4381                        reversed: selection.reversed,
 4382                        goal: SelectionGoal::None,
 4383                    })
 4384                    .collect::<Vec<_>>();
 4385
 4386            let mut i = 0;
 4387            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4388                let position = position.to_offset(map.buffer_snapshot()) + delta;
 4389                let start = map.buffer_snapshot().anchor_before(position);
 4390                let end = map.buffer_snapshot().anchor_after(position);
 4391                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4392                    match existing_state
 4393                        .range
 4394                        .start
 4395                        .cmp(&start, map.buffer_snapshot())
 4396                    {
 4397                        Ordering::Less => i += 1,
 4398                        Ordering::Greater => break,
 4399                        Ordering::Equal => {
 4400                            match end.cmp(&existing_state.range.end, map.buffer_snapshot()) {
 4401                                Ordering::Less => i += 1,
 4402                                Ordering::Equal => break,
 4403                                Ordering::Greater => break,
 4404                            }
 4405                        }
 4406                    }
 4407                }
 4408                this.autoclose_regions.insert(
 4409                    i,
 4410                    AutocloseRegion {
 4411                        selection_id,
 4412                        range: start..end,
 4413                        pair,
 4414                    },
 4415                );
 4416            }
 4417
 4418            let had_active_edit_prediction = this.has_active_edit_prediction();
 4419            this.change_selections(
 4420                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4421                window,
 4422                cx,
 4423                |s| s.select(new_selections),
 4424            );
 4425
 4426            if !bracket_inserted
 4427                && let Some(on_type_format_task) =
 4428                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4429            {
 4430                on_type_format_task.detach_and_log_err(cx);
 4431            }
 4432
 4433            let editor_settings = EditorSettings::get_global(cx);
 4434            if bracket_inserted
 4435                && (editor_settings.auto_signature_help
 4436                    || editor_settings.show_signature_help_after_edits)
 4437            {
 4438                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4439            }
 4440
 4441            let trigger_in_words =
 4442                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 4443            if this.hard_wrap.is_some() {
 4444                let latest: Range<Point> = this.selections.newest(&map).range();
 4445                if latest.is_empty()
 4446                    && this
 4447                        .buffer()
 4448                        .read(cx)
 4449                        .snapshot(cx)
 4450                        .line_len(MultiBufferRow(latest.start.row))
 4451                        == latest.start.column
 4452                {
 4453                    this.rewrap_impl(
 4454                        RewrapOptions {
 4455                            override_language_settings: true,
 4456                            preserve_existing_whitespace: true,
 4457                        },
 4458                        cx,
 4459                    )
 4460                }
 4461            }
 4462            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4463            refresh_linked_ranges(this, window, cx);
 4464            this.refresh_edit_prediction(true, false, window, cx);
 4465            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4466        });
 4467    }
 4468
 4469    fn find_possible_emoji_shortcode_at_position(
 4470        snapshot: &MultiBufferSnapshot,
 4471        position: Point,
 4472    ) -> Option<String> {
 4473        let mut chars = Vec::new();
 4474        let mut found_colon = false;
 4475        for char in snapshot.reversed_chars_at(position).take(100) {
 4476            // Found a possible emoji shortcode in the middle of the buffer
 4477            if found_colon {
 4478                if char.is_whitespace() {
 4479                    chars.reverse();
 4480                    return Some(chars.iter().collect());
 4481                }
 4482                // If the previous character is not a whitespace, we are in the middle of a word
 4483                // and we only want to complete the shortcode if the word is made up of other emojis
 4484                let mut containing_word = String::new();
 4485                for ch in snapshot
 4486                    .reversed_chars_at(position)
 4487                    .skip(chars.len() + 1)
 4488                    .take(100)
 4489                {
 4490                    if ch.is_whitespace() {
 4491                        break;
 4492                    }
 4493                    containing_word.push(ch);
 4494                }
 4495                let containing_word = containing_word.chars().rev().collect::<String>();
 4496                if util::word_consists_of_emojis(containing_word.as_str()) {
 4497                    chars.reverse();
 4498                    return Some(chars.iter().collect());
 4499                }
 4500            }
 4501
 4502            if char.is_whitespace() || !char.is_ascii() {
 4503                return None;
 4504            }
 4505            if char == ':' {
 4506                found_colon = true;
 4507            } else {
 4508                chars.push(char);
 4509            }
 4510        }
 4511        // Found a possible emoji shortcode at the beginning of the buffer
 4512        chars.reverse();
 4513        Some(chars.iter().collect())
 4514    }
 4515
 4516    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4517        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4518        self.transact(window, cx, |this, window, cx| {
 4519            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4520                let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
 4521                let multi_buffer = this.buffer.read(cx);
 4522                let buffer = multi_buffer.snapshot(cx);
 4523                selections
 4524                    .iter()
 4525                    .map(|selection| {
 4526                        let start_point = selection.start.to_point(&buffer);
 4527                        let mut existing_indent =
 4528                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4529                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4530                        let start = selection.start;
 4531                        let end = selection.end;
 4532                        let selection_is_empty = start == end;
 4533                        let language_scope = buffer.language_scope_at(start);
 4534                        let (
 4535                            comment_delimiter,
 4536                            doc_delimiter,
 4537                            insert_extra_newline,
 4538                            indent_on_newline,
 4539                            indent_on_extra_newline,
 4540                        ) = if let Some(language) = &language_scope {
 4541                            let mut insert_extra_newline =
 4542                                insert_extra_newline_brackets(&buffer, start..end, language)
 4543                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4544
 4545                            // Comment extension on newline is allowed only for cursor selections
 4546                            let comment_delimiter = maybe!({
 4547                                if !selection_is_empty {
 4548                                    return None;
 4549                                }
 4550
 4551                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4552                                    return None;
 4553                                }
 4554
 4555                                let delimiters = language.line_comment_prefixes();
 4556                                let max_len_of_delimiter =
 4557                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4558                                let (snapshot, range) =
 4559                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4560
 4561                                let num_of_whitespaces = snapshot
 4562                                    .chars_for_range(range.clone())
 4563                                    .take_while(|c| c.is_whitespace())
 4564                                    .count();
 4565                                let comment_candidate = snapshot
 4566                                    .chars_for_range(range.clone())
 4567                                    .skip(num_of_whitespaces)
 4568                                    .take(max_len_of_delimiter)
 4569                                    .collect::<String>();
 4570                                let (delimiter, trimmed_len) = delimiters
 4571                                    .iter()
 4572                                    .filter_map(|delimiter| {
 4573                                        let prefix = delimiter.trim_end();
 4574                                        if comment_candidate.starts_with(prefix) {
 4575                                            Some((delimiter, prefix.len()))
 4576                                        } else {
 4577                                            None
 4578                                        }
 4579                                    })
 4580                                    .max_by_key(|(_, len)| *len)?;
 4581
 4582                                if let Some(BlockCommentConfig {
 4583                                    start: block_start, ..
 4584                                }) = language.block_comment()
 4585                                {
 4586                                    let block_start_trimmed = block_start.trim_end();
 4587                                    if block_start_trimmed.starts_with(delimiter.trim_end()) {
 4588                                        let line_content = snapshot
 4589                                            .chars_for_range(range)
 4590                                            .skip(num_of_whitespaces)
 4591                                            .take(block_start_trimmed.len())
 4592                                            .collect::<String>();
 4593
 4594                                        if line_content.starts_with(block_start_trimmed) {
 4595                                            return None;
 4596                                        }
 4597                                    }
 4598                                }
 4599
 4600                                let cursor_is_placed_after_comment_marker =
 4601                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4602                                if cursor_is_placed_after_comment_marker {
 4603                                    Some(delimiter.clone())
 4604                                } else {
 4605                                    None
 4606                                }
 4607                            });
 4608
 4609                            let mut indent_on_newline = IndentSize::spaces(0);
 4610                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4611
 4612                            let doc_delimiter = maybe!({
 4613                                if !selection_is_empty {
 4614                                    return None;
 4615                                }
 4616
 4617                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4618                                    return None;
 4619                                }
 4620
 4621                                let BlockCommentConfig {
 4622                                    start: start_tag,
 4623                                    end: end_tag,
 4624                                    prefix: delimiter,
 4625                                    tab_size: len,
 4626                                } = language.documentation_comment()?;
 4627                                let is_within_block_comment = buffer
 4628                                    .language_scope_at(start_point)
 4629                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4630                                if !is_within_block_comment {
 4631                                    return None;
 4632                                }
 4633
 4634                                let (snapshot, range) =
 4635                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4636
 4637                                let num_of_whitespaces = snapshot
 4638                                    .chars_for_range(range.clone())
 4639                                    .take_while(|c| c.is_whitespace())
 4640                                    .count();
 4641
 4642                                // It is safe to use a column from MultiBufferPoint in context of a single buffer ranges, because we're only ever looking at a single line at a time.
 4643                                let column = start_point.column;
 4644                                let cursor_is_after_start_tag = {
 4645                                    let start_tag_len = start_tag.len();
 4646                                    let start_tag_line = snapshot
 4647                                        .chars_for_range(range.clone())
 4648                                        .skip(num_of_whitespaces)
 4649                                        .take(start_tag_len)
 4650                                        .collect::<String>();
 4651                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4652                                        num_of_whitespaces + start_tag_len <= column as usize
 4653                                    } else {
 4654                                        false
 4655                                    }
 4656                                };
 4657
 4658                                let cursor_is_after_delimiter = {
 4659                                    let delimiter_trim = delimiter.trim_end();
 4660                                    let delimiter_line = snapshot
 4661                                        .chars_for_range(range.clone())
 4662                                        .skip(num_of_whitespaces)
 4663                                        .take(delimiter_trim.len())
 4664                                        .collect::<String>();
 4665                                    if delimiter_line.starts_with(delimiter_trim) {
 4666                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4667                                    } else {
 4668                                        false
 4669                                    }
 4670                                };
 4671
 4672                                let cursor_is_before_end_tag_if_exists = {
 4673                                    let mut char_position = 0u32;
 4674                                    let mut end_tag_offset = None;
 4675
 4676                                    'outer: for chunk in snapshot.text_for_range(range) {
 4677                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4678                                            let chars_before_match =
 4679                                                chunk[..byte_pos].chars().count() as u32;
 4680                                            end_tag_offset =
 4681                                                Some(char_position + chars_before_match);
 4682                                            break 'outer;
 4683                                        }
 4684                                        char_position += chunk.chars().count() as u32;
 4685                                    }
 4686
 4687                                    if let Some(end_tag_offset) = end_tag_offset {
 4688                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4689                                        if cursor_is_after_start_tag {
 4690                                            if cursor_is_before_end_tag {
 4691                                                insert_extra_newline = true;
 4692                                            }
 4693                                            let cursor_is_at_start_of_end_tag =
 4694                                                column == end_tag_offset;
 4695                                            if cursor_is_at_start_of_end_tag {
 4696                                                indent_on_extra_newline.len = *len;
 4697                                            }
 4698                                        }
 4699                                        cursor_is_before_end_tag
 4700                                    } else {
 4701                                        true
 4702                                    }
 4703                                };
 4704
 4705                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4706                                    && cursor_is_before_end_tag_if_exists
 4707                                {
 4708                                    if cursor_is_after_start_tag {
 4709                                        indent_on_newline.len = *len;
 4710                                    }
 4711                                    Some(delimiter.clone())
 4712                                } else {
 4713                                    None
 4714                                }
 4715                            });
 4716
 4717                            (
 4718                                comment_delimiter,
 4719                                doc_delimiter,
 4720                                insert_extra_newline,
 4721                                indent_on_newline,
 4722                                indent_on_extra_newline,
 4723                            )
 4724                        } else {
 4725                            (
 4726                                None,
 4727                                None,
 4728                                false,
 4729                                IndentSize::default(),
 4730                                IndentSize::default(),
 4731                            )
 4732                        };
 4733
 4734                        let prevent_auto_indent = doc_delimiter.is_some();
 4735                        let delimiter = comment_delimiter.or(doc_delimiter);
 4736
 4737                        let capacity_for_delimiter =
 4738                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4739                        let mut new_text = String::with_capacity(
 4740                            1 + capacity_for_delimiter
 4741                                + existing_indent.len as usize
 4742                                + indent_on_newline.len as usize
 4743                                + indent_on_extra_newline.len as usize,
 4744                        );
 4745                        new_text.push('\n');
 4746                        new_text.extend(existing_indent.chars());
 4747                        new_text.extend(indent_on_newline.chars());
 4748
 4749                        if let Some(delimiter) = &delimiter {
 4750                            new_text.push_str(delimiter);
 4751                        }
 4752
 4753                        if insert_extra_newline {
 4754                            new_text.push('\n');
 4755                            new_text.extend(existing_indent.chars());
 4756                            new_text.extend(indent_on_extra_newline.chars());
 4757                        }
 4758
 4759                        let anchor = buffer.anchor_after(end);
 4760                        let new_selection = selection.map(|_| anchor);
 4761                        (
 4762                            ((start..end, new_text), prevent_auto_indent),
 4763                            (insert_extra_newline, new_selection),
 4764                        )
 4765                    })
 4766                    .unzip()
 4767            };
 4768
 4769            let mut auto_indent_edits = Vec::new();
 4770            let mut edits = Vec::new();
 4771            for (edit, prevent_auto_indent) in edits_with_flags {
 4772                if prevent_auto_indent {
 4773                    edits.push(edit);
 4774                } else {
 4775                    auto_indent_edits.push(edit);
 4776                }
 4777            }
 4778            if !edits.is_empty() {
 4779                this.edit(edits, cx);
 4780            }
 4781            if !auto_indent_edits.is_empty() {
 4782                this.edit_with_autoindent(auto_indent_edits, cx);
 4783            }
 4784
 4785            let buffer = this.buffer.read(cx).snapshot(cx);
 4786            let new_selections = selection_info
 4787                .into_iter()
 4788                .map(|(extra_newline_inserted, new_selection)| {
 4789                    let mut cursor = new_selection.end.to_point(&buffer);
 4790                    if extra_newline_inserted {
 4791                        cursor.row -= 1;
 4792                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4793                    }
 4794                    new_selection.map(|_| cursor)
 4795                })
 4796                .collect();
 4797
 4798            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 4799            this.refresh_edit_prediction(true, false, window, cx);
 4800        });
 4801    }
 4802
 4803    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4804        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4805
 4806        let buffer = self.buffer.read(cx);
 4807        let snapshot = buffer.snapshot(cx);
 4808
 4809        let mut edits = Vec::new();
 4810        let mut rows = Vec::new();
 4811
 4812        for (rows_inserted, selection) in self
 4813            .selections
 4814            .all_adjusted(&self.display_snapshot(cx))
 4815            .into_iter()
 4816            .enumerate()
 4817        {
 4818            let cursor = selection.head();
 4819            let row = cursor.row;
 4820
 4821            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4822
 4823            let newline = "\n".to_string();
 4824            edits.push((start_of_line..start_of_line, newline));
 4825
 4826            rows.push(row + rows_inserted as u32);
 4827        }
 4828
 4829        self.transact(window, cx, |editor, window, cx| {
 4830            editor.edit(edits, cx);
 4831
 4832            editor.change_selections(Default::default(), window, cx, |s| {
 4833                let mut index = 0;
 4834                s.move_cursors_with(|map, _, _| {
 4835                    let row = rows[index];
 4836                    index += 1;
 4837
 4838                    let point = Point::new(row, 0);
 4839                    let boundary = map.next_line_boundary(point).1;
 4840                    let clipped = map.clip_point(boundary, Bias::Left);
 4841
 4842                    (clipped, SelectionGoal::None)
 4843                });
 4844            });
 4845
 4846            let mut indent_edits = Vec::new();
 4847            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4848            for row in rows {
 4849                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4850                for (row, indent) in indents {
 4851                    if indent.len == 0 {
 4852                        continue;
 4853                    }
 4854
 4855                    let text = match indent.kind {
 4856                        IndentKind::Space => " ".repeat(indent.len as usize),
 4857                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4858                    };
 4859                    let point = Point::new(row.0, 0);
 4860                    indent_edits.push((point..point, text));
 4861                }
 4862            }
 4863            editor.edit(indent_edits, cx);
 4864        });
 4865    }
 4866
 4867    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4868        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4869
 4870        let buffer = self.buffer.read(cx);
 4871        let snapshot = buffer.snapshot(cx);
 4872
 4873        let mut edits = Vec::new();
 4874        let mut rows = Vec::new();
 4875        let mut rows_inserted = 0;
 4876
 4877        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
 4878            let cursor = selection.head();
 4879            let row = cursor.row;
 4880
 4881            let point = Point::new(row + 1, 0);
 4882            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4883
 4884            let newline = "\n".to_string();
 4885            edits.push((start_of_line..start_of_line, newline));
 4886
 4887            rows_inserted += 1;
 4888            rows.push(row + rows_inserted);
 4889        }
 4890
 4891        self.transact(window, cx, |editor, window, cx| {
 4892            editor.edit(edits, cx);
 4893
 4894            editor.change_selections(Default::default(), window, cx, |s| {
 4895                let mut index = 0;
 4896                s.move_cursors_with(|map, _, _| {
 4897                    let row = rows[index];
 4898                    index += 1;
 4899
 4900                    let point = Point::new(row, 0);
 4901                    let boundary = map.next_line_boundary(point).1;
 4902                    let clipped = map.clip_point(boundary, Bias::Left);
 4903
 4904                    (clipped, SelectionGoal::None)
 4905                });
 4906            });
 4907
 4908            let mut indent_edits = Vec::new();
 4909            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4910            for row in rows {
 4911                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4912                for (row, indent) in indents {
 4913                    if indent.len == 0 {
 4914                        continue;
 4915                    }
 4916
 4917                    let text = match indent.kind {
 4918                        IndentKind::Space => " ".repeat(indent.len as usize),
 4919                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4920                    };
 4921                    let point = Point::new(row.0, 0);
 4922                    indent_edits.push((point..point, text));
 4923                }
 4924            }
 4925            editor.edit(indent_edits, cx);
 4926        });
 4927    }
 4928
 4929    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4930        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4931            original_indent_columns: Vec::new(),
 4932        });
 4933        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4934    }
 4935
 4936    fn insert_with_autoindent_mode(
 4937        &mut self,
 4938        text: &str,
 4939        autoindent_mode: Option<AutoindentMode>,
 4940        window: &mut Window,
 4941        cx: &mut Context<Self>,
 4942    ) {
 4943        if self.read_only(cx) {
 4944            return;
 4945        }
 4946
 4947        let text: Arc<str> = text.into();
 4948        self.transact(window, cx, |this, window, cx| {
 4949            let old_selections = this.selections.all_adjusted(&this.display_snapshot(cx));
 4950            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4951                let anchors = {
 4952                    let snapshot = buffer.read(cx);
 4953                    old_selections
 4954                        .iter()
 4955                        .map(|s| {
 4956                            let anchor = snapshot.anchor_after(s.head());
 4957                            s.map(|_| anchor)
 4958                        })
 4959                        .collect::<Vec<_>>()
 4960                };
 4961                buffer.edit(
 4962                    old_selections
 4963                        .iter()
 4964                        .map(|s| (s.start..s.end, text.clone())),
 4965                    autoindent_mode,
 4966                    cx,
 4967                );
 4968                anchors
 4969            });
 4970
 4971            this.change_selections(Default::default(), window, cx, |s| {
 4972                s.select_anchors(selection_anchors);
 4973            });
 4974
 4975            cx.notify();
 4976        });
 4977    }
 4978
 4979    fn trigger_completion_on_input(
 4980        &mut self,
 4981        text: &str,
 4982        trigger_in_words: bool,
 4983        window: &mut Window,
 4984        cx: &mut Context<Self>,
 4985    ) {
 4986        let completions_source = self
 4987            .context_menu
 4988            .borrow()
 4989            .as_ref()
 4990            .and_then(|menu| match menu {
 4991                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 4992                CodeContextMenu::CodeActions(_) => None,
 4993            });
 4994
 4995        match completions_source {
 4996            Some(CompletionsMenuSource::Words { .. }) => {
 4997                self.open_or_update_completions_menu(
 4998                    Some(CompletionsMenuSource::Words {
 4999                        ignore_threshold: false,
 5000                    }),
 5001                    None,
 5002                    window,
 5003                    cx,
 5004                );
 5005            }
 5006            Some(CompletionsMenuSource::Normal)
 5007            | Some(CompletionsMenuSource::SnippetChoices)
 5008            | None
 5009                if self.is_completion_trigger(
 5010                    text,
 5011                    trigger_in_words,
 5012                    completions_source.is_some(),
 5013                    cx,
 5014                ) =>
 5015            {
 5016                self.show_completions(
 5017                    &ShowCompletions {
 5018                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 5019                    },
 5020                    window,
 5021                    cx,
 5022                )
 5023            }
 5024            _ => {
 5025                self.hide_context_menu(window, cx);
 5026            }
 5027        }
 5028    }
 5029
 5030    fn is_completion_trigger(
 5031        &self,
 5032        text: &str,
 5033        trigger_in_words: bool,
 5034        menu_is_open: bool,
 5035        cx: &mut Context<Self>,
 5036    ) -> bool {
 5037        let position = self.selections.newest_anchor().head();
 5038        let Some(buffer) = self.buffer.read(cx).buffer_for_anchor(position, cx) else {
 5039            return false;
 5040        };
 5041
 5042        if let Some(completion_provider) = &self.completion_provider {
 5043            completion_provider.is_completion_trigger(
 5044                &buffer,
 5045                position.text_anchor,
 5046                text,
 5047                trigger_in_words,
 5048                menu_is_open,
 5049                cx,
 5050            )
 5051        } else {
 5052            false
 5053        }
 5054    }
 5055
 5056    /// If any empty selections is touching the start of its innermost containing autoclose
 5057    /// region, expand it to select the brackets.
 5058    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 5059        let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 5060        let buffer = self.buffer.read(cx).read(cx);
 5061        let new_selections = self
 5062            .selections_with_autoclose_regions(selections, &buffer)
 5063            .map(|(mut selection, region)| {
 5064                if !selection.is_empty() {
 5065                    return selection;
 5066                }
 5067
 5068                if let Some(region) = region {
 5069                    let mut range = region.range.to_offset(&buffer);
 5070                    if selection.start == range.start && range.start >= region.pair.start.len() {
 5071                        range.start -= region.pair.start.len();
 5072                        if buffer.contains_str_at(range.start, &region.pair.start)
 5073                            && buffer.contains_str_at(range.end, &region.pair.end)
 5074                        {
 5075                            range.end += region.pair.end.len();
 5076                            selection.start = range.start;
 5077                            selection.end = range.end;
 5078
 5079                            return selection;
 5080                        }
 5081                    }
 5082                }
 5083
 5084                let always_treat_brackets_as_autoclosed = buffer
 5085                    .language_settings_at(selection.start, cx)
 5086                    .always_treat_brackets_as_autoclosed;
 5087
 5088                if !always_treat_brackets_as_autoclosed {
 5089                    return selection;
 5090                }
 5091
 5092                if let Some(scope) = buffer.language_scope_at(selection.start) {
 5093                    for (pair, enabled) in scope.brackets() {
 5094                        if !enabled || !pair.close {
 5095                            continue;
 5096                        }
 5097
 5098                        if buffer.contains_str_at(selection.start, &pair.end) {
 5099                            let pair_start_len = pair.start.len();
 5100                            if buffer.contains_str_at(
 5101                                selection.start.saturating_sub(pair_start_len),
 5102                                &pair.start,
 5103                            ) {
 5104                                selection.start -= pair_start_len;
 5105                                selection.end += pair.end.len();
 5106
 5107                                return selection;
 5108                            }
 5109                        }
 5110                    }
 5111                }
 5112
 5113                selection
 5114            })
 5115            .collect();
 5116
 5117        drop(buffer);
 5118        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 5119            selections.select(new_selections)
 5120        });
 5121    }
 5122
 5123    /// Iterate the given selections, and for each one, find the smallest surrounding
 5124    /// autoclose region. This uses the ordering of the selections and the autoclose
 5125    /// regions to avoid repeated comparisons.
 5126    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 5127        &'a self,
 5128        selections: impl IntoIterator<Item = Selection<D>>,
 5129        buffer: &'a MultiBufferSnapshot,
 5130    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 5131        let mut i = 0;
 5132        let mut regions = self.autoclose_regions.as_slice();
 5133        selections.into_iter().map(move |selection| {
 5134            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 5135
 5136            let mut enclosing = None;
 5137            while let Some(pair_state) = regions.get(i) {
 5138                if pair_state.range.end.to_offset(buffer) < range.start {
 5139                    regions = &regions[i + 1..];
 5140                    i = 0;
 5141                } else if pair_state.range.start.to_offset(buffer) > range.end {
 5142                    break;
 5143                } else {
 5144                    if pair_state.selection_id == selection.id {
 5145                        enclosing = Some(pair_state);
 5146                    }
 5147                    i += 1;
 5148                }
 5149            }
 5150
 5151            (selection, enclosing)
 5152        })
 5153    }
 5154
 5155    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 5156    fn invalidate_autoclose_regions(
 5157        &mut self,
 5158        mut selections: &[Selection<Anchor>],
 5159        buffer: &MultiBufferSnapshot,
 5160    ) {
 5161        self.autoclose_regions.retain(|state| {
 5162            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 5163                return false;
 5164            }
 5165
 5166            let mut i = 0;
 5167            while let Some(selection) = selections.get(i) {
 5168                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 5169                    selections = &selections[1..];
 5170                    continue;
 5171                }
 5172                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 5173                    break;
 5174                }
 5175                if selection.id == state.selection_id {
 5176                    return true;
 5177                } else {
 5178                    i += 1;
 5179                }
 5180            }
 5181            false
 5182        });
 5183    }
 5184
 5185    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5186        let offset = position.to_offset(buffer);
 5187        let (word_range, kind) =
 5188            buffer.surrounding_word(offset, Some(CharScopeContext::Completion));
 5189        if offset > word_range.start && kind == Some(CharKind::Word) {
 5190            Some(
 5191                buffer
 5192                    .text_for_range(word_range.start..offset)
 5193                    .collect::<String>(),
 5194            )
 5195        } else {
 5196            None
 5197        }
 5198    }
 5199
 5200    pub fn toggle_inline_values(
 5201        &mut self,
 5202        _: &ToggleInlineValues,
 5203        _: &mut Window,
 5204        cx: &mut Context<Self>,
 5205    ) {
 5206        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 5207
 5208        self.refresh_inline_values(cx);
 5209    }
 5210
 5211    pub fn toggle_inlay_hints(
 5212        &mut self,
 5213        _: &ToggleInlayHints,
 5214        _: &mut Window,
 5215        cx: &mut Context<Self>,
 5216    ) {
 5217        self.refresh_inlay_hints(
 5218            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 5219            cx,
 5220        );
 5221    }
 5222
 5223    pub fn inlay_hints_enabled(&self) -> bool {
 5224        self.inlay_hint_cache.enabled
 5225    }
 5226
 5227    pub fn inline_values_enabled(&self) -> bool {
 5228        self.inline_value_cache.enabled
 5229    }
 5230
 5231    #[cfg(any(test, feature = "test-support"))]
 5232    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 5233        self.display_map
 5234            .read(cx)
 5235            .current_inlays()
 5236            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 5237            .cloned()
 5238            .collect()
 5239    }
 5240
 5241    #[cfg(any(test, feature = "test-support"))]
 5242    pub fn all_inlays(&self, cx: &App) -> Vec<Inlay> {
 5243        self.display_map
 5244            .read(cx)
 5245            .current_inlays()
 5246            .cloned()
 5247            .collect()
 5248    }
 5249
 5250    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 5251        if self.semantics_provider.is_none() || !self.mode.is_full() {
 5252            return;
 5253        }
 5254
 5255        let reason_description = reason.description();
 5256        let ignore_debounce = matches!(
 5257            reason,
 5258            InlayHintRefreshReason::SettingsChange(_)
 5259                | InlayHintRefreshReason::Toggle(_)
 5260                | InlayHintRefreshReason::ExcerptsRemoved(_)
 5261                | InlayHintRefreshReason::ModifiersChanged(_)
 5262        );
 5263        let (invalidate_cache, required_languages) = match reason {
 5264            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 5265                match self.inlay_hint_cache.modifiers_override(enabled) {
 5266                    Some(enabled) => {
 5267                        if enabled {
 5268                            (InvalidationStrategy::RefreshRequested, None)
 5269                        } else {
 5270                            self.clear_inlay_hints(cx);
 5271                            return;
 5272                        }
 5273                    }
 5274                    None => return,
 5275                }
 5276            }
 5277            InlayHintRefreshReason::Toggle(enabled) => {
 5278                if self.inlay_hint_cache.toggle(enabled) {
 5279                    if enabled {
 5280                        (InvalidationStrategy::RefreshRequested, None)
 5281                    } else {
 5282                        self.clear_inlay_hints(cx);
 5283                        return;
 5284                    }
 5285                } else {
 5286                    return;
 5287                }
 5288            }
 5289            InlayHintRefreshReason::SettingsChange(new_settings) => {
 5290                match self.inlay_hint_cache.update_settings(
 5291                    &self.buffer,
 5292                    new_settings,
 5293                    self.visible_inlay_hints(cx).cloned().collect::<Vec<_>>(),
 5294                    cx,
 5295                ) {
 5296                    ControlFlow::Break(Some(InlaySplice {
 5297                        to_remove,
 5298                        to_insert,
 5299                    })) => {
 5300                        self.splice_inlays(&to_remove, to_insert, cx);
 5301                        return;
 5302                    }
 5303                    ControlFlow::Break(None) => return,
 5304                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 5305                }
 5306            }
 5307            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 5308                if let Some(InlaySplice {
 5309                    to_remove,
 5310                    to_insert,
 5311                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 5312                {
 5313                    self.splice_inlays(&to_remove, to_insert, cx);
 5314                }
 5315                self.display_map.update(cx, |display_map, cx| {
 5316                    display_map.remove_inlays_for_excerpts(&excerpts_removed, cx)
 5317                });
 5318                return;
 5319            }
 5320            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 5321            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 5322                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 5323            }
 5324            InlayHintRefreshReason::RefreshRequested => {
 5325                (InvalidationStrategy::RefreshRequested, None)
 5326            }
 5327        };
 5328
 5329        let mut visible_excerpts = self.visible_excerpts(required_languages.as_ref(), cx);
 5330        visible_excerpts.retain(|_, (buffer, _, _)| {
 5331            self.registered_buffers
 5332                .contains_key(&buffer.read(cx).remote_id())
 5333        });
 5334
 5335        if let Some(InlaySplice {
 5336            to_remove,
 5337            to_insert,
 5338        }) = self.inlay_hint_cache.spawn_hint_refresh(
 5339            reason_description,
 5340            visible_excerpts,
 5341            invalidate_cache,
 5342            ignore_debounce,
 5343            cx,
 5344        ) {
 5345            self.splice_inlays(&to_remove, to_insert, cx);
 5346        }
 5347    }
 5348
 5349    pub fn clear_inlay_hints(&self, cx: &mut Context<Editor>) {
 5350        self.splice_inlays(
 5351            &self
 5352                .visible_inlay_hints(cx)
 5353                .map(|inlay| inlay.id)
 5354                .collect::<Vec<_>>(),
 5355            Vec::new(),
 5356            cx,
 5357        );
 5358    }
 5359
 5360    fn visible_inlay_hints<'a>(
 5361        &'a self,
 5362        cx: &'a Context<Editor>,
 5363    ) -> impl Iterator<Item = &'a Inlay> {
 5364        self.display_map
 5365            .read(cx)
 5366            .current_inlays()
 5367            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 5368    }
 5369
 5370    pub fn visible_excerpts(
 5371        &self,
 5372        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 5373        cx: &mut Context<Editor>,
 5374    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5375        let Some(project) = self.project() else {
 5376            return HashMap::default();
 5377        };
 5378        let project = project.read(cx);
 5379        let multi_buffer = self.buffer().read(cx);
 5380        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5381        let multi_buffer_visible_start = self
 5382            .scroll_manager
 5383            .anchor()
 5384            .anchor
 5385            .to_point(&multi_buffer_snapshot);
 5386        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5387            multi_buffer_visible_start
 5388                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5389            Bias::Left,
 5390        );
 5391        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 5392        multi_buffer_snapshot
 5393            .range_to_buffer_ranges(multi_buffer_visible_range)
 5394            .into_iter()
 5395            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5396            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5397                let buffer_file = project::File::from_dyn(buffer.file())?;
 5398                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5399                let worktree_entry = buffer_worktree
 5400                    .read(cx)
 5401                    .entry_for_id(buffer_file.project_entry_id()?)?;
 5402                if worktree_entry.is_ignored {
 5403                    return None;
 5404                }
 5405
 5406                let language = buffer.language()?;
 5407                if let Some(restrict_to_languages) = restrict_to_languages
 5408                    && !restrict_to_languages.contains(language)
 5409                {
 5410                    return None;
 5411                }
 5412                Some((
 5413                    excerpt_id,
 5414                    (
 5415                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5416                        buffer.version().clone(),
 5417                        excerpt_visible_range,
 5418                    ),
 5419                ))
 5420            })
 5421            .collect()
 5422    }
 5423
 5424    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5425        TextLayoutDetails {
 5426            text_system: window.text_system().clone(),
 5427            editor_style: self.style.clone().unwrap(),
 5428            rem_size: window.rem_size(),
 5429            scroll_anchor: self.scroll_manager.anchor(),
 5430            visible_rows: self.visible_line_count(),
 5431            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5432        }
 5433    }
 5434
 5435    pub fn splice_inlays(
 5436        &self,
 5437        to_remove: &[InlayId],
 5438        to_insert: Vec<Inlay>,
 5439        cx: &mut Context<Self>,
 5440    ) {
 5441        self.display_map.update(cx, |display_map, cx| {
 5442            display_map.splice_inlays(to_remove, to_insert, cx)
 5443        });
 5444        cx.notify();
 5445    }
 5446
 5447    fn trigger_on_type_formatting(
 5448        &self,
 5449        input: String,
 5450        window: &mut Window,
 5451        cx: &mut Context<Self>,
 5452    ) -> Option<Task<Result<()>>> {
 5453        if input.len() != 1 {
 5454            return None;
 5455        }
 5456
 5457        let project = self.project()?;
 5458        let position = self.selections.newest_anchor().head();
 5459        let (buffer, buffer_position) = self
 5460            .buffer
 5461            .read(cx)
 5462            .text_anchor_for_position(position, cx)?;
 5463
 5464        let settings = language_settings::language_settings(
 5465            buffer
 5466                .read(cx)
 5467                .language_at(buffer_position)
 5468                .map(|l| l.name()),
 5469            buffer.read(cx).file(),
 5470            cx,
 5471        );
 5472        if !settings.use_on_type_format {
 5473            return None;
 5474        }
 5475
 5476        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5477        // hence we do LSP request & edit on host side only — add formats to host's history.
 5478        let push_to_lsp_host_history = true;
 5479        // If this is not the host, append its history with new edits.
 5480        let push_to_client_history = project.read(cx).is_via_collab();
 5481
 5482        let on_type_formatting = project.update(cx, |project, cx| {
 5483            project.on_type_format(
 5484                buffer.clone(),
 5485                buffer_position,
 5486                input,
 5487                push_to_lsp_host_history,
 5488                cx,
 5489            )
 5490        });
 5491        Some(cx.spawn_in(window, async move |editor, cx| {
 5492            if let Some(transaction) = on_type_formatting.await? {
 5493                if push_to_client_history {
 5494                    buffer
 5495                        .update(cx, |buffer, _| {
 5496                            buffer.push_transaction(transaction, Instant::now());
 5497                            buffer.finalize_last_transaction();
 5498                        })
 5499                        .ok();
 5500                }
 5501                editor.update(cx, |editor, cx| {
 5502                    editor.refresh_document_highlights(cx);
 5503                })?;
 5504            }
 5505            Ok(())
 5506        }))
 5507    }
 5508
 5509    pub fn show_word_completions(
 5510        &mut self,
 5511        _: &ShowWordCompletions,
 5512        window: &mut Window,
 5513        cx: &mut Context<Self>,
 5514    ) {
 5515        self.open_or_update_completions_menu(
 5516            Some(CompletionsMenuSource::Words {
 5517                ignore_threshold: true,
 5518            }),
 5519            None,
 5520            window,
 5521            cx,
 5522        );
 5523    }
 5524
 5525    pub fn show_completions(
 5526        &mut self,
 5527        options: &ShowCompletions,
 5528        window: &mut Window,
 5529        cx: &mut Context<Self>,
 5530    ) {
 5531        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5532    }
 5533
 5534    fn open_or_update_completions_menu(
 5535        &mut self,
 5536        requested_source: Option<CompletionsMenuSource>,
 5537        trigger: Option<&str>,
 5538        window: &mut Window,
 5539        cx: &mut Context<Self>,
 5540    ) {
 5541        if self.pending_rename.is_some() {
 5542            return;
 5543        }
 5544
 5545        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5546
 5547        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5548        // inserted and selected. To handle that case, the start of the selection is used so that
 5549        // the menu starts with all choices.
 5550        let position = self
 5551            .selections
 5552            .newest_anchor()
 5553            .start
 5554            .bias_right(&multibuffer_snapshot);
 5555        if position.diff_base_anchor.is_some() {
 5556            return;
 5557        }
 5558        let buffer_position = multibuffer_snapshot.anchor_before(position);
 5559        let Some(buffer) = buffer_position
 5560            .buffer_id
 5561            .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
 5562        else {
 5563            return;
 5564        };
 5565        let buffer_snapshot = buffer.read(cx).snapshot();
 5566
 5567        let query: Option<Arc<String>> =
 5568            Self::completion_query(&multibuffer_snapshot, buffer_position)
 5569                .map(|query| query.into());
 5570
 5571        drop(multibuffer_snapshot);
 5572
 5573        // Hide the current completions menu when query is empty. Without this, cached
 5574        // completions from before the trigger char may be reused (#32774).
 5575        if query.is_none() {
 5576            let menu_is_open = matches!(
 5577                self.context_menu.borrow().as_ref(),
 5578                Some(CodeContextMenu::Completions(_))
 5579            );
 5580            if menu_is_open {
 5581                self.hide_context_menu(window, cx);
 5582            }
 5583        }
 5584
 5585        let mut ignore_word_threshold = false;
 5586        let provider = match requested_source {
 5587            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5588            Some(CompletionsMenuSource::Words { ignore_threshold }) => {
 5589                ignore_word_threshold = ignore_threshold;
 5590                None
 5591            }
 5592            Some(CompletionsMenuSource::SnippetChoices) => {
 5593                log::error!("bug: SnippetChoices requested_source is not handled");
 5594                None
 5595            }
 5596        };
 5597
 5598        let sort_completions = provider
 5599            .as_ref()
 5600            .is_some_and(|provider| provider.sort_completions());
 5601
 5602        let filter_completions = provider
 5603            .as_ref()
 5604            .is_none_or(|provider| provider.filter_completions());
 5605
 5606        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5607            if filter_completions {
 5608                menu.filter(query.clone(), provider.clone(), window, cx);
 5609            }
 5610            // When `is_incomplete` is false, no need to re-query completions when the current query
 5611            // is a suffix of the initial query.
 5612            if !menu.is_incomplete {
 5613                // If the new query is a suffix of the old query (typing more characters) and
 5614                // the previous result was complete, the existing completions can be filtered.
 5615                //
 5616                // Note that this is always true for snippet completions.
 5617                let query_matches = match (&menu.initial_query, &query) {
 5618                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5619                    (None, _) => true,
 5620                    _ => false,
 5621                };
 5622                if query_matches {
 5623                    let position_matches = if menu.initial_position == position {
 5624                        true
 5625                    } else {
 5626                        let snapshot = self.buffer.read(cx).read(cx);
 5627                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5628                    };
 5629                    if position_matches {
 5630                        return;
 5631                    }
 5632                }
 5633            }
 5634        };
 5635
 5636        let trigger_kind = match trigger {
 5637            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5638                CompletionTriggerKind::TRIGGER_CHARACTER
 5639            }
 5640            _ => CompletionTriggerKind::INVOKED,
 5641        };
 5642        let completion_context = CompletionContext {
 5643            trigger_character: trigger.and_then(|trigger| {
 5644                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5645                    Some(String::from(trigger))
 5646                } else {
 5647                    None
 5648                }
 5649            }),
 5650            trigger_kind,
 5651        };
 5652
 5653        let Anchor {
 5654            excerpt_id: buffer_excerpt_id,
 5655            text_anchor: buffer_position,
 5656            ..
 5657        } = buffer_position;
 5658
 5659        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5660            buffer_snapshot.surrounding_word(buffer_position, None)
 5661        {
 5662            let word_to_exclude = buffer_snapshot
 5663                .text_for_range(word_range.clone())
 5664                .collect::<String>();
 5665            (
 5666                buffer_snapshot.anchor_before(word_range.start)
 5667                    ..buffer_snapshot.anchor_after(buffer_position),
 5668                Some(word_to_exclude),
 5669            )
 5670        } else {
 5671            (buffer_position..buffer_position, None)
 5672        };
 5673
 5674        let language = buffer_snapshot
 5675            .language_at(buffer_position)
 5676            .map(|language| language.name());
 5677
 5678        let completion_settings = language_settings(language.clone(), buffer_snapshot.file(), cx)
 5679            .completions
 5680            .clone();
 5681
 5682        let show_completion_documentation = buffer_snapshot
 5683            .settings_at(buffer_position, cx)
 5684            .show_completion_documentation;
 5685
 5686        // The document can be large, so stay in reasonable bounds when searching for words,
 5687        // otherwise completion pop-up might be slow to appear.
 5688        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5689        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5690        let min_word_search = buffer_snapshot.clip_point(
 5691            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5692            Bias::Left,
 5693        );
 5694        let max_word_search = buffer_snapshot.clip_point(
 5695            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5696            Bias::Right,
 5697        );
 5698        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5699            ..buffer_snapshot.point_to_offset(max_word_search);
 5700
 5701        let skip_digits = query
 5702            .as_ref()
 5703            .is_none_or(|query| !query.chars().any(|c| c.is_digit(10)));
 5704
 5705        let omit_word_completions = !self.word_completions_enabled
 5706            || (!ignore_word_threshold
 5707                && match &query {
 5708                    Some(query) => query.chars().count() < completion_settings.words_min_length,
 5709                    None => completion_settings.words_min_length != 0,
 5710                });
 5711
 5712        let (mut words, provider_responses) = match &provider {
 5713            Some(provider) => {
 5714                let provider_responses = provider.completions(
 5715                    buffer_excerpt_id,
 5716                    &buffer,
 5717                    buffer_position,
 5718                    completion_context,
 5719                    window,
 5720                    cx,
 5721                );
 5722
 5723                let words = match (omit_word_completions, completion_settings.words) {
 5724                    (true, _) | (_, WordsCompletionMode::Disabled) => {
 5725                        Task::ready(BTreeMap::default())
 5726                    }
 5727                    (false, WordsCompletionMode::Enabled | WordsCompletionMode::Fallback) => cx
 5728                        .background_spawn(async move {
 5729                            buffer_snapshot.words_in_range(WordsQuery {
 5730                                fuzzy_contents: None,
 5731                                range: word_search_range,
 5732                                skip_digits,
 5733                            })
 5734                        }),
 5735                };
 5736
 5737                (words, provider_responses)
 5738            }
 5739            None => {
 5740                let words = if omit_word_completions {
 5741                    Task::ready(BTreeMap::default())
 5742                } else {
 5743                    cx.background_spawn(async move {
 5744                        buffer_snapshot.words_in_range(WordsQuery {
 5745                            fuzzy_contents: None,
 5746                            range: word_search_range,
 5747                            skip_digits,
 5748                        })
 5749                    })
 5750                };
 5751                (words, Task::ready(Ok(Vec::new())))
 5752            }
 5753        };
 5754
 5755        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5756
 5757        let id = post_inc(&mut self.next_completion_id);
 5758        let task = cx.spawn_in(window, async move |editor, cx| {
 5759            let Ok(()) = editor.update(cx, |this, _| {
 5760                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5761            }) else {
 5762                return;
 5763            };
 5764
 5765            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5766            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5767            let mut completions = Vec::new();
 5768            let mut is_incomplete = false;
 5769            let mut display_options: Option<CompletionDisplayOptions> = None;
 5770            if let Some(provider_responses) = provider_responses.await.log_err()
 5771                && !provider_responses.is_empty()
 5772            {
 5773                for response in provider_responses {
 5774                    completions.extend(response.completions);
 5775                    is_incomplete = is_incomplete || response.is_incomplete;
 5776                    match display_options.as_mut() {
 5777                        None => {
 5778                            display_options = Some(response.display_options);
 5779                        }
 5780                        Some(options) => options.merge(&response.display_options),
 5781                    }
 5782                }
 5783                if completion_settings.words == WordsCompletionMode::Fallback {
 5784                    words = Task::ready(BTreeMap::default());
 5785                }
 5786            }
 5787            let display_options = display_options.unwrap_or_default();
 5788
 5789            let mut words = words.await;
 5790            if let Some(word_to_exclude) = &word_to_exclude {
 5791                words.remove(word_to_exclude);
 5792            }
 5793            for lsp_completion in &completions {
 5794                words.remove(&lsp_completion.new_text);
 5795            }
 5796            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5797                replace_range: word_replace_range.clone(),
 5798                new_text: word.clone(),
 5799                label: CodeLabel::plain(word, None),
 5800                icon_path: None,
 5801                documentation: None,
 5802                source: CompletionSource::BufferWord {
 5803                    word_range,
 5804                    resolved: false,
 5805                },
 5806                insert_text_mode: Some(InsertTextMode::AS_IS),
 5807                confirm: None,
 5808            }));
 5809
 5810            let menu = if completions.is_empty() {
 5811                None
 5812            } else {
 5813                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5814                    let languages = editor
 5815                        .workspace
 5816                        .as_ref()
 5817                        .and_then(|(workspace, _)| workspace.upgrade())
 5818                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5819                    let menu = CompletionsMenu::new(
 5820                        id,
 5821                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5822                        sort_completions,
 5823                        show_completion_documentation,
 5824                        position,
 5825                        query.clone(),
 5826                        is_incomplete,
 5827                        buffer.clone(),
 5828                        completions.into(),
 5829                        display_options,
 5830                        snippet_sort_order,
 5831                        languages,
 5832                        language,
 5833                        cx,
 5834                    );
 5835
 5836                    let query = if filter_completions { query } else { None };
 5837                    let matches_task = if let Some(query) = query {
 5838                        menu.do_async_filtering(query, cx)
 5839                    } else {
 5840                        Task::ready(menu.unfiltered_matches())
 5841                    };
 5842                    (menu, matches_task)
 5843                }) else {
 5844                    return;
 5845                };
 5846
 5847                let matches = matches_task.await;
 5848
 5849                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5850                    // Newer menu already set, so exit.
 5851                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5852                        editor.context_menu.borrow().as_ref()
 5853                        && prev_menu.id > id
 5854                    {
 5855                        return;
 5856                    };
 5857
 5858                    // Only valid to take prev_menu because it the new menu is immediately set
 5859                    // below, or the menu is hidden.
 5860                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5861                        editor.context_menu.borrow_mut().take()
 5862                    {
 5863                        let position_matches =
 5864                            if prev_menu.initial_position == menu.initial_position {
 5865                                true
 5866                            } else {
 5867                                let snapshot = editor.buffer.read(cx).read(cx);
 5868                                prev_menu.initial_position.to_offset(&snapshot)
 5869                                    == menu.initial_position.to_offset(&snapshot)
 5870                            };
 5871                        if position_matches {
 5872                            // Preserve markdown cache before `set_filter_results` because it will
 5873                            // try to populate the documentation cache.
 5874                            menu.preserve_markdown_cache(prev_menu);
 5875                        }
 5876                    };
 5877
 5878                    menu.set_filter_results(matches, provider, window, cx);
 5879                }) else {
 5880                    return;
 5881                };
 5882
 5883                menu.visible().then_some(menu)
 5884            };
 5885
 5886            editor
 5887                .update_in(cx, |editor, window, cx| {
 5888                    if editor.focus_handle.is_focused(window)
 5889                        && let Some(menu) = menu
 5890                    {
 5891                        *editor.context_menu.borrow_mut() =
 5892                            Some(CodeContextMenu::Completions(menu));
 5893
 5894                        crate::hover_popover::hide_hover(editor, cx);
 5895                        if editor.show_edit_predictions_in_menu() {
 5896                            editor.update_visible_edit_prediction(window, cx);
 5897                        } else {
 5898                            editor.discard_edit_prediction(false, cx);
 5899                        }
 5900
 5901                        cx.notify();
 5902                        return;
 5903                    }
 5904
 5905                    if editor.completion_tasks.len() <= 1 {
 5906                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5907                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5908                        // If it was already hidden and we don't show edit predictions in the menu,
 5909                        // we should also show the edit prediction when available.
 5910                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5911                            editor.update_visible_edit_prediction(window, cx);
 5912                        }
 5913                    }
 5914                })
 5915                .ok();
 5916        });
 5917
 5918        self.completion_tasks.push((id, task));
 5919    }
 5920
 5921    #[cfg(feature = "test-support")]
 5922    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5923        let menu = self.context_menu.borrow();
 5924        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5925            let completions = menu.completions.borrow();
 5926            Some(completions.to_vec())
 5927        } else {
 5928            None
 5929        }
 5930    }
 5931
 5932    pub fn with_completions_menu_matching_id<R>(
 5933        &self,
 5934        id: CompletionId,
 5935        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5936    ) -> R {
 5937        let mut context_menu = self.context_menu.borrow_mut();
 5938        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5939            return f(None);
 5940        };
 5941        if completions_menu.id != id {
 5942            return f(None);
 5943        }
 5944        f(Some(completions_menu))
 5945    }
 5946
 5947    pub fn confirm_completion(
 5948        &mut self,
 5949        action: &ConfirmCompletion,
 5950        window: &mut Window,
 5951        cx: &mut Context<Self>,
 5952    ) -> Option<Task<Result<()>>> {
 5953        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5954        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5955    }
 5956
 5957    pub fn confirm_completion_insert(
 5958        &mut self,
 5959        _: &ConfirmCompletionInsert,
 5960        window: &mut Window,
 5961        cx: &mut Context<Self>,
 5962    ) -> Option<Task<Result<()>>> {
 5963        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5964        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5965    }
 5966
 5967    pub fn confirm_completion_replace(
 5968        &mut self,
 5969        _: &ConfirmCompletionReplace,
 5970        window: &mut Window,
 5971        cx: &mut Context<Self>,
 5972    ) -> Option<Task<Result<()>>> {
 5973        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5974        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5975    }
 5976
 5977    pub fn compose_completion(
 5978        &mut self,
 5979        action: &ComposeCompletion,
 5980        window: &mut Window,
 5981        cx: &mut Context<Self>,
 5982    ) -> Option<Task<Result<()>>> {
 5983        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5984        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5985    }
 5986
 5987    fn do_completion(
 5988        &mut self,
 5989        item_ix: Option<usize>,
 5990        intent: CompletionIntent,
 5991        window: &mut Window,
 5992        cx: &mut Context<Editor>,
 5993    ) -> Option<Task<Result<()>>> {
 5994        use language::ToOffset as _;
 5995
 5996        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5997        else {
 5998            return None;
 5999        };
 6000
 6001        let candidate_id = {
 6002            let entries = completions_menu.entries.borrow();
 6003            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 6004            if self.show_edit_predictions_in_menu() {
 6005                self.discard_edit_prediction(true, cx);
 6006            }
 6007            mat.candidate_id
 6008        };
 6009
 6010        let completion = completions_menu
 6011            .completions
 6012            .borrow()
 6013            .get(candidate_id)?
 6014            .clone();
 6015        cx.stop_propagation();
 6016
 6017        let buffer_handle = completions_menu.buffer.clone();
 6018
 6019        let CompletionEdit {
 6020            new_text,
 6021            snippet,
 6022            replace_range,
 6023        } = process_completion_for_edit(
 6024            &completion,
 6025            intent,
 6026            &buffer_handle,
 6027            &completions_menu.initial_position.text_anchor,
 6028            cx,
 6029        );
 6030
 6031        let buffer = buffer_handle.read(cx);
 6032        let snapshot = self.buffer.read(cx).snapshot(cx);
 6033        let newest_anchor = self.selections.newest_anchor();
 6034        let replace_range_multibuffer = {
 6035            let mut excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 6036            excerpt.map_range_from_buffer(replace_range.clone())
 6037        };
 6038        if snapshot.buffer_id_for_anchor(newest_anchor.head()) != Some(buffer.remote_id()) {
 6039            return None;
 6040        }
 6041
 6042        let old_text = buffer
 6043            .text_for_range(replace_range.clone())
 6044            .collect::<String>();
 6045        let lookbehind = newest_anchor
 6046            .start
 6047            .text_anchor
 6048            .to_offset(buffer)
 6049            .saturating_sub(replace_range.start);
 6050        let lookahead = replace_range
 6051            .end
 6052            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 6053        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 6054        let suffix = &old_text[lookbehind.min(old_text.len())..];
 6055
 6056        let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 6057        let mut ranges = Vec::new();
 6058        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 6059
 6060        for selection in &selections {
 6061            let range = if selection.id == newest_anchor.id {
 6062                replace_range_multibuffer.clone()
 6063            } else {
 6064                let mut range = selection.range();
 6065
 6066                // if prefix is present, don't duplicate it
 6067                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 6068                    range.start = range.start.saturating_sub(lookbehind);
 6069
 6070                    // if suffix is also present, mimic the newest cursor and replace it
 6071                    if selection.id != newest_anchor.id
 6072                        && snapshot.contains_str_at(range.end, suffix)
 6073                    {
 6074                        range.end += lookahead;
 6075                    }
 6076                }
 6077                range
 6078            };
 6079
 6080            ranges.push(range.clone());
 6081
 6082            if !self.linked_edit_ranges.is_empty() {
 6083                let start_anchor = snapshot.anchor_before(range.start);
 6084                let end_anchor = snapshot.anchor_after(range.end);
 6085                if let Some(ranges) = self
 6086                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 6087                {
 6088                    for (buffer, edits) in ranges {
 6089                        linked_edits
 6090                            .entry(buffer.clone())
 6091                            .or_default()
 6092                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 6093                    }
 6094                }
 6095            }
 6096        }
 6097
 6098        let common_prefix_len = old_text
 6099            .chars()
 6100            .zip(new_text.chars())
 6101            .take_while(|(a, b)| a == b)
 6102            .map(|(a, _)| a.len_utf8())
 6103            .sum::<usize>();
 6104
 6105        cx.emit(EditorEvent::InputHandled {
 6106            utf16_range_to_replace: None,
 6107            text: new_text[common_prefix_len..].into(),
 6108        });
 6109
 6110        self.transact(window, cx, |editor, window, cx| {
 6111            if let Some(mut snippet) = snippet {
 6112                snippet.text = new_text.to_string();
 6113                editor
 6114                    .insert_snippet(&ranges, snippet, window, cx)
 6115                    .log_err();
 6116            } else {
 6117                editor.buffer.update(cx, |multi_buffer, cx| {
 6118                    let auto_indent = match completion.insert_text_mode {
 6119                        Some(InsertTextMode::AS_IS) => None,
 6120                        _ => editor.autoindent_mode.clone(),
 6121                    };
 6122                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 6123                    multi_buffer.edit(edits, auto_indent, cx);
 6124                });
 6125            }
 6126            for (buffer, edits) in linked_edits {
 6127                buffer.update(cx, |buffer, cx| {
 6128                    let snapshot = buffer.snapshot();
 6129                    let edits = edits
 6130                        .into_iter()
 6131                        .map(|(range, text)| {
 6132                            use text::ToPoint as TP;
 6133                            let end_point = TP::to_point(&range.end, &snapshot);
 6134                            let start_point = TP::to_point(&range.start, &snapshot);
 6135                            (start_point..end_point, text)
 6136                        })
 6137                        .sorted_by_key(|(range, _)| range.start);
 6138                    buffer.edit(edits, None, cx);
 6139                })
 6140            }
 6141
 6142            editor.refresh_edit_prediction(true, false, window, cx);
 6143        });
 6144        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors_arc(), &snapshot);
 6145
 6146        let show_new_completions_on_confirm = completion
 6147            .confirm
 6148            .as_ref()
 6149            .is_some_and(|confirm| confirm(intent, window, cx));
 6150        if show_new_completions_on_confirm {
 6151            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 6152        }
 6153
 6154        let provider = self.completion_provider.as_ref()?;
 6155        drop(completion);
 6156        let apply_edits = provider.apply_additional_edits_for_completion(
 6157            buffer_handle,
 6158            completions_menu.completions.clone(),
 6159            candidate_id,
 6160            true,
 6161            cx,
 6162        );
 6163
 6164        let editor_settings = EditorSettings::get_global(cx);
 6165        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 6166            // After the code completion is finished, users often want to know what signatures are needed.
 6167            // so we should automatically call signature_help
 6168            self.show_signature_help(&ShowSignatureHelp, window, cx);
 6169        }
 6170
 6171        Some(cx.foreground_executor().spawn(async move {
 6172            apply_edits.await?;
 6173            Ok(())
 6174        }))
 6175    }
 6176
 6177    pub fn toggle_code_actions(
 6178        &mut self,
 6179        action: &ToggleCodeActions,
 6180        window: &mut Window,
 6181        cx: &mut Context<Self>,
 6182    ) {
 6183        let quick_launch = action.quick_launch;
 6184        let mut context_menu = self.context_menu.borrow_mut();
 6185        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 6186            if code_actions.deployed_from == action.deployed_from {
 6187                // Toggle if we're selecting the same one
 6188                *context_menu = None;
 6189                cx.notify();
 6190                return;
 6191            } else {
 6192                // Otherwise, clear it and start a new one
 6193                *context_menu = None;
 6194                cx.notify();
 6195            }
 6196        }
 6197        drop(context_menu);
 6198        let snapshot = self.snapshot(window, cx);
 6199        let deployed_from = action.deployed_from.clone();
 6200        let action = action.clone();
 6201        self.completion_tasks.clear();
 6202        self.discard_edit_prediction(false, cx);
 6203
 6204        let multibuffer_point = match &action.deployed_from {
 6205            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 6206                DisplayPoint::new(*row, 0).to_point(&snapshot)
 6207            }
 6208            _ => self
 6209                .selections
 6210                .newest::<Point>(&snapshot.display_snapshot)
 6211                .head(),
 6212        };
 6213        let Some((buffer, buffer_row)) = snapshot
 6214            .buffer_snapshot()
 6215            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6216            .and_then(|(buffer_snapshot, range)| {
 6217                self.buffer()
 6218                    .read(cx)
 6219                    .buffer(buffer_snapshot.remote_id())
 6220                    .map(|buffer| (buffer, range.start.row))
 6221            })
 6222        else {
 6223            return;
 6224        };
 6225        let buffer_id = buffer.read(cx).remote_id();
 6226        let tasks = self
 6227            .tasks
 6228            .get(&(buffer_id, buffer_row))
 6229            .map(|t| Arc::new(t.to_owned()));
 6230
 6231        if !self.focus_handle.is_focused(window) {
 6232            return;
 6233        }
 6234        let project = self.project.clone();
 6235
 6236        let code_actions_task = match deployed_from {
 6237            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6238            _ => self.code_actions(buffer_row, window, cx),
 6239        };
 6240
 6241        let runnable_task = match deployed_from {
 6242            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6243            _ => {
 6244                let mut task_context_task = Task::ready(None);
 6245                if let Some(tasks) = &tasks
 6246                    && let Some(project) = project
 6247                {
 6248                    task_context_task =
 6249                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6250                }
 6251
 6252                cx.spawn_in(window, {
 6253                    let buffer = buffer.clone();
 6254                    async move |editor, cx| {
 6255                        let task_context = task_context_task.await;
 6256
 6257                        let resolved_tasks =
 6258                            tasks
 6259                                .zip(task_context.clone())
 6260                                .map(|(tasks, task_context)| ResolvedTasks {
 6261                                    templates: tasks.resolve(&task_context).collect(),
 6262                                    position: snapshot.buffer_snapshot().anchor_before(Point::new(
 6263                                        multibuffer_point.row,
 6264                                        tasks.column,
 6265                                    )),
 6266                                });
 6267                        let debug_scenarios = editor
 6268                            .update(cx, |editor, cx| {
 6269                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6270                            })?
 6271                            .await;
 6272                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6273                    }
 6274                })
 6275            }
 6276        };
 6277
 6278        cx.spawn_in(window, async move |editor, cx| {
 6279            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6280            let code_actions = code_actions_task.await;
 6281            let spawn_straight_away = quick_launch
 6282                && resolved_tasks
 6283                    .as_ref()
 6284                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6285                && code_actions
 6286                    .as_ref()
 6287                    .is_none_or(|actions| actions.is_empty())
 6288                && debug_scenarios.is_empty();
 6289
 6290            editor.update_in(cx, |editor, window, cx| {
 6291                crate::hover_popover::hide_hover(editor, cx);
 6292                let actions = CodeActionContents::new(
 6293                    resolved_tasks,
 6294                    code_actions,
 6295                    debug_scenarios,
 6296                    task_context.unwrap_or_default(),
 6297                );
 6298
 6299                // Don't show the menu if there are no actions available
 6300                if actions.is_empty() {
 6301                    cx.notify();
 6302                    return Task::ready(Ok(()));
 6303                }
 6304
 6305                *editor.context_menu.borrow_mut() =
 6306                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6307                        buffer,
 6308                        actions,
 6309                        selected_item: Default::default(),
 6310                        scroll_handle: UniformListScrollHandle::default(),
 6311                        deployed_from,
 6312                    }));
 6313                cx.notify();
 6314                if spawn_straight_away
 6315                    && let Some(task) = editor.confirm_code_action(
 6316                        &ConfirmCodeAction { item_ix: Some(0) },
 6317                        window,
 6318                        cx,
 6319                    )
 6320                {
 6321                    return task;
 6322                }
 6323
 6324                Task::ready(Ok(()))
 6325            })
 6326        })
 6327        .detach_and_log_err(cx);
 6328    }
 6329
 6330    fn debug_scenarios(
 6331        &mut self,
 6332        resolved_tasks: &Option<ResolvedTasks>,
 6333        buffer: &Entity<Buffer>,
 6334        cx: &mut App,
 6335    ) -> Task<Vec<task::DebugScenario>> {
 6336        maybe!({
 6337            let project = self.project()?;
 6338            let dap_store = project.read(cx).dap_store();
 6339            let mut scenarios = vec![];
 6340            let resolved_tasks = resolved_tasks.as_ref()?;
 6341            let buffer = buffer.read(cx);
 6342            let language = buffer.language()?;
 6343            let file = buffer.file();
 6344            let debug_adapter = language_settings(language.name().into(), file, cx)
 6345                .debuggers
 6346                .first()
 6347                .map(SharedString::from)
 6348                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6349
 6350            dap_store.update(cx, |dap_store, cx| {
 6351                for (_, task) in &resolved_tasks.templates {
 6352                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6353                        task.original_task().clone(),
 6354                        debug_adapter.clone().into(),
 6355                        task.display_label().to_owned().into(),
 6356                        cx,
 6357                    );
 6358                    scenarios.push(maybe_scenario);
 6359                }
 6360            });
 6361            Some(cx.background_spawn(async move {
 6362                futures::future::join_all(scenarios)
 6363                    .await
 6364                    .into_iter()
 6365                    .flatten()
 6366                    .collect::<Vec<_>>()
 6367            }))
 6368        })
 6369        .unwrap_or_else(|| Task::ready(vec![]))
 6370    }
 6371
 6372    fn code_actions(
 6373        &mut self,
 6374        buffer_row: u32,
 6375        window: &mut Window,
 6376        cx: &mut Context<Self>,
 6377    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6378        let mut task = self.code_actions_task.take();
 6379        cx.spawn_in(window, async move |editor, cx| {
 6380            while let Some(prev_task) = task {
 6381                prev_task.await.log_err();
 6382                task = editor
 6383                    .update(cx, |this, _| this.code_actions_task.take())
 6384                    .ok()?;
 6385            }
 6386
 6387            editor
 6388                .update(cx, |editor, cx| {
 6389                    editor
 6390                        .available_code_actions
 6391                        .clone()
 6392                        .and_then(|(location, code_actions)| {
 6393                            let snapshot = location.buffer.read(cx).snapshot();
 6394                            let point_range = location.range.to_point(&snapshot);
 6395                            let point_range = point_range.start.row..=point_range.end.row;
 6396                            if point_range.contains(&buffer_row) {
 6397                                Some(code_actions)
 6398                            } else {
 6399                                None
 6400                            }
 6401                        })
 6402                })
 6403                .ok()
 6404                .flatten()
 6405        })
 6406    }
 6407
 6408    pub fn confirm_code_action(
 6409        &mut self,
 6410        action: &ConfirmCodeAction,
 6411        window: &mut Window,
 6412        cx: &mut Context<Self>,
 6413    ) -> Option<Task<Result<()>>> {
 6414        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6415
 6416        let actions_menu =
 6417            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6418                menu
 6419            } else {
 6420                return None;
 6421            };
 6422
 6423        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6424        let action = actions_menu.actions.get(action_ix)?;
 6425        let title = action.label();
 6426        let buffer = actions_menu.buffer;
 6427        let workspace = self.workspace()?;
 6428
 6429        match action {
 6430            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6431                workspace.update(cx, |workspace, cx| {
 6432                    workspace.schedule_resolved_task(
 6433                        task_source_kind,
 6434                        resolved_task,
 6435                        false,
 6436                        window,
 6437                        cx,
 6438                    );
 6439
 6440                    Some(Task::ready(Ok(())))
 6441                })
 6442            }
 6443            CodeActionsItem::CodeAction {
 6444                excerpt_id,
 6445                action,
 6446                provider,
 6447            } => {
 6448                let apply_code_action =
 6449                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6450                let workspace = workspace.downgrade();
 6451                Some(cx.spawn_in(window, async move |editor, cx| {
 6452                    let project_transaction = apply_code_action.await?;
 6453                    Self::open_project_transaction(
 6454                        &editor,
 6455                        workspace,
 6456                        project_transaction,
 6457                        title,
 6458                        cx,
 6459                    )
 6460                    .await
 6461                }))
 6462            }
 6463            CodeActionsItem::DebugScenario(scenario) => {
 6464                let context = actions_menu.actions.context;
 6465
 6466                workspace.update(cx, |workspace, cx| {
 6467                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6468                    workspace.start_debug_session(
 6469                        scenario,
 6470                        context,
 6471                        Some(buffer),
 6472                        None,
 6473                        window,
 6474                        cx,
 6475                    );
 6476                });
 6477                Some(Task::ready(Ok(())))
 6478            }
 6479        }
 6480    }
 6481
 6482    pub async fn open_project_transaction(
 6483        editor: &WeakEntity<Editor>,
 6484        workspace: WeakEntity<Workspace>,
 6485        transaction: ProjectTransaction,
 6486        title: String,
 6487        cx: &mut AsyncWindowContext,
 6488    ) -> Result<()> {
 6489        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6490        cx.update(|_, cx| {
 6491            entries.sort_unstable_by_key(|(buffer, _)| {
 6492                buffer.read(cx).file().map(|f| f.path().clone())
 6493            });
 6494        })?;
 6495        if entries.is_empty() {
 6496            return Ok(());
 6497        }
 6498
 6499        // If the project transaction's edits are all contained within this editor, then
 6500        // avoid opening a new editor to display them.
 6501
 6502        if let [(buffer, transaction)] = &*entries {
 6503            let excerpt = editor.update(cx, |editor, cx| {
 6504                editor
 6505                    .buffer()
 6506                    .read(cx)
 6507                    .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6508            })?;
 6509            if let Some((_, excerpted_buffer, excerpt_range)) = excerpt
 6510                && excerpted_buffer == *buffer
 6511            {
 6512                let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6513                    let excerpt_range = excerpt_range.to_offset(buffer);
 6514                    buffer
 6515                        .edited_ranges_for_transaction::<usize>(transaction)
 6516                        .all(|range| {
 6517                            excerpt_range.start <= range.start && excerpt_range.end >= range.end
 6518                        })
 6519                })?;
 6520
 6521                if all_edits_within_excerpt {
 6522                    return Ok(());
 6523                }
 6524            }
 6525        }
 6526
 6527        let mut ranges_to_highlight = Vec::new();
 6528        let excerpt_buffer = cx.new(|cx| {
 6529            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6530            for (buffer_handle, transaction) in &entries {
 6531                let edited_ranges = buffer_handle
 6532                    .read(cx)
 6533                    .edited_ranges_for_transaction::<Point>(transaction)
 6534                    .collect::<Vec<_>>();
 6535                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6536                    PathKey::for_buffer(buffer_handle, cx),
 6537                    buffer_handle.clone(),
 6538                    edited_ranges,
 6539                    multibuffer_context_lines(cx),
 6540                    cx,
 6541                );
 6542
 6543                ranges_to_highlight.extend(ranges);
 6544            }
 6545            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6546            multibuffer
 6547        })?;
 6548
 6549        workspace.update_in(cx, |workspace, window, cx| {
 6550            let project = workspace.project().clone();
 6551            let editor =
 6552                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6553            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6554            editor.update(cx, |editor, cx| {
 6555                editor.highlight_background::<Self>(
 6556                    &ranges_to_highlight,
 6557                    |theme| theme.colors().editor_highlighted_line_background,
 6558                    cx,
 6559                );
 6560            });
 6561        })?;
 6562
 6563        Ok(())
 6564    }
 6565
 6566    pub fn clear_code_action_providers(&mut self) {
 6567        self.code_action_providers.clear();
 6568        self.available_code_actions.take();
 6569    }
 6570
 6571    pub fn add_code_action_provider(
 6572        &mut self,
 6573        provider: Rc<dyn CodeActionProvider>,
 6574        window: &mut Window,
 6575        cx: &mut Context<Self>,
 6576    ) {
 6577        if self
 6578            .code_action_providers
 6579            .iter()
 6580            .any(|existing_provider| existing_provider.id() == provider.id())
 6581        {
 6582            return;
 6583        }
 6584
 6585        self.code_action_providers.push(provider);
 6586        self.refresh_code_actions(window, cx);
 6587    }
 6588
 6589    pub fn remove_code_action_provider(
 6590        &mut self,
 6591        id: Arc<str>,
 6592        window: &mut Window,
 6593        cx: &mut Context<Self>,
 6594    ) {
 6595        self.code_action_providers
 6596            .retain(|provider| provider.id() != id);
 6597        self.refresh_code_actions(window, cx);
 6598    }
 6599
 6600    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6601        !self.code_action_providers.is_empty()
 6602            && EditorSettings::get_global(cx).toolbar.code_actions
 6603    }
 6604
 6605    pub fn has_available_code_actions(&self) -> bool {
 6606        self.available_code_actions
 6607            .as_ref()
 6608            .is_some_and(|(_, actions)| !actions.is_empty())
 6609    }
 6610
 6611    fn render_inline_code_actions(
 6612        &self,
 6613        icon_size: ui::IconSize,
 6614        display_row: DisplayRow,
 6615        is_active: bool,
 6616        cx: &mut Context<Self>,
 6617    ) -> AnyElement {
 6618        let show_tooltip = !self.context_menu_visible();
 6619        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6620            .icon_size(icon_size)
 6621            .shape(ui::IconButtonShape::Square)
 6622            .icon_color(ui::Color::Hidden)
 6623            .toggle_state(is_active)
 6624            .when(show_tooltip, |this| {
 6625                this.tooltip({
 6626                    let focus_handle = self.focus_handle.clone();
 6627                    move |window, cx| {
 6628                        Tooltip::for_action_in(
 6629                            "Toggle Code Actions",
 6630                            &ToggleCodeActions {
 6631                                deployed_from: None,
 6632                                quick_launch: false,
 6633                            },
 6634                            &focus_handle,
 6635                            window,
 6636                            cx,
 6637                        )
 6638                    }
 6639                })
 6640            })
 6641            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6642                window.focus(&editor.focus_handle(cx));
 6643                editor.toggle_code_actions(
 6644                    &crate::actions::ToggleCodeActions {
 6645                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6646                            display_row,
 6647                        )),
 6648                        quick_launch: false,
 6649                    },
 6650                    window,
 6651                    cx,
 6652                );
 6653            }))
 6654            .into_any_element()
 6655    }
 6656
 6657    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6658        &self.context_menu
 6659    }
 6660
 6661    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6662        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6663            cx.background_executor()
 6664                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6665                .await;
 6666
 6667            let (start_buffer, start, _, end, newest_selection) = this
 6668                .update(cx, |this, cx| {
 6669                    let newest_selection = this.selections.newest_anchor().clone();
 6670                    if newest_selection.head().diff_base_anchor.is_some() {
 6671                        return None;
 6672                    }
 6673                    let display_snapshot = this.display_snapshot(cx);
 6674                    let newest_selection_adjusted =
 6675                        this.selections.newest_adjusted(&display_snapshot);
 6676                    let buffer = this.buffer.read(cx);
 6677
 6678                    let (start_buffer, start) =
 6679                        buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6680                    let (end_buffer, end) =
 6681                        buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6682
 6683                    Some((start_buffer, start, end_buffer, end, newest_selection))
 6684                })?
 6685                .filter(|(start_buffer, _, end_buffer, _, _)| start_buffer == end_buffer)
 6686                .context(
 6687                    "Expected selection to lie in a single buffer when refreshing code actions",
 6688                )?;
 6689            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6690                let providers = this.code_action_providers.clone();
 6691                let tasks = this
 6692                    .code_action_providers
 6693                    .iter()
 6694                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6695                    .collect::<Vec<_>>();
 6696                (providers, tasks)
 6697            })?;
 6698
 6699            let mut actions = Vec::new();
 6700            for (provider, provider_actions) in
 6701                providers.into_iter().zip(future::join_all(tasks).await)
 6702            {
 6703                if let Some(provider_actions) = provider_actions.log_err() {
 6704                    actions.extend(provider_actions.into_iter().map(|action| {
 6705                        AvailableCodeAction {
 6706                            excerpt_id: newest_selection.start.excerpt_id,
 6707                            action,
 6708                            provider: provider.clone(),
 6709                        }
 6710                    }));
 6711                }
 6712            }
 6713
 6714            this.update(cx, |this, cx| {
 6715                this.available_code_actions = if actions.is_empty() {
 6716                    None
 6717                } else {
 6718                    Some((
 6719                        Location {
 6720                            buffer: start_buffer,
 6721                            range: start..end,
 6722                        },
 6723                        actions.into(),
 6724                    ))
 6725                };
 6726                cx.notify();
 6727            })
 6728        }));
 6729    }
 6730
 6731    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6732        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6733            self.show_git_blame_inline = false;
 6734
 6735            self.show_git_blame_inline_delay_task =
 6736                Some(cx.spawn_in(window, async move |this, cx| {
 6737                    cx.background_executor().timer(delay).await;
 6738
 6739                    this.update(cx, |this, cx| {
 6740                        this.show_git_blame_inline = true;
 6741                        cx.notify();
 6742                    })
 6743                    .log_err();
 6744                }));
 6745        }
 6746    }
 6747
 6748    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6749        let snapshot = self.snapshot(window, cx);
 6750        let cursor = self
 6751            .selections
 6752            .newest::<Point>(&snapshot.display_snapshot)
 6753            .head();
 6754        let Some((buffer, point, _)) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)
 6755        else {
 6756            return;
 6757        };
 6758
 6759        let Some(blame) = self.blame.as_ref() else {
 6760            return;
 6761        };
 6762
 6763        let row_info = RowInfo {
 6764            buffer_id: Some(buffer.remote_id()),
 6765            buffer_row: Some(point.row),
 6766            ..Default::default()
 6767        };
 6768        let Some((buffer, blame_entry)) = blame
 6769            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6770            .flatten()
 6771        else {
 6772            return;
 6773        };
 6774
 6775        let anchor = self.selections.newest_anchor().head();
 6776        let position = self.to_pixel_point(anchor, &snapshot, window);
 6777        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6778            self.show_blame_popover(
 6779                buffer,
 6780                &blame_entry,
 6781                position + last_bounds.origin,
 6782                true,
 6783                cx,
 6784            );
 6785        };
 6786    }
 6787
 6788    fn show_blame_popover(
 6789        &mut self,
 6790        buffer: BufferId,
 6791        blame_entry: &BlameEntry,
 6792        position: gpui::Point<Pixels>,
 6793        ignore_timeout: bool,
 6794        cx: &mut Context<Self>,
 6795    ) {
 6796        if let Some(state) = &mut self.inline_blame_popover {
 6797            state.hide_task.take();
 6798        } else {
 6799            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay.0;
 6800            let blame_entry = blame_entry.clone();
 6801            let show_task = cx.spawn(async move |editor, cx| {
 6802                if !ignore_timeout {
 6803                    cx.background_executor()
 6804                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6805                        .await;
 6806                }
 6807                editor
 6808                    .update(cx, |editor, cx| {
 6809                        editor.inline_blame_popover_show_task.take();
 6810                        let Some(blame) = editor.blame.as_ref() else {
 6811                            return;
 6812                        };
 6813                        let blame = blame.read(cx);
 6814                        let details = blame.details_for_entry(buffer, &blame_entry);
 6815                        let markdown = cx.new(|cx| {
 6816                            Markdown::new(
 6817                                details
 6818                                    .as_ref()
 6819                                    .map(|message| message.message.clone())
 6820                                    .unwrap_or_default(),
 6821                                None,
 6822                                None,
 6823                                cx,
 6824                            )
 6825                        });
 6826                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6827                            position,
 6828                            hide_task: None,
 6829                            popover_bounds: None,
 6830                            popover_state: InlineBlamePopoverState {
 6831                                scroll_handle: ScrollHandle::new(),
 6832                                commit_message: details,
 6833                                markdown,
 6834                            },
 6835                            keyboard_grace: ignore_timeout,
 6836                        });
 6837                        cx.notify();
 6838                    })
 6839                    .ok();
 6840            });
 6841            self.inline_blame_popover_show_task = Some(show_task);
 6842        }
 6843    }
 6844
 6845    fn hide_blame_popover(&mut self, ignore_timeout: bool, cx: &mut Context<Self>) -> bool {
 6846        self.inline_blame_popover_show_task.take();
 6847        if let Some(state) = &mut self.inline_blame_popover {
 6848            let hide_task = cx.spawn(async move |editor, cx| {
 6849                if !ignore_timeout {
 6850                    cx.background_executor()
 6851                        .timer(std::time::Duration::from_millis(100))
 6852                        .await;
 6853                }
 6854                editor
 6855                    .update(cx, |editor, cx| {
 6856                        editor.inline_blame_popover.take();
 6857                        cx.notify();
 6858                    })
 6859                    .ok();
 6860            });
 6861            state.hide_task = Some(hide_task);
 6862            true
 6863        } else {
 6864            false
 6865        }
 6866    }
 6867
 6868    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6869        if self.pending_rename.is_some() {
 6870            return None;
 6871        }
 6872
 6873        let provider = self.semantics_provider.clone()?;
 6874        let buffer = self.buffer.read(cx);
 6875        let newest_selection = self.selections.newest_anchor().clone();
 6876        let cursor_position = newest_selection.head();
 6877        let (cursor_buffer, cursor_buffer_position) =
 6878            buffer.text_anchor_for_position(cursor_position, cx)?;
 6879        let (tail_buffer, tail_buffer_position) =
 6880            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6881        if cursor_buffer != tail_buffer {
 6882            return None;
 6883        }
 6884
 6885        let snapshot = cursor_buffer.read(cx).snapshot();
 6886        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, None);
 6887        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, None);
 6888        if start_word_range != end_word_range {
 6889            self.document_highlights_task.take();
 6890            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6891            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6892            return None;
 6893        }
 6894
 6895        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce.0;
 6896        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6897            cx.background_executor()
 6898                .timer(Duration::from_millis(debounce))
 6899                .await;
 6900
 6901            let highlights = if let Some(highlights) = cx
 6902                .update(|cx| {
 6903                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6904                })
 6905                .ok()
 6906                .flatten()
 6907            {
 6908                highlights.await.log_err()
 6909            } else {
 6910                None
 6911            };
 6912
 6913            if let Some(highlights) = highlights {
 6914                this.update(cx, |this, cx| {
 6915                    if this.pending_rename.is_some() {
 6916                        return;
 6917                    }
 6918
 6919                    let buffer = this.buffer.read(cx);
 6920                    if buffer
 6921                        .text_anchor_for_position(cursor_position, cx)
 6922                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 6923                    {
 6924                        return;
 6925                    }
 6926
 6927                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6928                    let mut write_ranges = Vec::new();
 6929                    let mut read_ranges = Vec::new();
 6930                    for highlight in highlights {
 6931                        let buffer_id = cursor_buffer.read(cx).remote_id();
 6932                        for (excerpt_id, excerpt_range) in buffer.excerpts_for_buffer(buffer_id, cx)
 6933                        {
 6934                            let start = highlight
 6935                                .range
 6936                                .start
 6937                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6938                            let end = highlight
 6939                                .range
 6940                                .end
 6941                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6942                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6943                                continue;
 6944                            }
 6945
 6946                            let range =
 6947                                Anchor::range_in_buffer(excerpt_id, buffer_id, *start..*end);
 6948                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6949                                write_ranges.push(range);
 6950                            } else {
 6951                                read_ranges.push(range);
 6952                            }
 6953                        }
 6954                    }
 6955
 6956                    this.highlight_background::<DocumentHighlightRead>(
 6957                        &read_ranges,
 6958                        |theme| theme.colors().editor_document_highlight_read_background,
 6959                        cx,
 6960                    );
 6961                    this.highlight_background::<DocumentHighlightWrite>(
 6962                        &write_ranges,
 6963                        |theme| theme.colors().editor_document_highlight_write_background,
 6964                        cx,
 6965                    );
 6966                    cx.notify();
 6967                })
 6968                .log_err();
 6969            }
 6970        }));
 6971        None
 6972    }
 6973
 6974    fn prepare_highlight_query_from_selection(
 6975        &mut self,
 6976        window: &Window,
 6977        cx: &mut Context<Editor>,
 6978    ) -> Option<(String, Range<Anchor>)> {
 6979        if matches!(self.mode, EditorMode::SingleLine) {
 6980            return None;
 6981        }
 6982        if !EditorSettings::get_global(cx).selection_highlight {
 6983            return None;
 6984        }
 6985        if self.selections.count() != 1 || self.selections.line_mode() {
 6986            return None;
 6987        }
 6988        let snapshot = self.snapshot(window, cx);
 6989        let selection = self.selections.newest::<Point>(&snapshot);
 6990        // If the selection spans multiple rows OR it is empty
 6991        if selection.start.row != selection.end.row
 6992            || selection.start.column == selection.end.column
 6993        {
 6994            return None;
 6995        }
 6996        let selection_anchor_range = selection.range().to_anchors(snapshot.buffer_snapshot());
 6997        let query = snapshot
 6998            .buffer_snapshot()
 6999            .text_for_range(selection_anchor_range.clone())
 7000            .collect::<String>();
 7001        if query.trim().is_empty() {
 7002            return None;
 7003        }
 7004        Some((query, selection_anchor_range))
 7005    }
 7006
 7007    fn update_selection_occurrence_highlights(
 7008        &mut self,
 7009        query_text: String,
 7010        query_range: Range<Anchor>,
 7011        multi_buffer_range_to_query: Range<Point>,
 7012        use_debounce: bool,
 7013        window: &mut Window,
 7014        cx: &mut Context<Editor>,
 7015    ) -> Task<()> {
 7016        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7017        cx.spawn_in(window, async move |editor, cx| {
 7018            if use_debounce {
 7019                cx.background_executor()
 7020                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 7021                    .await;
 7022            }
 7023            let match_task = cx.background_spawn(async move {
 7024                let buffer_ranges = multi_buffer_snapshot
 7025                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 7026                    .into_iter()
 7027                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 7028                let mut match_ranges = Vec::new();
 7029                let Ok(regex) = project::search::SearchQuery::text(
 7030                    query_text.clone(),
 7031                    false,
 7032                    false,
 7033                    false,
 7034                    Default::default(),
 7035                    Default::default(),
 7036                    false,
 7037                    None,
 7038                ) else {
 7039                    return Vec::default();
 7040                };
 7041                let query_range = query_range.to_anchors(&multi_buffer_snapshot);
 7042                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 7043                    match_ranges.extend(
 7044                        regex
 7045                            .search(buffer_snapshot, Some(search_range.clone()))
 7046                            .await
 7047                            .into_iter()
 7048                            .filter_map(|match_range| {
 7049                                let match_start = buffer_snapshot
 7050                                    .anchor_after(search_range.start + match_range.start);
 7051                                let match_end = buffer_snapshot
 7052                                    .anchor_before(search_range.start + match_range.end);
 7053                                let match_anchor_range = Anchor::range_in_buffer(
 7054                                    excerpt_id,
 7055                                    buffer_snapshot.remote_id(),
 7056                                    match_start..match_end,
 7057                                );
 7058                                (match_anchor_range != query_range).then_some(match_anchor_range)
 7059                            }),
 7060                    );
 7061                }
 7062                match_ranges
 7063            });
 7064            let match_ranges = match_task.await;
 7065            editor
 7066                .update_in(cx, |editor, _, cx| {
 7067                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 7068                    if !match_ranges.is_empty() {
 7069                        editor.highlight_background::<SelectedTextHighlight>(
 7070                            &match_ranges,
 7071                            |theme| theme.colors().editor_document_highlight_bracket_background,
 7072                            cx,
 7073                        )
 7074                    }
 7075                })
 7076                .log_err();
 7077        })
 7078    }
 7079
 7080    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 7081        struct NewlineFold;
 7082        let type_id = std::any::TypeId::of::<NewlineFold>();
 7083        if !self.mode.is_single_line() {
 7084            return;
 7085        }
 7086        let snapshot = self.snapshot(window, cx);
 7087        if snapshot.buffer_snapshot().max_point().row == 0 {
 7088            return;
 7089        }
 7090        let task = cx.background_spawn(async move {
 7091            let new_newlines = snapshot
 7092                .buffer_chars_at(0)
 7093                .filter_map(|(c, i)| {
 7094                    if c == '\n' {
 7095                        Some(
 7096                            snapshot.buffer_snapshot().anchor_after(i)
 7097                                ..snapshot.buffer_snapshot().anchor_before(i + 1),
 7098                        )
 7099                    } else {
 7100                        None
 7101                    }
 7102                })
 7103                .collect::<Vec<_>>();
 7104            let existing_newlines = snapshot
 7105                .folds_in_range(0..snapshot.buffer_snapshot().len())
 7106                .filter_map(|fold| {
 7107                    if fold.placeholder.type_tag == Some(type_id) {
 7108                        Some(fold.range.start..fold.range.end)
 7109                    } else {
 7110                        None
 7111                    }
 7112                })
 7113                .collect::<Vec<_>>();
 7114
 7115            (new_newlines, existing_newlines)
 7116        });
 7117        self.folding_newlines = cx.spawn(async move |this, cx| {
 7118            let (new_newlines, existing_newlines) = task.await;
 7119            if new_newlines == existing_newlines {
 7120                return;
 7121            }
 7122            let placeholder = FoldPlaceholder {
 7123                render: Arc::new(move |_, _, cx| {
 7124                    div()
 7125                        .bg(cx.theme().status().hint_background)
 7126                        .border_b_1()
 7127                        .size_full()
 7128                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 7129                        .border_color(cx.theme().status().hint)
 7130                        .child("\\n")
 7131                        .into_any()
 7132                }),
 7133                constrain_width: false,
 7134                merge_adjacent: false,
 7135                type_tag: Some(type_id),
 7136            };
 7137            let creases = new_newlines
 7138                .into_iter()
 7139                .map(|range| Crease::simple(range, placeholder.clone()))
 7140                .collect();
 7141            this.update(cx, |this, cx| {
 7142                this.display_map.update(cx, |display_map, cx| {
 7143                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 7144                    display_map.fold(creases, cx);
 7145                });
 7146            })
 7147            .ok();
 7148        });
 7149    }
 7150
 7151    fn refresh_selected_text_highlights(
 7152        &mut self,
 7153        on_buffer_edit: bool,
 7154        window: &mut Window,
 7155        cx: &mut Context<Editor>,
 7156    ) {
 7157        let Some((query_text, query_range)) =
 7158            self.prepare_highlight_query_from_selection(window, cx)
 7159        else {
 7160            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 7161            self.quick_selection_highlight_task.take();
 7162            self.debounced_selection_highlight_task.take();
 7163            return;
 7164        };
 7165        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7166        if on_buffer_edit
 7167            || self
 7168                .quick_selection_highlight_task
 7169                .as_ref()
 7170                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7171        {
 7172            let multi_buffer_visible_start = self
 7173                .scroll_manager
 7174                .anchor()
 7175                .anchor
 7176                .to_point(&multi_buffer_snapshot);
 7177            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 7178                multi_buffer_visible_start
 7179                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 7180                Bias::Left,
 7181            );
 7182            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 7183            self.quick_selection_highlight_task = Some((
 7184                query_range.clone(),
 7185                self.update_selection_occurrence_highlights(
 7186                    query_text.clone(),
 7187                    query_range.clone(),
 7188                    multi_buffer_visible_range,
 7189                    false,
 7190                    window,
 7191                    cx,
 7192                ),
 7193            ));
 7194        }
 7195        if on_buffer_edit
 7196            || self
 7197                .debounced_selection_highlight_task
 7198                .as_ref()
 7199                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7200        {
 7201            let multi_buffer_start = multi_buffer_snapshot
 7202                .anchor_before(0)
 7203                .to_point(&multi_buffer_snapshot);
 7204            let multi_buffer_end = multi_buffer_snapshot
 7205                .anchor_after(multi_buffer_snapshot.len())
 7206                .to_point(&multi_buffer_snapshot);
 7207            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 7208            self.debounced_selection_highlight_task = Some((
 7209                query_range.clone(),
 7210                self.update_selection_occurrence_highlights(
 7211                    query_text,
 7212                    query_range,
 7213                    multi_buffer_full_range,
 7214                    true,
 7215                    window,
 7216                    cx,
 7217                ),
 7218            ));
 7219        }
 7220    }
 7221
 7222    pub fn refresh_edit_prediction(
 7223        &mut self,
 7224        debounce: bool,
 7225        user_requested: bool,
 7226        window: &mut Window,
 7227        cx: &mut Context<Self>,
 7228    ) -> Option<()> {
 7229        if DisableAiSettings::get_global(cx).disable_ai {
 7230            return None;
 7231        }
 7232
 7233        let provider = self.edit_prediction_provider()?;
 7234        let cursor = self.selections.newest_anchor().head();
 7235        let (buffer, cursor_buffer_position) =
 7236            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7237
 7238        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7239            self.discard_edit_prediction(false, cx);
 7240            return None;
 7241        }
 7242
 7243        self.update_visible_edit_prediction(window, cx);
 7244
 7245        if !user_requested
 7246            && (!self.should_show_edit_predictions()
 7247                || !self.is_focused(window)
 7248                || buffer.read(cx).is_empty())
 7249        {
 7250            self.discard_edit_prediction(false, cx);
 7251            return None;
 7252        }
 7253
 7254        provider.refresh(buffer, cursor_buffer_position, debounce, cx);
 7255        Some(())
 7256    }
 7257
 7258    fn show_edit_predictions_in_menu(&self) -> bool {
 7259        match self.edit_prediction_settings {
 7260            EditPredictionSettings::Disabled => false,
 7261            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7262        }
 7263    }
 7264
 7265    pub fn edit_predictions_enabled(&self) -> bool {
 7266        match self.edit_prediction_settings {
 7267            EditPredictionSettings::Disabled => false,
 7268            EditPredictionSettings::Enabled { .. } => true,
 7269        }
 7270    }
 7271
 7272    fn edit_prediction_requires_modifier(&self) -> bool {
 7273        match self.edit_prediction_settings {
 7274            EditPredictionSettings::Disabled => false,
 7275            EditPredictionSettings::Enabled {
 7276                preview_requires_modifier,
 7277                ..
 7278            } => preview_requires_modifier,
 7279        }
 7280    }
 7281
 7282    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7283        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7284            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7285            self.discard_edit_prediction(false, cx);
 7286        } else {
 7287            let selection = self.selections.newest_anchor();
 7288            let cursor = selection.head();
 7289
 7290            if let Some((buffer, cursor_buffer_position)) =
 7291                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7292            {
 7293                self.edit_prediction_settings =
 7294                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7295            }
 7296        }
 7297    }
 7298
 7299    fn edit_prediction_settings_at_position(
 7300        &self,
 7301        buffer: &Entity<Buffer>,
 7302        buffer_position: language::Anchor,
 7303        cx: &App,
 7304    ) -> EditPredictionSettings {
 7305        if !self.mode.is_full()
 7306            || !self.show_edit_predictions_override.unwrap_or(true)
 7307            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7308        {
 7309            return EditPredictionSettings::Disabled;
 7310        }
 7311
 7312        let buffer = buffer.read(cx);
 7313
 7314        let file = buffer.file();
 7315
 7316        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7317            return EditPredictionSettings::Disabled;
 7318        };
 7319
 7320        let by_provider = matches!(
 7321            self.menu_edit_predictions_policy,
 7322            MenuEditPredictionsPolicy::ByProvider
 7323        );
 7324
 7325        let show_in_menu = by_provider
 7326            && self
 7327                .edit_prediction_provider
 7328                .as_ref()
 7329                .is_some_and(|provider| provider.provider.show_completions_in_menu());
 7330
 7331        let preview_requires_modifier =
 7332            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7333
 7334        EditPredictionSettings::Enabled {
 7335            show_in_menu,
 7336            preview_requires_modifier,
 7337        }
 7338    }
 7339
 7340    fn should_show_edit_predictions(&self) -> bool {
 7341        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7342    }
 7343
 7344    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7345        matches!(
 7346            self.edit_prediction_preview,
 7347            EditPredictionPreview::Active { .. }
 7348        )
 7349    }
 7350
 7351    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7352        let cursor = self.selections.newest_anchor().head();
 7353        if let Some((buffer, cursor_position)) =
 7354            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7355        {
 7356            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7357        } else {
 7358            false
 7359        }
 7360    }
 7361
 7362    pub fn supports_minimap(&self, cx: &App) -> bool {
 7363        !self.minimap_visibility.disabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton
 7364    }
 7365
 7366    fn edit_predictions_enabled_in_buffer(
 7367        &self,
 7368        buffer: &Entity<Buffer>,
 7369        buffer_position: language::Anchor,
 7370        cx: &App,
 7371    ) -> bool {
 7372        maybe!({
 7373            if self.read_only(cx) {
 7374                return Some(false);
 7375            }
 7376            let provider = self.edit_prediction_provider()?;
 7377            if !provider.is_enabled(buffer, buffer_position, cx) {
 7378                return Some(false);
 7379            }
 7380            let buffer = buffer.read(cx);
 7381            let Some(file) = buffer.file() else {
 7382                return Some(true);
 7383            };
 7384            let settings = all_language_settings(Some(file), cx);
 7385            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7386        })
 7387        .unwrap_or(false)
 7388    }
 7389
 7390    fn cycle_edit_prediction(
 7391        &mut self,
 7392        direction: Direction,
 7393        window: &mut Window,
 7394        cx: &mut Context<Self>,
 7395    ) -> Option<()> {
 7396        let provider = self.edit_prediction_provider()?;
 7397        let cursor = self.selections.newest_anchor().head();
 7398        let (buffer, cursor_buffer_position) =
 7399            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7400        if self.edit_predictions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7401            return None;
 7402        }
 7403
 7404        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7405        self.update_visible_edit_prediction(window, cx);
 7406
 7407        Some(())
 7408    }
 7409
 7410    pub fn show_edit_prediction(
 7411        &mut self,
 7412        _: &ShowEditPrediction,
 7413        window: &mut Window,
 7414        cx: &mut Context<Self>,
 7415    ) {
 7416        if !self.has_active_edit_prediction() {
 7417            self.refresh_edit_prediction(false, true, window, cx);
 7418            return;
 7419        }
 7420
 7421        self.update_visible_edit_prediction(window, cx);
 7422    }
 7423
 7424    pub fn display_cursor_names(
 7425        &mut self,
 7426        _: &DisplayCursorNames,
 7427        window: &mut Window,
 7428        cx: &mut Context<Self>,
 7429    ) {
 7430        self.show_cursor_names(window, cx);
 7431    }
 7432
 7433    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7434        self.show_cursor_names = true;
 7435        cx.notify();
 7436        cx.spawn_in(window, async move |this, cx| {
 7437            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7438            this.update(cx, |this, cx| {
 7439                this.show_cursor_names = false;
 7440                cx.notify()
 7441            })
 7442            .ok()
 7443        })
 7444        .detach();
 7445    }
 7446
 7447    pub fn next_edit_prediction(
 7448        &mut self,
 7449        _: &NextEditPrediction,
 7450        window: &mut Window,
 7451        cx: &mut Context<Self>,
 7452    ) {
 7453        if self.has_active_edit_prediction() {
 7454            self.cycle_edit_prediction(Direction::Next, window, cx);
 7455        } else {
 7456            let is_copilot_disabled = self
 7457                .refresh_edit_prediction(false, true, window, cx)
 7458                .is_none();
 7459            if is_copilot_disabled {
 7460                cx.propagate();
 7461            }
 7462        }
 7463    }
 7464
 7465    pub fn previous_edit_prediction(
 7466        &mut self,
 7467        _: &PreviousEditPrediction,
 7468        window: &mut Window,
 7469        cx: &mut Context<Self>,
 7470    ) {
 7471        if self.has_active_edit_prediction() {
 7472            self.cycle_edit_prediction(Direction::Prev, window, cx);
 7473        } else {
 7474            let is_copilot_disabled = self
 7475                .refresh_edit_prediction(false, true, window, cx)
 7476                .is_none();
 7477            if is_copilot_disabled {
 7478                cx.propagate();
 7479            }
 7480        }
 7481    }
 7482
 7483    pub fn accept_edit_prediction(
 7484        &mut self,
 7485        _: &AcceptEditPrediction,
 7486        window: &mut Window,
 7487        cx: &mut Context<Self>,
 7488    ) {
 7489        if self.show_edit_predictions_in_menu() {
 7490            self.hide_context_menu(window, cx);
 7491        }
 7492
 7493        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7494            return;
 7495        };
 7496
 7497        match &active_edit_prediction.completion {
 7498            EditPrediction::MoveWithin { target, .. } => {
 7499                let target = *target;
 7500
 7501                if let Some(position_map) = &self.last_position_map {
 7502                    if position_map
 7503                        .visible_row_range
 7504                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7505                        || !self.edit_prediction_requires_modifier()
 7506                    {
 7507                        self.unfold_ranges(&[target..target], true, false, cx);
 7508                        // Note that this is also done in vim's handler of the Tab action.
 7509                        self.change_selections(
 7510                            SelectionEffects::scroll(Autoscroll::newest()),
 7511                            window,
 7512                            cx,
 7513                            |selections| {
 7514                                selections.select_anchor_ranges([target..target]);
 7515                            },
 7516                        );
 7517                        self.clear_row_highlights::<EditPredictionPreview>();
 7518
 7519                        self.edit_prediction_preview
 7520                            .set_previous_scroll_position(None);
 7521                    } else {
 7522                        self.edit_prediction_preview
 7523                            .set_previous_scroll_position(Some(
 7524                                position_map.snapshot.scroll_anchor,
 7525                            ));
 7526
 7527                        self.highlight_rows::<EditPredictionPreview>(
 7528                            target..target,
 7529                            cx.theme().colors().editor_highlighted_line_background,
 7530                            RowHighlightOptions {
 7531                                autoscroll: true,
 7532                                ..Default::default()
 7533                            },
 7534                            cx,
 7535                        );
 7536                        self.request_autoscroll(Autoscroll::fit(), cx);
 7537                    }
 7538                }
 7539            }
 7540            EditPrediction::MoveOutside { snapshot, target } => {
 7541                if let Some(workspace) = self.workspace() {
 7542                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7543                        .detach_and_log_err(cx);
 7544                }
 7545            }
 7546            EditPrediction::Edit { edits, .. } => {
 7547                self.report_edit_prediction_event(
 7548                    active_edit_prediction.completion_id.clone(),
 7549                    true,
 7550                    cx,
 7551                );
 7552
 7553                if let Some(provider) = self.edit_prediction_provider() {
 7554                    provider.accept(cx);
 7555                }
 7556
 7557                // Store the transaction ID and selections before applying the edit
 7558                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7559
 7560                let snapshot = self.buffer.read(cx).snapshot(cx);
 7561                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7562
 7563                self.buffer.update(cx, |buffer, cx| {
 7564                    buffer.edit(edits.iter().cloned(), None, cx)
 7565                });
 7566
 7567                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7568                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7569                });
 7570
 7571                let selections = self.selections.disjoint_anchors_arc();
 7572                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7573                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7574                    if has_new_transaction {
 7575                        self.selection_history
 7576                            .insert_transaction(transaction_id_now, selections);
 7577                    }
 7578                }
 7579
 7580                self.update_visible_edit_prediction(window, cx);
 7581                if self.active_edit_prediction.is_none() {
 7582                    self.refresh_edit_prediction(true, true, window, cx);
 7583                }
 7584
 7585                cx.notify();
 7586            }
 7587        }
 7588
 7589        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7590    }
 7591
 7592    pub fn accept_partial_edit_prediction(
 7593        &mut self,
 7594        _: &AcceptPartialEditPrediction,
 7595        window: &mut Window,
 7596        cx: &mut Context<Self>,
 7597    ) {
 7598        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7599            return;
 7600        };
 7601        if self.selections.count() != 1 {
 7602            return;
 7603        }
 7604
 7605        match &active_edit_prediction.completion {
 7606            EditPrediction::MoveWithin { target, .. } => {
 7607                let target = *target;
 7608                self.change_selections(
 7609                    SelectionEffects::scroll(Autoscroll::newest()),
 7610                    window,
 7611                    cx,
 7612                    |selections| {
 7613                        selections.select_anchor_ranges([target..target]);
 7614                    },
 7615                );
 7616            }
 7617            EditPrediction::MoveOutside { snapshot, target } => {
 7618                if let Some(workspace) = self.workspace() {
 7619                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7620                        .detach_and_log_err(cx);
 7621                }
 7622            }
 7623            EditPrediction::Edit { edits, .. } => {
 7624                self.report_edit_prediction_event(
 7625                    active_edit_prediction.completion_id.clone(),
 7626                    true,
 7627                    cx,
 7628                );
 7629
 7630                // Find an insertion that starts at the cursor position.
 7631                let snapshot = self.buffer.read(cx).snapshot(cx);
 7632                let cursor_offset = self
 7633                    .selections
 7634                    .newest::<usize>(&self.display_snapshot(cx))
 7635                    .head();
 7636                let insertion = edits.iter().find_map(|(range, text)| {
 7637                    let range = range.to_offset(&snapshot);
 7638                    if range.is_empty() && range.start == cursor_offset {
 7639                        Some(text)
 7640                    } else {
 7641                        None
 7642                    }
 7643                });
 7644
 7645                if let Some(text) = insertion {
 7646                    let mut partial_completion = text
 7647                        .chars()
 7648                        .by_ref()
 7649                        .take_while(|c| c.is_alphabetic())
 7650                        .collect::<String>();
 7651                    if partial_completion.is_empty() {
 7652                        partial_completion = text
 7653                            .chars()
 7654                            .by_ref()
 7655                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7656                            .collect::<String>();
 7657                    }
 7658
 7659                    cx.emit(EditorEvent::InputHandled {
 7660                        utf16_range_to_replace: None,
 7661                        text: partial_completion.clone().into(),
 7662                    });
 7663
 7664                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7665
 7666                    self.refresh_edit_prediction(true, true, window, cx);
 7667                    cx.notify();
 7668                } else {
 7669                    self.accept_edit_prediction(&Default::default(), window, cx);
 7670                }
 7671            }
 7672        }
 7673    }
 7674
 7675    fn discard_edit_prediction(
 7676        &mut self,
 7677        should_report_edit_prediction_event: bool,
 7678        cx: &mut Context<Self>,
 7679    ) -> bool {
 7680        if should_report_edit_prediction_event {
 7681            let completion_id = self
 7682                .active_edit_prediction
 7683                .as_ref()
 7684                .and_then(|active_completion| active_completion.completion_id.clone());
 7685
 7686            self.report_edit_prediction_event(completion_id, false, cx);
 7687        }
 7688
 7689        if let Some(provider) = self.edit_prediction_provider() {
 7690            provider.discard(cx);
 7691        }
 7692
 7693        self.take_active_edit_prediction(cx)
 7694    }
 7695
 7696    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7697        let Some(provider) = self.edit_prediction_provider() else {
 7698            return;
 7699        };
 7700
 7701        let Some((_, buffer, _)) = self
 7702            .buffer
 7703            .read(cx)
 7704            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7705        else {
 7706            return;
 7707        };
 7708
 7709        let extension = buffer
 7710            .read(cx)
 7711            .file()
 7712            .and_then(|file| Some(file.path().extension()?.to_string()));
 7713
 7714        let event_type = match accepted {
 7715            true => "Edit Prediction Accepted",
 7716            false => "Edit Prediction Discarded",
 7717        };
 7718        telemetry::event!(
 7719            event_type,
 7720            provider = provider.name(),
 7721            prediction_id = id,
 7722            suggestion_accepted = accepted,
 7723            file_extension = extension,
 7724        );
 7725    }
 7726
 7727    fn open_editor_at_anchor(
 7728        snapshot: &language::BufferSnapshot,
 7729        target: language::Anchor,
 7730        workspace: &Entity<Workspace>,
 7731        window: &mut Window,
 7732        cx: &mut App,
 7733    ) -> Task<Result<()>> {
 7734        workspace.update(cx, |workspace, cx| {
 7735            let path = snapshot.file().map(|file| file.full_path(cx));
 7736            let Some(path) =
 7737                path.and_then(|path| workspace.project().read(cx).find_project_path(path, cx))
 7738            else {
 7739                return Task::ready(Err(anyhow::anyhow!("Project path not found")));
 7740            };
 7741            let target = text::ToPoint::to_point(&target, snapshot);
 7742            let item = workspace.open_path(path, None, true, window, cx);
 7743            window.spawn(cx, async move |cx| {
 7744                let Some(editor) = item.await?.downcast::<Editor>() else {
 7745                    return Ok(());
 7746                };
 7747                editor
 7748                    .update_in(cx, |editor, window, cx| {
 7749                        editor.go_to_singleton_buffer_point(target, window, cx);
 7750                    })
 7751                    .ok();
 7752                anyhow::Ok(())
 7753            })
 7754        })
 7755    }
 7756
 7757    pub fn has_active_edit_prediction(&self) -> bool {
 7758        self.active_edit_prediction.is_some()
 7759    }
 7760
 7761    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7762        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7763            return false;
 7764        };
 7765
 7766        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7767        self.clear_highlights::<EditPredictionHighlight>(cx);
 7768        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7769        true
 7770    }
 7771
 7772    /// Returns true when we're displaying the edit prediction popover below the cursor
 7773    /// like we are not previewing and the LSP autocomplete menu is visible
 7774    /// or we are in `when_holding_modifier` mode.
 7775    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7776        if self.edit_prediction_preview_is_active()
 7777            || !self.show_edit_predictions_in_menu()
 7778            || !self.edit_predictions_enabled()
 7779        {
 7780            return false;
 7781        }
 7782
 7783        if self.has_visible_completions_menu() {
 7784            return true;
 7785        }
 7786
 7787        has_completion && self.edit_prediction_requires_modifier()
 7788    }
 7789
 7790    fn handle_modifiers_changed(
 7791        &mut self,
 7792        modifiers: Modifiers,
 7793        position_map: &PositionMap,
 7794        window: &mut Window,
 7795        cx: &mut Context<Self>,
 7796    ) {
 7797        if self.show_edit_predictions_in_menu() {
 7798            self.update_edit_prediction_preview(&modifiers, window, cx);
 7799        }
 7800
 7801        self.update_selection_mode(&modifiers, position_map, window, cx);
 7802
 7803        let mouse_position = window.mouse_position();
 7804        if !position_map.text_hitbox.is_hovered(window) {
 7805            return;
 7806        }
 7807
 7808        self.update_hovered_link(
 7809            position_map.point_for_position(mouse_position),
 7810            &position_map.snapshot,
 7811            modifiers,
 7812            window,
 7813            cx,
 7814        )
 7815    }
 7816
 7817    fn multi_cursor_modifier(invert: bool, modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7818        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7819        if invert {
 7820            match multi_cursor_setting {
 7821                MultiCursorModifier::Alt => modifiers.alt,
 7822                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7823            }
 7824        } else {
 7825            match multi_cursor_setting {
 7826                MultiCursorModifier::Alt => modifiers.secondary(),
 7827                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7828            }
 7829        }
 7830    }
 7831
 7832    fn columnar_selection_mode(
 7833        modifiers: &Modifiers,
 7834        cx: &mut Context<Self>,
 7835    ) -> Option<ColumnarMode> {
 7836        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7837            if Self::multi_cursor_modifier(false, modifiers, cx) {
 7838                Some(ColumnarMode::FromMouse)
 7839            } else if Self::multi_cursor_modifier(true, modifiers, cx) {
 7840                Some(ColumnarMode::FromSelection)
 7841            } else {
 7842                None
 7843            }
 7844        } else {
 7845            None
 7846        }
 7847    }
 7848
 7849    fn update_selection_mode(
 7850        &mut self,
 7851        modifiers: &Modifiers,
 7852        position_map: &PositionMap,
 7853        window: &mut Window,
 7854        cx: &mut Context<Self>,
 7855    ) {
 7856        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7857            return;
 7858        };
 7859        if self.selections.pending_anchor().is_none() {
 7860            return;
 7861        }
 7862
 7863        let mouse_position = window.mouse_position();
 7864        let point_for_position = position_map.point_for_position(mouse_position);
 7865        let position = point_for_position.previous_valid;
 7866
 7867        self.select(
 7868            SelectPhase::BeginColumnar {
 7869                position,
 7870                reset: false,
 7871                mode,
 7872                goal_column: point_for_position.exact_unclipped.column(),
 7873            },
 7874            window,
 7875            cx,
 7876        );
 7877    }
 7878
 7879    fn update_edit_prediction_preview(
 7880        &mut self,
 7881        modifiers: &Modifiers,
 7882        window: &mut Window,
 7883        cx: &mut Context<Self>,
 7884    ) {
 7885        let mut modifiers_held = false;
 7886        if let Some(accept_keystroke) = self
 7887            .accept_edit_prediction_keybind(false, window, cx)
 7888            .keystroke()
 7889        {
 7890            modifiers_held = modifiers_held
 7891                || (accept_keystroke.modifiers() == modifiers
 7892                    && accept_keystroke.modifiers().modified());
 7893        };
 7894        if let Some(accept_partial_keystroke) = self
 7895            .accept_edit_prediction_keybind(true, window, cx)
 7896            .keystroke()
 7897        {
 7898            modifiers_held = modifiers_held
 7899                || (accept_partial_keystroke.modifiers() == modifiers
 7900                    && accept_partial_keystroke.modifiers().modified());
 7901        }
 7902
 7903        if modifiers_held {
 7904            if matches!(
 7905                self.edit_prediction_preview,
 7906                EditPredictionPreview::Inactive { .. }
 7907            ) {
 7908                self.edit_prediction_preview = EditPredictionPreview::Active {
 7909                    previous_scroll_position: None,
 7910                    since: Instant::now(),
 7911                };
 7912
 7913                self.update_visible_edit_prediction(window, cx);
 7914                cx.notify();
 7915            }
 7916        } else if let EditPredictionPreview::Active {
 7917            previous_scroll_position,
 7918            since,
 7919        } = self.edit_prediction_preview
 7920        {
 7921            if let (Some(previous_scroll_position), Some(position_map)) =
 7922                (previous_scroll_position, self.last_position_map.as_ref())
 7923            {
 7924                self.set_scroll_position(
 7925                    previous_scroll_position
 7926                        .scroll_position(&position_map.snapshot.display_snapshot),
 7927                    window,
 7928                    cx,
 7929                );
 7930            }
 7931
 7932            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7933                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7934            };
 7935            self.clear_row_highlights::<EditPredictionPreview>();
 7936            self.update_visible_edit_prediction(window, cx);
 7937            cx.notify();
 7938        }
 7939    }
 7940
 7941    fn update_visible_edit_prediction(
 7942        &mut self,
 7943        _window: &mut Window,
 7944        cx: &mut Context<Self>,
 7945    ) -> Option<()> {
 7946        if DisableAiSettings::get_global(cx).disable_ai {
 7947            return None;
 7948        }
 7949
 7950        if self.ime_transaction.is_some() {
 7951            self.discard_edit_prediction(false, cx);
 7952            return None;
 7953        }
 7954
 7955        let selection = self.selections.newest_anchor();
 7956        let cursor = selection.head();
 7957        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7958        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7959        let excerpt_id = cursor.excerpt_id;
 7960
 7961        let show_in_menu = self.show_edit_predictions_in_menu();
 7962        let completions_menu_has_precedence = !show_in_menu
 7963            && (self.context_menu.borrow().is_some()
 7964                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 7965
 7966        if completions_menu_has_precedence
 7967            || !offset_selection.is_empty()
 7968            || self
 7969                .active_edit_prediction
 7970                .as_ref()
 7971                .is_some_and(|completion| {
 7972                    let Some(invalidation_range) = completion.invalidation_range.as_ref() else {
 7973                        return false;
 7974                    };
 7975                    let invalidation_range = invalidation_range.to_offset(&multibuffer);
 7976                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7977                    !invalidation_range.contains(&offset_selection.head())
 7978                })
 7979        {
 7980            self.discard_edit_prediction(false, cx);
 7981            return None;
 7982        }
 7983
 7984        self.take_active_edit_prediction(cx);
 7985        let Some(provider) = self.edit_prediction_provider() else {
 7986            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7987            return None;
 7988        };
 7989
 7990        let (buffer, cursor_buffer_position) =
 7991            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7992
 7993        self.edit_prediction_settings =
 7994            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7995
 7996        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7997
 7998        if self.edit_prediction_indent_conflict {
 7999            let cursor_point = cursor.to_point(&multibuffer);
 8000
 8001            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 8002
 8003            if let Some((_, indent)) = indents.iter().next()
 8004                && indent.len == cursor_point.column
 8005            {
 8006                self.edit_prediction_indent_conflict = false;
 8007            }
 8008        }
 8009
 8010        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 8011
 8012        let (completion_id, edits, edit_preview) = match edit_prediction {
 8013            edit_prediction::EditPrediction::Local {
 8014                id,
 8015                edits,
 8016                edit_preview,
 8017            } => (id, edits, edit_preview),
 8018            edit_prediction::EditPrediction::Jump {
 8019                id,
 8020                snapshot,
 8021                target,
 8022            } => {
 8023                self.stale_edit_prediction_in_menu = None;
 8024                self.active_edit_prediction = Some(EditPredictionState {
 8025                    inlay_ids: vec![],
 8026                    completion: EditPrediction::MoveOutside { snapshot, target },
 8027                    completion_id: id,
 8028                    invalidation_range: None,
 8029                });
 8030                cx.notify();
 8031                return Some(());
 8032            }
 8033        };
 8034
 8035        let edits = edits
 8036            .into_iter()
 8037            .flat_map(|(range, new_text)| {
 8038                Some((
 8039                    multibuffer.anchor_range_in_excerpt(excerpt_id, range)?,
 8040                    new_text,
 8041                ))
 8042            })
 8043            .collect::<Vec<_>>();
 8044        if edits.is_empty() {
 8045            return None;
 8046        }
 8047
 8048        let first_edit_start = edits.first().unwrap().0.start;
 8049        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 8050        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 8051
 8052        let last_edit_end = edits.last().unwrap().0.end;
 8053        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 8054        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 8055
 8056        let cursor_row = cursor.to_point(&multibuffer).row;
 8057
 8058        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 8059
 8060        let mut inlay_ids = Vec::new();
 8061        let invalidation_row_range;
 8062        let move_invalidation_row_range = if cursor_row < edit_start_row {
 8063            Some(cursor_row..edit_end_row)
 8064        } else if cursor_row > edit_end_row {
 8065            Some(edit_start_row..cursor_row)
 8066        } else {
 8067            None
 8068        };
 8069        let supports_jump = self
 8070            .edit_prediction_provider
 8071            .as_ref()
 8072            .map(|provider| provider.provider.supports_jump_to_edit())
 8073            .unwrap_or(true);
 8074
 8075        let is_move = supports_jump
 8076            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 8077        let completion = if is_move {
 8078            invalidation_row_range =
 8079                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 8080            let target = first_edit_start;
 8081            EditPrediction::MoveWithin { target, snapshot }
 8082        } else {
 8083            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 8084                && !self.edit_predictions_hidden_for_vim_mode;
 8085
 8086            if show_completions_in_buffer {
 8087                if edits
 8088                    .iter()
 8089                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 8090                {
 8091                    let mut inlays = Vec::new();
 8092                    for (range, new_text) in &edits {
 8093                        let inlay = Inlay::edit_prediction(
 8094                            post_inc(&mut self.next_inlay_id),
 8095                            range.start,
 8096                            new_text.as_str(),
 8097                        );
 8098                        inlay_ids.push(inlay.id);
 8099                        inlays.push(inlay);
 8100                    }
 8101
 8102                    self.splice_inlays(&[], inlays, cx);
 8103                } else {
 8104                    let background_color = cx.theme().status().deleted_background;
 8105                    self.highlight_text::<EditPredictionHighlight>(
 8106                        edits.iter().map(|(range, _)| range.clone()).collect(),
 8107                        HighlightStyle {
 8108                            background_color: Some(background_color),
 8109                            ..Default::default()
 8110                        },
 8111                        cx,
 8112                    );
 8113                }
 8114            }
 8115
 8116            invalidation_row_range = edit_start_row..edit_end_row;
 8117
 8118            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 8119                if provider.show_tab_accept_marker() {
 8120                    EditDisplayMode::TabAccept
 8121                } else {
 8122                    EditDisplayMode::Inline
 8123                }
 8124            } else {
 8125                EditDisplayMode::DiffPopover
 8126            };
 8127
 8128            EditPrediction::Edit {
 8129                edits,
 8130                edit_preview,
 8131                display_mode,
 8132                snapshot,
 8133            }
 8134        };
 8135
 8136        let invalidation_range = multibuffer
 8137            .anchor_before(Point::new(invalidation_row_range.start, 0))
 8138            ..multibuffer.anchor_after(Point::new(
 8139                invalidation_row_range.end,
 8140                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 8141            ));
 8142
 8143        self.stale_edit_prediction_in_menu = None;
 8144        self.active_edit_prediction = Some(EditPredictionState {
 8145            inlay_ids,
 8146            completion,
 8147            completion_id,
 8148            invalidation_range: Some(invalidation_range),
 8149        });
 8150
 8151        cx.notify();
 8152
 8153        Some(())
 8154    }
 8155
 8156    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionProviderHandle>> {
 8157        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 8158    }
 8159
 8160    fn clear_tasks(&mut self) {
 8161        self.tasks.clear()
 8162    }
 8163
 8164    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 8165        if self.tasks.insert(key, value).is_some() {
 8166            // This case should hopefully be rare, but just in case...
 8167            log::error!(
 8168                "multiple different run targets found on a single line, only the last target will be rendered"
 8169            )
 8170        }
 8171    }
 8172
 8173    /// Get all display points of breakpoints that will be rendered within editor
 8174    ///
 8175    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 8176    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 8177    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 8178    fn active_breakpoints(
 8179        &self,
 8180        range: Range<DisplayRow>,
 8181        window: &mut Window,
 8182        cx: &mut Context<Self>,
 8183    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 8184        let mut breakpoint_display_points = HashMap::default();
 8185
 8186        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 8187            return breakpoint_display_points;
 8188        };
 8189
 8190        let snapshot = self.snapshot(window, cx);
 8191
 8192        let multi_buffer_snapshot = snapshot.display_snapshot.buffer_snapshot();
 8193        let Some(project) = self.project() else {
 8194            return breakpoint_display_points;
 8195        };
 8196
 8197        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 8198            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 8199
 8200        for (buffer_snapshot, range, excerpt_id) in
 8201            multi_buffer_snapshot.range_to_buffer_ranges(range)
 8202        {
 8203            let Some(buffer) = project
 8204                .read(cx)
 8205                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 8206            else {
 8207                continue;
 8208            };
 8209            let breakpoints = breakpoint_store.read(cx).breakpoints(
 8210                &buffer,
 8211                Some(
 8212                    buffer_snapshot.anchor_before(range.start)
 8213                        ..buffer_snapshot.anchor_after(range.end),
 8214                ),
 8215                buffer_snapshot,
 8216                cx,
 8217            );
 8218            for (breakpoint, state) in breakpoints {
 8219                let multi_buffer_anchor =
 8220                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 8221                let position = multi_buffer_anchor
 8222                    .to_point(multi_buffer_snapshot)
 8223                    .to_display_point(&snapshot);
 8224
 8225                breakpoint_display_points.insert(
 8226                    position.row(),
 8227                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 8228                );
 8229            }
 8230        }
 8231
 8232        breakpoint_display_points
 8233    }
 8234
 8235    fn breakpoint_context_menu(
 8236        &self,
 8237        anchor: Anchor,
 8238        window: &mut Window,
 8239        cx: &mut Context<Self>,
 8240    ) -> Entity<ui::ContextMenu> {
 8241        let weak_editor = cx.weak_entity();
 8242        let focus_handle = self.focus_handle(cx);
 8243
 8244        let row = self
 8245            .buffer
 8246            .read(cx)
 8247            .snapshot(cx)
 8248            .summary_for_anchor::<Point>(&anchor)
 8249            .row;
 8250
 8251        let breakpoint = self
 8252            .breakpoint_at_row(row, window, cx)
 8253            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 8254
 8255        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 8256            "Edit Log Breakpoint"
 8257        } else {
 8258            "Set Log Breakpoint"
 8259        };
 8260
 8261        let condition_breakpoint_msg = if breakpoint
 8262            .as_ref()
 8263            .is_some_and(|bp| bp.1.condition.is_some())
 8264        {
 8265            "Edit Condition Breakpoint"
 8266        } else {
 8267            "Set Condition Breakpoint"
 8268        };
 8269
 8270        let hit_condition_breakpoint_msg = if breakpoint
 8271            .as_ref()
 8272            .is_some_and(|bp| bp.1.hit_condition.is_some())
 8273        {
 8274            "Edit Hit Condition Breakpoint"
 8275        } else {
 8276            "Set Hit Condition Breakpoint"
 8277        };
 8278
 8279        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 8280            "Unset Breakpoint"
 8281        } else {
 8282            "Set Breakpoint"
 8283        };
 8284
 8285        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8286
 8287        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8288            BreakpointState::Enabled => Some("Disable"),
 8289            BreakpointState::Disabled => Some("Enable"),
 8290        });
 8291
 8292        let (anchor, breakpoint) =
 8293            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8294
 8295        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8296            menu.on_blur_subscription(Subscription::new(|| {}))
 8297                .context(focus_handle)
 8298                .when(run_to_cursor, |this| {
 8299                    let weak_editor = weak_editor.clone();
 8300                    this.entry("Run to cursor", None, move |window, cx| {
 8301                        weak_editor
 8302                            .update(cx, |editor, cx| {
 8303                                editor.change_selections(
 8304                                    SelectionEffects::no_scroll(),
 8305                                    window,
 8306                                    cx,
 8307                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8308                                );
 8309                            })
 8310                            .ok();
 8311
 8312                        window.dispatch_action(Box::new(RunToCursor), cx);
 8313                    })
 8314                    .separator()
 8315                })
 8316                .when_some(toggle_state_msg, |this, msg| {
 8317                    this.entry(msg, None, {
 8318                        let weak_editor = weak_editor.clone();
 8319                        let breakpoint = breakpoint.clone();
 8320                        move |_window, cx| {
 8321                            weak_editor
 8322                                .update(cx, |this, cx| {
 8323                                    this.edit_breakpoint_at_anchor(
 8324                                        anchor,
 8325                                        breakpoint.as_ref().clone(),
 8326                                        BreakpointEditAction::InvertState,
 8327                                        cx,
 8328                                    );
 8329                                })
 8330                                .log_err();
 8331                        }
 8332                    })
 8333                })
 8334                .entry(set_breakpoint_msg, None, {
 8335                    let weak_editor = weak_editor.clone();
 8336                    let breakpoint = breakpoint.clone();
 8337                    move |_window, cx| {
 8338                        weak_editor
 8339                            .update(cx, |this, cx| {
 8340                                this.edit_breakpoint_at_anchor(
 8341                                    anchor,
 8342                                    breakpoint.as_ref().clone(),
 8343                                    BreakpointEditAction::Toggle,
 8344                                    cx,
 8345                                );
 8346                            })
 8347                            .log_err();
 8348                    }
 8349                })
 8350                .entry(log_breakpoint_msg, None, {
 8351                    let breakpoint = breakpoint.clone();
 8352                    let weak_editor = weak_editor.clone();
 8353                    move |window, cx| {
 8354                        weak_editor
 8355                            .update(cx, |this, cx| {
 8356                                this.add_edit_breakpoint_block(
 8357                                    anchor,
 8358                                    breakpoint.as_ref(),
 8359                                    BreakpointPromptEditAction::Log,
 8360                                    window,
 8361                                    cx,
 8362                                );
 8363                            })
 8364                            .log_err();
 8365                    }
 8366                })
 8367                .entry(condition_breakpoint_msg, None, {
 8368                    let breakpoint = breakpoint.clone();
 8369                    let weak_editor = weak_editor.clone();
 8370                    move |window, cx| {
 8371                        weak_editor
 8372                            .update(cx, |this, cx| {
 8373                                this.add_edit_breakpoint_block(
 8374                                    anchor,
 8375                                    breakpoint.as_ref(),
 8376                                    BreakpointPromptEditAction::Condition,
 8377                                    window,
 8378                                    cx,
 8379                                );
 8380                            })
 8381                            .log_err();
 8382                    }
 8383                })
 8384                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8385                    weak_editor
 8386                        .update(cx, |this, cx| {
 8387                            this.add_edit_breakpoint_block(
 8388                                anchor,
 8389                                breakpoint.as_ref(),
 8390                                BreakpointPromptEditAction::HitCondition,
 8391                                window,
 8392                                cx,
 8393                            );
 8394                        })
 8395                        .log_err();
 8396                })
 8397        })
 8398    }
 8399
 8400    fn render_breakpoint(
 8401        &self,
 8402        position: Anchor,
 8403        row: DisplayRow,
 8404        breakpoint: &Breakpoint,
 8405        state: Option<BreakpointSessionState>,
 8406        cx: &mut Context<Self>,
 8407    ) -> IconButton {
 8408        let is_rejected = state.is_some_and(|s| !s.verified);
 8409        // Is it a breakpoint that shows up when hovering over gutter?
 8410        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8411            (false, false),
 8412            |PhantomBreakpointIndicator {
 8413                 is_active,
 8414                 display_row,
 8415                 collides_with_existing_breakpoint,
 8416             }| {
 8417                (
 8418                    is_active && display_row == row,
 8419                    collides_with_existing_breakpoint,
 8420                )
 8421            },
 8422        );
 8423
 8424        let (color, icon) = {
 8425            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8426                (false, false) => ui::IconName::DebugBreakpoint,
 8427                (true, false) => ui::IconName::DebugLogBreakpoint,
 8428                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8429                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8430            };
 8431
 8432            let color = if is_phantom {
 8433                Color::Hint
 8434            } else if is_rejected {
 8435                Color::Disabled
 8436            } else {
 8437                Color::Debugger
 8438            };
 8439
 8440            (color, icon)
 8441        };
 8442
 8443        let breakpoint = Arc::from(breakpoint.clone());
 8444
 8445        let alt_as_text = gpui::Keystroke {
 8446            modifiers: Modifiers::secondary_key(),
 8447            ..Default::default()
 8448        };
 8449        let primary_action_text = if breakpoint.is_disabled() {
 8450            "Enable breakpoint"
 8451        } else if is_phantom && !collides_with_existing {
 8452            "Set breakpoint"
 8453        } else {
 8454            "Unset breakpoint"
 8455        };
 8456        let focus_handle = self.focus_handle.clone();
 8457
 8458        let meta = if is_rejected {
 8459            SharedString::from("No executable code is associated with this line.")
 8460        } else if collides_with_existing && !breakpoint.is_disabled() {
 8461            SharedString::from(format!(
 8462                "{alt_as_text}-click to disable,\nright-click for more options."
 8463            ))
 8464        } else {
 8465            SharedString::from("Right-click for more options.")
 8466        };
 8467        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8468            .icon_size(IconSize::XSmall)
 8469            .size(ui::ButtonSize::None)
 8470            .when(is_rejected, |this| {
 8471                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8472            })
 8473            .icon_color(color)
 8474            .style(ButtonStyle::Transparent)
 8475            .on_click(cx.listener({
 8476                move |editor, event: &ClickEvent, window, cx| {
 8477                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8478                        BreakpointEditAction::InvertState
 8479                    } else {
 8480                        BreakpointEditAction::Toggle
 8481                    };
 8482
 8483                    window.focus(&editor.focus_handle(cx));
 8484                    editor.edit_breakpoint_at_anchor(
 8485                        position,
 8486                        breakpoint.as_ref().clone(),
 8487                        edit_action,
 8488                        cx,
 8489                    );
 8490                }
 8491            }))
 8492            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8493                editor.set_breakpoint_context_menu(
 8494                    row,
 8495                    Some(position),
 8496                    event.position(),
 8497                    window,
 8498                    cx,
 8499                );
 8500            }))
 8501            .tooltip(move |window, cx| {
 8502                Tooltip::with_meta_in(
 8503                    primary_action_text,
 8504                    Some(&ToggleBreakpoint),
 8505                    meta.clone(),
 8506                    &focus_handle,
 8507                    window,
 8508                    cx,
 8509                )
 8510            })
 8511    }
 8512
 8513    fn build_tasks_context(
 8514        project: &Entity<Project>,
 8515        buffer: &Entity<Buffer>,
 8516        buffer_row: u32,
 8517        tasks: &Arc<RunnableTasks>,
 8518        cx: &mut Context<Self>,
 8519    ) -> Task<Option<task::TaskContext>> {
 8520        let position = Point::new(buffer_row, tasks.column);
 8521        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8522        let location = Location {
 8523            buffer: buffer.clone(),
 8524            range: range_start..range_start,
 8525        };
 8526        // Fill in the environmental variables from the tree-sitter captures
 8527        let mut captured_task_variables = TaskVariables::default();
 8528        for (capture_name, value) in tasks.extra_variables.clone() {
 8529            captured_task_variables.insert(
 8530                task::VariableName::Custom(capture_name.into()),
 8531                value.clone(),
 8532            );
 8533        }
 8534        project.update(cx, |project, cx| {
 8535            project.task_store().update(cx, |task_store, cx| {
 8536                task_store.task_context_for_location(captured_task_variables, location, cx)
 8537            })
 8538        })
 8539    }
 8540
 8541    pub fn spawn_nearest_task(
 8542        &mut self,
 8543        action: &SpawnNearestTask,
 8544        window: &mut Window,
 8545        cx: &mut Context<Self>,
 8546    ) {
 8547        let Some((workspace, _)) = self.workspace.clone() else {
 8548            return;
 8549        };
 8550        let Some(project) = self.project.clone() else {
 8551            return;
 8552        };
 8553
 8554        // Try to find a closest, enclosing node using tree-sitter that has a task
 8555        let Some((buffer, buffer_row, tasks)) = self
 8556            .find_enclosing_node_task(cx)
 8557            // Or find the task that's closest in row-distance.
 8558            .or_else(|| self.find_closest_task(cx))
 8559        else {
 8560            return;
 8561        };
 8562
 8563        let reveal_strategy = action.reveal;
 8564        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8565        cx.spawn_in(window, async move |_, cx| {
 8566            let context = task_context.await?;
 8567            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8568
 8569            let resolved = &mut resolved_task.resolved;
 8570            resolved.reveal = reveal_strategy;
 8571
 8572            workspace
 8573                .update_in(cx, |workspace, window, cx| {
 8574                    workspace.schedule_resolved_task(
 8575                        task_source_kind,
 8576                        resolved_task,
 8577                        false,
 8578                        window,
 8579                        cx,
 8580                    );
 8581                })
 8582                .ok()
 8583        })
 8584        .detach();
 8585    }
 8586
 8587    fn find_closest_task(
 8588        &mut self,
 8589        cx: &mut Context<Self>,
 8590    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8591        let cursor_row = self
 8592            .selections
 8593            .newest_adjusted(&self.display_snapshot(cx))
 8594            .head()
 8595            .row;
 8596
 8597        let ((buffer_id, row), tasks) = self
 8598            .tasks
 8599            .iter()
 8600            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8601
 8602        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8603        let tasks = Arc::new(tasks.to_owned());
 8604        Some((buffer, *row, tasks))
 8605    }
 8606
 8607    fn find_enclosing_node_task(
 8608        &mut self,
 8609        cx: &mut Context<Self>,
 8610    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8611        let snapshot = self.buffer.read(cx).snapshot(cx);
 8612        let offset = self
 8613            .selections
 8614            .newest::<usize>(&self.display_snapshot(cx))
 8615            .head();
 8616        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8617        let buffer_id = excerpt.buffer().remote_id();
 8618
 8619        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8620        let mut cursor = layer.node().walk();
 8621
 8622        while cursor.goto_first_child_for_byte(offset).is_some() {
 8623            if cursor.node().end_byte() == offset {
 8624                cursor.goto_next_sibling();
 8625            }
 8626        }
 8627
 8628        // Ascend to the smallest ancestor that contains the range and has a task.
 8629        loop {
 8630            let node = cursor.node();
 8631            let node_range = node.byte_range();
 8632            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8633
 8634            // Check if this node contains our offset
 8635            if node_range.start <= offset && node_range.end >= offset {
 8636                // If it contains offset, check for task
 8637                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8638                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8639                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8640                }
 8641            }
 8642
 8643            if !cursor.goto_parent() {
 8644                break;
 8645            }
 8646        }
 8647        None
 8648    }
 8649
 8650    fn render_run_indicator(
 8651        &self,
 8652        _style: &EditorStyle,
 8653        is_active: bool,
 8654        row: DisplayRow,
 8655        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8656        cx: &mut Context<Self>,
 8657    ) -> IconButton {
 8658        let color = Color::Muted;
 8659        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8660
 8661        IconButton::new(
 8662            ("run_indicator", row.0 as usize),
 8663            ui::IconName::PlayOutlined,
 8664        )
 8665        .shape(ui::IconButtonShape::Square)
 8666        .icon_size(IconSize::XSmall)
 8667        .icon_color(color)
 8668        .toggle_state(is_active)
 8669        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8670            let quick_launch = match e {
 8671                ClickEvent::Keyboard(_) => true,
 8672                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8673            };
 8674
 8675            window.focus(&editor.focus_handle(cx));
 8676            editor.toggle_code_actions(
 8677                &ToggleCodeActions {
 8678                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8679                    quick_launch,
 8680                },
 8681                window,
 8682                cx,
 8683            );
 8684        }))
 8685        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8686            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8687        }))
 8688    }
 8689
 8690    pub fn context_menu_visible(&self) -> bool {
 8691        !self.edit_prediction_preview_is_active()
 8692            && self
 8693                .context_menu
 8694                .borrow()
 8695                .as_ref()
 8696                .is_some_and(|menu| menu.visible())
 8697    }
 8698
 8699    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8700        self.context_menu
 8701            .borrow()
 8702            .as_ref()
 8703            .map(|menu| menu.origin())
 8704    }
 8705
 8706    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8707        self.context_menu_options = Some(options);
 8708    }
 8709
 8710    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = px(24.);
 8711    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = px(2.);
 8712
 8713    fn render_edit_prediction_popover(
 8714        &mut self,
 8715        text_bounds: &Bounds<Pixels>,
 8716        content_origin: gpui::Point<Pixels>,
 8717        right_margin: Pixels,
 8718        editor_snapshot: &EditorSnapshot,
 8719        visible_row_range: Range<DisplayRow>,
 8720        scroll_top: ScrollOffset,
 8721        scroll_bottom: ScrollOffset,
 8722        line_layouts: &[LineWithInvisibles],
 8723        line_height: Pixels,
 8724        scroll_position: gpui::Point<ScrollOffset>,
 8725        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8726        newest_selection_head: Option<DisplayPoint>,
 8727        editor_width: Pixels,
 8728        style: &EditorStyle,
 8729        window: &mut Window,
 8730        cx: &mut App,
 8731    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8732        if self.mode().is_minimap() {
 8733            return None;
 8734        }
 8735        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8736
 8737        if self.edit_prediction_visible_in_cursor_popover(true) {
 8738            return None;
 8739        }
 8740
 8741        match &active_edit_prediction.completion {
 8742            EditPrediction::MoveWithin { target, .. } => {
 8743                let target_display_point = target.to_display_point(editor_snapshot);
 8744
 8745                if self.edit_prediction_requires_modifier() {
 8746                    if !self.edit_prediction_preview_is_active() {
 8747                        return None;
 8748                    }
 8749
 8750                    self.render_edit_prediction_modifier_jump_popover(
 8751                        text_bounds,
 8752                        content_origin,
 8753                        visible_row_range,
 8754                        line_layouts,
 8755                        line_height,
 8756                        scroll_pixel_position,
 8757                        newest_selection_head,
 8758                        target_display_point,
 8759                        window,
 8760                        cx,
 8761                    )
 8762                } else {
 8763                    self.render_edit_prediction_eager_jump_popover(
 8764                        text_bounds,
 8765                        content_origin,
 8766                        editor_snapshot,
 8767                        visible_row_range,
 8768                        scroll_top,
 8769                        scroll_bottom,
 8770                        line_height,
 8771                        scroll_pixel_position,
 8772                        target_display_point,
 8773                        editor_width,
 8774                        window,
 8775                        cx,
 8776                    )
 8777                }
 8778            }
 8779            EditPrediction::Edit {
 8780                display_mode: EditDisplayMode::Inline,
 8781                ..
 8782            } => None,
 8783            EditPrediction::Edit {
 8784                display_mode: EditDisplayMode::TabAccept,
 8785                edits,
 8786                ..
 8787            } => {
 8788                let range = &edits.first()?.0;
 8789                let target_display_point = range.end.to_display_point(editor_snapshot);
 8790
 8791                self.render_edit_prediction_end_of_line_popover(
 8792                    "Accept",
 8793                    editor_snapshot,
 8794                    visible_row_range,
 8795                    target_display_point,
 8796                    line_height,
 8797                    scroll_pixel_position,
 8798                    content_origin,
 8799                    editor_width,
 8800                    window,
 8801                    cx,
 8802                )
 8803            }
 8804            EditPrediction::Edit {
 8805                edits,
 8806                edit_preview,
 8807                display_mode: EditDisplayMode::DiffPopover,
 8808                snapshot,
 8809            } => self.render_edit_prediction_diff_popover(
 8810                text_bounds,
 8811                content_origin,
 8812                right_margin,
 8813                editor_snapshot,
 8814                visible_row_range,
 8815                line_layouts,
 8816                line_height,
 8817                scroll_position,
 8818                scroll_pixel_position,
 8819                newest_selection_head,
 8820                editor_width,
 8821                style,
 8822                edits,
 8823                edit_preview,
 8824                snapshot,
 8825                window,
 8826                cx,
 8827            ),
 8828            EditPrediction::MoveOutside { snapshot, .. } => {
 8829                let file_name = snapshot
 8830                    .file()
 8831                    .map(|file| file.file_name(cx))
 8832                    .unwrap_or("untitled");
 8833                let mut element = self
 8834                    .render_edit_prediction_line_popover(
 8835                        format!("Jump to {file_name}"),
 8836                        Some(IconName::ZedPredict),
 8837                        window,
 8838                        cx,
 8839                    )
 8840                    .into_any();
 8841
 8842                let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8843                let origin_x = text_bounds.size.width / 2. - size.width / 2.;
 8844                let origin_y = text_bounds.size.height - size.height - px(30.);
 8845                let origin = text_bounds.origin + gpui::Point::new(origin_x, origin_y);
 8846                element.prepaint_at(origin, window, cx);
 8847
 8848                Some((element, origin))
 8849            }
 8850        }
 8851    }
 8852
 8853    fn render_edit_prediction_modifier_jump_popover(
 8854        &mut self,
 8855        text_bounds: &Bounds<Pixels>,
 8856        content_origin: gpui::Point<Pixels>,
 8857        visible_row_range: Range<DisplayRow>,
 8858        line_layouts: &[LineWithInvisibles],
 8859        line_height: Pixels,
 8860        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8861        newest_selection_head: Option<DisplayPoint>,
 8862        target_display_point: DisplayPoint,
 8863        window: &mut Window,
 8864        cx: &mut App,
 8865    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8866        let scrolled_content_origin =
 8867            content_origin - gpui::Point::new(scroll_pixel_position.x.into(), Pixels::ZERO);
 8868
 8869        const SCROLL_PADDING_Y: Pixels = px(12.);
 8870
 8871        if target_display_point.row() < visible_row_range.start {
 8872            return self.render_edit_prediction_scroll_popover(
 8873                |_| SCROLL_PADDING_Y,
 8874                IconName::ArrowUp,
 8875                visible_row_range,
 8876                line_layouts,
 8877                newest_selection_head,
 8878                scrolled_content_origin,
 8879                window,
 8880                cx,
 8881            );
 8882        } else if target_display_point.row() >= visible_row_range.end {
 8883            return self.render_edit_prediction_scroll_popover(
 8884                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8885                IconName::ArrowDown,
 8886                visible_row_range,
 8887                line_layouts,
 8888                newest_selection_head,
 8889                scrolled_content_origin,
 8890                window,
 8891                cx,
 8892            );
 8893        }
 8894
 8895        const POLE_WIDTH: Pixels = px(2.);
 8896
 8897        let line_layout =
 8898            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8899        let target_column = target_display_point.column() as usize;
 8900
 8901        let target_x = line_layout.x_for_index(target_column);
 8902        let target_y = (target_display_point.row().as_f64() * f64::from(line_height))
 8903            - scroll_pixel_position.y;
 8904
 8905        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8906
 8907        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8908        border_color.l += 0.001;
 8909
 8910        let mut element = v_flex()
 8911            .items_end()
 8912            .when(flag_on_right, |el| el.items_start())
 8913            .child(if flag_on_right {
 8914                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8915                    .rounded_bl(px(0.))
 8916                    .rounded_tl(px(0.))
 8917                    .border_l_2()
 8918                    .border_color(border_color)
 8919            } else {
 8920                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8921                    .rounded_br(px(0.))
 8922                    .rounded_tr(px(0.))
 8923                    .border_r_2()
 8924                    .border_color(border_color)
 8925            })
 8926            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8927            .into_any();
 8928
 8929        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8930
 8931        let mut origin = scrolled_content_origin + point(target_x, target_y.into())
 8932            - point(
 8933                if flag_on_right {
 8934                    POLE_WIDTH
 8935                } else {
 8936                    size.width - POLE_WIDTH
 8937                },
 8938                size.height - line_height,
 8939            );
 8940
 8941        origin.x = origin.x.max(content_origin.x);
 8942
 8943        element.prepaint_at(origin, window, cx);
 8944
 8945        Some((element, origin))
 8946    }
 8947
 8948    fn render_edit_prediction_scroll_popover(
 8949        &mut self,
 8950        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8951        scroll_icon: IconName,
 8952        visible_row_range: Range<DisplayRow>,
 8953        line_layouts: &[LineWithInvisibles],
 8954        newest_selection_head: Option<DisplayPoint>,
 8955        scrolled_content_origin: gpui::Point<Pixels>,
 8956        window: &mut Window,
 8957        cx: &mut App,
 8958    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8959        let mut element = self
 8960            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)
 8961            .into_any();
 8962
 8963        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8964
 8965        let cursor = newest_selection_head?;
 8966        let cursor_row_layout =
 8967            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8968        let cursor_column = cursor.column() as usize;
 8969
 8970        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8971
 8972        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8973
 8974        element.prepaint_at(origin, window, cx);
 8975        Some((element, origin))
 8976    }
 8977
 8978    fn render_edit_prediction_eager_jump_popover(
 8979        &mut self,
 8980        text_bounds: &Bounds<Pixels>,
 8981        content_origin: gpui::Point<Pixels>,
 8982        editor_snapshot: &EditorSnapshot,
 8983        visible_row_range: Range<DisplayRow>,
 8984        scroll_top: ScrollOffset,
 8985        scroll_bottom: ScrollOffset,
 8986        line_height: Pixels,
 8987        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8988        target_display_point: DisplayPoint,
 8989        editor_width: Pixels,
 8990        window: &mut Window,
 8991        cx: &mut App,
 8992    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8993        if target_display_point.row().as_f64() < scroll_top {
 8994            let mut element = self
 8995                .render_edit_prediction_line_popover(
 8996                    "Jump to Edit",
 8997                    Some(IconName::ArrowUp),
 8998                    window,
 8999                    cx,
 9000                )
 9001                .into_any();
 9002
 9003            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9004            let offset = point(
 9005                (text_bounds.size.width - size.width) / 2.,
 9006                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 9007            );
 9008
 9009            let origin = text_bounds.origin + offset;
 9010            element.prepaint_at(origin, window, cx);
 9011            Some((element, origin))
 9012        } else if (target_display_point.row().as_f64() + 1.) > scroll_bottom {
 9013            let mut element = self
 9014                .render_edit_prediction_line_popover(
 9015                    "Jump to Edit",
 9016                    Some(IconName::ArrowDown),
 9017                    window,
 9018                    cx,
 9019                )
 9020                .into_any();
 9021
 9022            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9023            let offset = point(
 9024                (text_bounds.size.width - size.width) / 2.,
 9025                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 9026            );
 9027
 9028            let origin = text_bounds.origin + offset;
 9029            element.prepaint_at(origin, window, cx);
 9030            Some((element, origin))
 9031        } else {
 9032            self.render_edit_prediction_end_of_line_popover(
 9033                "Jump to Edit",
 9034                editor_snapshot,
 9035                visible_row_range,
 9036                target_display_point,
 9037                line_height,
 9038                scroll_pixel_position,
 9039                content_origin,
 9040                editor_width,
 9041                window,
 9042                cx,
 9043            )
 9044        }
 9045    }
 9046
 9047    fn render_edit_prediction_end_of_line_popover(
 9048        self: &mut Editor,
 9049        label: &'static str,
 9050        editor_snapshot: &EditorSnapshot,
 9051        visible_row_range: Range<DisplayRow>,
 9052        target_display_point: DisplayPoint,
 9053        line_height: Pixels,
 9054        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9055        content_origin: gpui::Point<Pixels>,
 9056        editor_width: Pixels,
 9057        window: &mut Window,
 9058        cx: &mut App,
 9059    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9060        let target_line_end = DisplayPoint::new(
 9061            target_display_point.row(),
 9062            editor_snapshot.line_len(target_display_point.row()),
 9063        );
 9064
 9065        let mut element = self
 9066            .render_edit_prediction_line_popover(label, None, window, cx)
 9067            .into_any();
 9068
 9069        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9070
 9071        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 9072
 9073        let start_point = content_origin - point(scroll_pixel_position.x.into(), Pixels::ZERO);
 9074        let mut origin = start_point
 9075            + line_origin
 9076            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 9077        origin.x = origin.x.max(content_origin.x);
 9078
 9079        let max_x = content_origin.x + editor_width - size.width;
 9080
 9081        if origin.x > max_x {
 9082            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 9083
 9084            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 9085                origin.y += offset;
 9086                IconName::ArrowUp
 9087            } else {
 9088                origin.y -= offset;
 9089                IconName::ArrowDown
 9090            };
 9091
 9092            element = self
 9093                .render_edit_prediction_line_popover(label, Some(icon), window, cx)
 9094                .into_any();
 9095
 9096            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9097
 9098            origin.x = content_origin.x + editor_width - size.width - px(2.);
 9099        }
 9100
 9101        element.prepaint_at(origin, window, cx);
 9102        Some((element, origin))
 9103    }
 9104
 9105    fn render_edit_prediction_diff_popover(
 9106        self: &Editor,
 9107        text_bounds: &Bounds<Pixels>,
 9108        content_origin: gpui::Point<Pixels>,
 9109        right_margin: Pixels,
 9110        editor_snapshot: &EditorSnapshot,
 9111        visible_row_range: Range<DisplayRow>,
 9112        line_layouts: &[LineWithInvisibles],
 9113        line_height: Pixels,
 9114        scroll_position: gpui::Point<ScrollOffset>,
 9115        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9116        newest_selection_head: Option<DisplayPoint>,
 9117        editor_width: Pixels,
 9118        style: &EditorStyle,
 9119        edits: &Vec<(Range<Anchor>, String)>,
 9120        edit_preview: &Option<language::EditPreview>,
 9121        snapshot: &language::BufferSnapshot,
 9122        window: &mut Window,
 9123        cx: &mut App,
 9124    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9125        let edit_start = edits
 9126            .first()
 9127            .unwrap()
 9128            .0
 9129            .start
 9130            .to_display_point(editor_snapshot);
 9131        let edit_end = edits
 9132            .last()
 9133            .unwrap()
 9134            .0
 9135            .end
 9136            .to_display_point(editor_snapshot);
 9137
 9138        let is_visible = visible_row_range.contains(&edit_start.row())
 9139            || visible_row_range.contains(&edit_end.row());
 9140        if !is_visible {
 9141            return None;
 9142        }
 9143
 9144        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 9145            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 9146        } else {
 9147            // Fallback for providers without edit_preview
 9148            crate::edit_prediction_fallback_text(edits, cx)
 9149        };
 9150
 9151        let styled_text = highlighted_edits.to_styled_text(&style.text);
 9152        let line_count = highlighted_edits.text.lines().count();
 9153
 9154        const BORDER_WIDTH: Pixels = px(1.);
 9155
 9156        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9157        let has_keybind = keybind.is_some();
 9158
 9159        let mut element = h_flex()
 9160            .items_start()
 9161            .child(
 9162                h_flex()
 9163                    .bg(cx.theme().colors().editor_background)
 9164                    .border(BORDER_WIDTH)
 9165                    .shadow_xs()
 9166                    .border_color(cx.theme().colors().border)
 9167                    .rounded_l_lg()
 9168                    .when(line_count > 1, |el| el.rounded_br_lg())
 9169                    .pr_1()
 9170                    .child(styled_text),
 9171            )
 9172            .child(
 9173                h_flex()
 9174                    .h(line_height + BORDER_WIDTH * 2.)
 9175                    .px_1p5()
 9176                    .gap_1()
 9177                    // Workaround: For some reason, there's a gap if we don't do this
 9178                    .ml(-BORDER_WIDTH)
 9179                    .shadow(vec![gpui::BoxShadow {
 9180                        color: gpui::black().opacity(0.05),
 9181                        offset: point(px(1.), px(1.)),
 9182                        blur_radius: px(2.),
 9183                        spread_radius: px(0.),
 9184                    }])
 9185                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 9186                    .border(BORDER_WIDTH)
 9187                    .border_color(cx.theme().colors().border)
 9188                    .rounded_r_lg()
 9189                    .id("edit_prediction_diff_popover_keybind")
 9190                    .when(!has_keybind, |el| {
 9191                        let status_colors = cx.theme().status();
 9192
 9193                        el.bg(status_colors.error_background)
 9194                            .border_color(status_colors.error.opacity(0.6))
 9195                            .child(Icon::new(IconName::Info).color(Color::Error))
 9196                            .cursor_default()
 9197                            .hoverable_tooltip(move |_window, cx| {
 9198                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9199                            })
 9200                    })
 9201                    .children(keybind),
 9202            )
 9203            .into_any();
 9204
 9205        let longest_row =
 9206            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 9207        let longest_line_width = if visible_row_range.contains(&longest_row) {
 9208            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 9209        } else {
 9210            layout_line(
 9211                longest_row,
 9212                editor_snapshot,
 9213                style,
 9214                editor_width,
 9215                |_| false,
 9216                window,
 9217                cx,
 9218            )
 9219            .width
 9220        };
 9221
 9222        let viewport_bounds =
 9223            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 9224                right: -right_margin,
 9225                ..Default::default()
 9226            });
 9227
 9228        let x_after_longest = Pixels::from(
 9229            ScrollPixelOffset::from(
 9230                text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X,
 9231            ) - scroll_pixel_position.x,
 9232        );
 9233
 9234        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9235
 9236        // Fully visible if it can be displayed within the window (allow overlapping other
 9237        // panes). However, this is only allowed if the popover starts within text_bounds.
 9238        let can_position_to_the_right = x_after_longest < text_bounds.right()
 9239            && x_after_longest + element_bounds.width < viewport_bounds.right();
 9240
 9241        let mut origin = if can_position_to_the_right {
 9242            point(
 9243                x_after_longest,
 9244                text_bounds.origin.y
 9245                    + Pixels::from(
 9246                        edit_start.row().as_f64() * ScrollPixelOffset::from(line_height)
 9247                            - scroll_pixel_position.y,
 9248                    ),
 9249            )
 9250        } else {
 9251            let cursor_row = newest_selection_head.map(|head| head.row());
 9252            let above_edit = edit_start
 9253                .row()
 9254                .0
 9255                .checked_sub(line_count as u32)
 9256                .map(DisplayRow);
 9257            let below_edit = Some(edit_end.row() + 1);
 9258            let above_cursor =
 9259                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 9260            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 9261
 9262            // Place the edit popover adjacent to the edit if there is a location
 9263            // available that is onscreen and does not obscure the cursor. Otherwise,
 9264            // place it adjacent to the cursor.
 9265            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 9266                .into_iter()
 9267                .flatten()
 9268                .find(|&start_row| {
 9269                    let end_row = start_row + line_count as u32;
 9270                    visible_row_range.contains(&start_row)
 9271                        && visible_row_range.contains(&end_row)
 9272                        && cursor_row
 9273                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9274                })?;
 9275
 9276            content_origin
 9277                + point(
 9278                    Pixels::from(-scroll_pixel_position.x),
 9279                    Pixels::from(
 9280                        (row_target.as_f64() - scroll_position.y) * f64::from(line_height),
 9281                    ),
 9282                )
 9283        };
 9284
 9285        origin.x -= BORDER_WIDTH;
 9286
 9287        window.defer_draw(element, origin, 1);
 9288
 9289        // Do not return an element, since it will already be drawn due to defer_draw.
 9290        None
 9291    }
 9292
 9293    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9294        px(30.)
 9295    }
 9296
 9297    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9298        if self.read_only(cx) {
 9299            cx.theme().players().read_only()
 9300        } else {
 9301            self.style.as_ref().unwrap().local_player
 9302        }
 9303    }
 9304
 9305    fn render_edit_prediction_accept_keybind(
 9306        &self,
 9307        window: &mut Window,
 9308        cx: &mut App,
 9309    ) -> Option<AnyElement> {
 9310        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 9311        let accept_keystroke = accept_binding.keystroke()?;
 9312
 9313        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9314
 9315        let modifiers_color = if *accept_keystroke.modifiers() == window.modifiers() {
 9316            Color::Accent
 9317        } else {
 9318            Color::Muted
 9319        };
 9320
 9321        h_flex()
 9322            .px_0p5()
 9323            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9324            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9325            .text_size(TextSize::XSmall.rems(cx))
 9326            .child(h_flex().children(ui::render_modifiers(
 9327                accept_keystroke.modifiers(),
 9328                PlatformStyle::platform(),
 9329                Some(modifiers_color),
 9330                Some(IconSize::XSmall.rems().into()),
 9331                true,
 9332            )))
 9333            .when(is_platform_style_mac, |parent| {
 9334                parent.child(accept_keystroke.key().to_string())
 9335            })
 9336            .when(!is_platform_style_mac, |parent| {
 9337                parent.child(
 9338                    Key::new(
 9339                        util::capitalize(accept_keystroke.key()),
 9340                        Some(Color::Default),
 9341                    )
 9342                    .size(Some(IconSize::XSmall.rems().into())),
 9343                )
 9344            })
 9345            .into_any()
 9346            .into()
 9347    }
 9348
 9349    fn render_edit_prediction_line_popover(
 9350        &self,
 9351        label: impl Into<SharedString>,
 9352        icon: Option<IconName>,
 9353        window: &mut Window,
 9354        cx: &mut App,
 9355    ) -> Stateful<Div> {
 9356        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9357
 9358        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9359        let has_keybind = keybind.is_some();
 9360
 9361        h_flex()
 9362            .id("ep-line-popover")
 9363            .py_0p5()
 9364            .pl_1()
 9365            .pr(padding_right)
 9366            .gap_1()
 9367            .rounded_md()
 9368            .border_1()
 9369            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9370            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9371            .shadow_xs()
 9372            .when(!has_keybind, |el| {
 9373                let status_colors = cx.theme().status();
 9374
 9375                el.bg(status_colors.error_background)
 9376                    .border_color(status_colors.error.opacity(0.6))
 9377                    .pl_2()
 9378                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9379                    .cursor_default()
 9380                    .hoverable_tooltip(move |_window, cx| {
 9381                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9382                    })
 9383            })
 9384            .children(keybind)
 9385            .child(
 9386                Label::new(label)
 9387                    .size(LabelSize::Small)
 9388                    .when(!has_keybind, |el| {
 9389                        el.color(cx.theme().status().error.into()).strikethrough()
 9390                    }),
 9391            )
 9392            .when(!has_keybind, |el| {
 9393                el.child(
 9394                    h_flex().ml_1().child(
 9395                        Icon::new(IconName::Info)
 9396                            .size(IconSize::Small)
 9397                            .color(cx.theme().status().error.into()),
 9398                    ),
 9399                )
 9400            })
 9401            .when_some(icon, |element, icon| {
 9402                element.child(
 9403                    div()
 9404                        .mt(px(1.5))
 9405                        .child(Icon::new(icon).size(IconSize::Small)),
 9406                )
 9407            })
 9408    }
 9409
 9410    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9411        let accent_color = cx.theme().colors().text_accent;
 9412        let editor_bg_color = cx.theme().colors().editor_background;
 9413        editor_bg_color.blend(accent_color.opacity(0.1))
 9414    }
 9415
 9416    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9417        let accent_color = cx.theme().colors().text_accent;
 9418        let editor_bg_color = cx.theme().colors().editor_background;
 9419        editor_bg_color.blend(accent_color.opacity(0.6))
 9420    }
 9421    fn get_prediction_provider_icon_name(
 9422        provider: &Option<RegisteredEditPredictionProvider>,
 9423    ) -> IconName {
 9424        match provider {
 9425            Some(provider) => match provider.provider.name() {
 9426                "copilot" => IconName::Copilot,
 9427                "supermaven" => IconName::Supermaven,
 9428                _ => IconName::ZedPredict,
 9429            },
 9430            None => IconName::ZedPredict,
 9431        }
 9432    }
 9433
 9434    fn render_edit_prediction_cursor_popover(
 9435        &self,
 9436        min_width: Pixels,
 9437        max_width: Pixels,
 9438        cursor_point: Point,
 9439        style: &EditorStyle,
 9440        accept_keystroke: Option<&gpui::KeybindingKeystroke>,
 9441        _window: &Window,
 9442        cx: &mut Context<Editor>,
 9443    ) -> Option<AnyElement> {
 9444        let provider = self.edit_prediction_provider.as_ref()?;
 9445        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9446
 9447        let is_refreshing = provider.provider.is_refreshing(cx);
 9448
 9449        fn pending_completion_container(icon: IconName) -> Div {
 9450            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9451        }
 9452
 9453        let completion = match &self.active_edit_prediction {
 9454            Some(prediction) => {
 9455                if !self.has_visible_completions_menu() {
 9456                    const RADIUS: Pixels = px(6.);
 9457                    const BORDER_WIDTH: Pixels = px(1.);
 9458
 9459                    return Some(
 9460                        h_flex()
 9461                            .elevation_2(cx)
 9462                            .border(BORDER_WIDTH)
 9463                            .border_color(cx.theme().colors().border)
 9464                            .when(accept_keystroke.is_none(), |el| {
 9465                                el.border_color(cx.theme().status().error)
 9466                            })
 9467                            .rounded(RADIUS)
 9468                            .rounded_tl(px(0.))
 9469                            .overflow_hidden()
 9470                            .child(div().px_1p5().child(match &prediction.completion {
 9471                                EditPrediction::MoveWithin { target, snapshot } => {
 9472                                    use text::ToPoint as _;
 9473                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9474                                    {
 9475                                        Icon::new(IconName::ZedPredictDown)
 9476                                    } else {
 9477                                        Icon::new(IconName::ZedPredictUp)
 9478                                    }
 9479                                }
 9480                                EditPrediction::MoveOutside { .. } => {
 9481                                    // TODO [zeta2] custom icon for external jump?
 9482                                    Icon::new(provider_icon)
 9483                                }
 9484                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9485                            }))
 9486                            .child(
 9487                                h_flex()
 9488                                    .gap_1()
 9489                                    .py_1()
 9490                                    .px_2()
 9491                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9492                                    .border_l_1()
 9493                                    .border_color(cx.theme().colors().border)
 9494                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9495                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9496                                        el.child(
 9497                                            Label::new("Hold")
 9498                                                .size(LabelSize::Small)
 9499                                                .when(accept_keystroke.is_none(), |el| {
 9500                                                    el.strikethrough()
 9501                                                })
 9502                                                .line_height_style(LineHeightStyle::UiLabel),
 9503                                        )
 9504                                    })
 9505                                    .id("edit_prediction_cursor_popover_keybind")
 9506                                    .when(accept_keystroke.is_none(), |el| {
 9507                                        let status_colors = cx.theme().status();
 9508
 9509                                        el.bg(status_colors.error_background)
 9510                                            .border_color(status_colors.error.opacity(0.6))
 9511                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9512                                            .cursor_default()
 9513                                            .hoverable_tooltip(move |_window, cx| {
 9514                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9515                                                    .into()
 9516                                            })
 9517                                    })
 9518                                    .when_some(
 9519                                        accept_keystroke.as_ref(),
 9520                                        |el, accept_keystroke| {
 9521                                            el.child(h_flex().children(ui::render_modifiers(
 9522                                                accept_keystroke.modifiers(),
 9523                                                PlatformStyle::platform(),
 9524                                                Some(Color::Default),
 9525                                                Some(IconSize::XSmall.rems().into()),
 9526                                                false,
 9527                                            )))
 9528                                        },
 9529                                    ),
 9530                            )
 9531                            .into_any(),
 9532                    );
 9533                }
 9534
 9535                self.render_edit_prediction_cursor_popover_preview(
 9536                    prediction,
 9537                    cursor_point,
 9538                    style,
 9539                    cx,
 9540                )?
 9541            }
 9542
 9543            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9544                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9545                    stale_completion,
 9546                    cursor_point,
 9547                    style,
 9548                    cx,
 9549                )?,
 9550
 9551                None => pending_completion_container(provider_icon)
 9552                    .child(Label::new("...").size(LabelSize::Small)),
 9553            },
 9554
 9555            None => pending_completion_container(provider_icon)
 9556                .child(Label::new("...").size(LabelSize::Small)),
 9557        };
 9558
 9559        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9560            completion
 9561                .with_animation(
 9562                    "loading-completion",
 9563                    Animation::new(Duration::from_secs(2))
 9564                        .repeat()
 9565                        .with_easing(pulsating_between(0.4, 0.8)),
 9566                    |label, delta| label.opacity(delta),
 9567                )
 9568                .into_any_element()
 9569        } else {
 9570            completion.into_any_element()
 9571        };
 9572
 9573        let has_completion = self.active_edit_prediction.is_some();
 9574
 9575        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9576        Some(
 9577            h_flex()
 9578                .min_w(min_width)
 9579                .max_w(max_width)
 9580                .flex_1()
 9581                .elevation_2(cx)
 9582                .border_color(cx.theme().colors().border)
 9583                .child(
 9584                    div()
 9585                        .flex_1()
 9586                        .py_1()
 9587                        .px_2()
 9588                        .overflow_hidden()
 9589                        .child(completion),
 9590                )
 9591                .when_some(accept_keystroke, |el, accept_keystroke| {
 9592                    if !accept_keystroke.modifiers().modified() {
 9593                        return el;
 9594                    }
 9595
 9596                    el.child(
 9597                        h_flex()
 9598                            .h_full()
 9599                            .border_l_1()
 9600                            .rounded_r_lg()
 9601                            .border_color(cx.theme().colors().border)
 9602                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9603                            .gap_1()
 9604                            .py_1()
 9605                            .px_2()
 9606                            .child(
 9607                                h_flex()
 9608                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9609                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9610                                    .child(h_flex().children(ui::render_modifiers(
 9611                                        accept_keystroke.modifiers(),
 9612                                        PlatformStyle::platform(),
 9613                                        Some(if !has_completion {
 9614                                            Color::Muted
 9615                                        } else {
 9616                                            Color::Default
 9617                                        }),
 9618                                        None,
 9619                                        false,
 9620                                    ))),
 9621                            )
 9622                            .child(Label::new("Preview").into_any_element())
 9623                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9624                    )
 9625                })
 9626                .into_any(),
 9627        )
 9628    }
 9629
 9630    fn render_edit_prediction_cursor_popover_preview(
 9631        &self,
 9632        completion: &EditPredictionState,
 9633        cursor_point: Point,
 9634        style: &EditorStyle,
 9635        cx: &mut Context<Editor>,
 9636    ) -> Option<Div> {
 9637        use text::ToPoint as _;
 9638
 9639        fn render_relative_row_jump(
 9640            prefix: impl Into<String>,
 9641            current_row: u32,
 9642            target_row: u32,
 9643        ) -> Div {
 9644            let (row_diff, arrow) = if target_row < current_row {
 9645                (current_row - target_row, IconName::ArrowUp)
 9646            } else {
 9647                (target_row - current_row, IconName::ArrowDown)
 9648            };
 9649
 9650            h_flex()
 9651                .child(
 9652                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9653                        .color(Color::Muted)
 9654                        .size(LabelSize::Small),
 9655                )
 9656                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9657        }
 9658
 9659        let supports_jump = self
 9660            .edit_prediction_provider
 9661            .as_ref()
 9662            .map(|provider| provider.provider.supports_jump_to_edit())
 9663            .unwrap_or(true);
 9664
 9665        match &completion.completion {
 9666            EditPrediction::MoveWithin {
 9667                target, snapshot, ..
 9668            } => {
 9669                if !supports_jump {
 9670                    return None;
 9671                }
 9672
 9673                Some(
 9674                    h_flex()
 9675                        .px_2()
 9676                        .gap_2()
 9677                        .flex_1()
 9678                        .child(
 9679                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
 9680                                Icon::new(IconName::ZedPredictDown)
 9681                            } else {
 9682                                Icon::new(IconName::ZedPredictUp)
 9683                            },
 9684                        )
 9685                        .child(Label::new("Jump to Edit")),
 9686                )
 9687            }
 9688            EditPrediction::MoveOutside { snapshot, .. } => {
 9689                let file_name = snapshot
 9690                    .file()
 9691                    .map(|file| file.file_name(cx))
 9692                    .unwrap_or("untitled");
 9693                Some(
 9694                    h_flex()
 9695                        .px_2()
 9696                        .gap_2()
 9697                        .flex_1()
 9698                        .child(Icon::new(IconName::ZedPredict))
 9699                        .child(Label::new(format!("Jump to {file_name}"))),
 9700                )
 9701            }
 9702            EditPrediction::Edit {
 9703                edits,
 9704                edit_preview,
 9705                snapshot,
 9706                display_mode: _,
 9707            } => {
 9708                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
 9709
 9710                let (highlighted_edits, has_more_lines) =
 9711                    if let Some(edit_preview) = edit_preview.as_ref() {
 9712                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
 9713                            .first_line_preview()
 9714                    } else {
 9715                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
 9716                    };
 9717
 9718                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9719                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9720
 9721                let preview = h_flex()
 9722                    .gap_1()
 9723                    .min_w_16()
 9724                    .child(styled_text)
 9725                    .when(has_more_lines, |parent| parent.child(""));
 9726
 9727                let left = if supports_jump && first_edit_row != cursor_point.row {
 9728                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9729                        .into_any_element()
 9730                } else {
 9731                    let icon_name =
 9732                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9733                    Icon::new(icon_name).into_any_element()
 9734                };
 9735
 9736                Some(
 9737                    h_flex()
 9738                        .h_full()
 9739                        .flex_1()
 9740                        .gap_2()
 9741                        .pr_1()
 9742                        .overflow_x_hidden()
 9743                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9744                        .child(left)
 9745                        .child(preview),
 9746                )
 9747            }
 9748        }
 9749    }
 9750
 9751    pub fn render_context_menu(
 9752        &self,
 9753        style: &EditorStyle,
 9754        max_height_in_lines: u32,
 9755        window: &mut Window,
 9756        cx: &mut Context<Editor>,
 9757    ) -> Option<AnyElement> {
 9758        let menu = self.context_menu.borrow();
 9759        let menu = menu.as_ref()?;
 9760        if !menu.visible() {
 9761            return None;
 9762        };
 9763        Some(menu.render(style, max_height_in_lines, window, cx))
 9764    }
 9765
 9766    fn render_context_menu_aside(
 9767        &mut self,
 9768        max_size: Size<Pixels>,
 9769        window: &mut Window,
 9770        cx: &mut Context<Editor>,
 9771    ) -> Option<AnyElement> {
 9772        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9773            if menu.visible() {
 9774                menu.render_aside(max_size, window, cx)
 9775            } else {
 9776                None
 9777            }
 9778        })
 9779    }
 9780
 9781    fn hide_context_menu(
 9782        &mut self,
 9783        window: &mut Window,
 9784        cx: &mut Context<Self>,
 9785    ) -> Option<CodeContextMenu> {
 9786        cx.notify();
 9787        self.completion_tasks.clear();
 9788        let context_menu = self.context_menu.borrow_mut().take();
 9789        self.stale_edit_prediction_in_menu.take();
 9790        self.update_visible_edit_prediction(window, cx);
 9791        if let Some(CodeContextMenu::Completions(_)) = &context_menu
 9792            && let Some(completion_provider) = &self.completion_provider
 9793        {
 9794            completion_provider.selection_changed(None, window, cx);
 9795        }
 9796        context_menu
 9797    }
 9798
 9799    fn show_snippet_choices(
 9800        &mut self,
 9801        choices: &Vec<String>,
 9802        selection: Range<Anchor>,
 9803        cx: &mut Context<Self>,
 9804    ) {
 9805        let Some((_, buffer, _)) = self
 9806            .buffer()
 9807            .read(cx)
 9808            .excerpt_containing(selection.start, cx)
 9809        else {
 9810            return;
 9811        };
 9812        let Some((_, end_buffer, _)) = self.buffer().read(cx).excerpt_containing(selection.end, cx)
 9813        else {
 9814            return;
 9815        };
 9816        if buffer != end_buffer {
 9817            log::error!("expected anchor range to have matching buffer IDs");
 9818            return;
 9819        }
 9820
 9821        let id = post_inc(&mut self.next_completion_id);
 9822        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9823        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9824            CompletionsMenu::new_snippet_choices(
 9825                id,
 9826                true,
 9827                choices,
 9828                selection,
 9829                buffer,
 9830                snippet_sort_order,
 9831            ),
 9832        ));
 9833    }
 9834
 9835    pub fn insert_snippet(
 9836        &mut self,
 9837        insertion_ranges: &[Range<usize>],
 9838        snippet: Snippet,
 9839        window: &mut Window,
 9840        cx: &mut Context<Self>,
 9841    ) -> Result<()> {
 9842        struct Tabstop<T> {
 9843            is_end_tabstop: bool,
 9844            ranges: Vec<Range<T>>,
 9845            choices: Option<Vec<String>>,
 9846        }
 9847
 9848        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9849            let snippet_text: Arc<str> = snippet.text.clone().into();
 9850            let edits = insertion_ranges
 9851                .iter()
 9852                .cloned()
 9853                .map(|range| (range, snippet_text.clone()));
 9854            let autoindent_mode = AutoindentMode::Block {
 9855                original_indent_columns: Vec::new(),
 9856            };
 9857            buffer.edit(edits, Some(autoindent_mode), cx);
 9858
 9859            let snapshot = &*buffer.read(cx);
 9860            let snippet = &snippet;
 9861            snippet
 9862                .tabstops
 9863                .iter()
 9864                .map(|tabstop| {
 9865                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
 9866                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9867                    });
 9868                    let mut tabstop_ranges = tabstop
 9869                        .ranges
 9870                        .iter()
 9871                        .flat_map(|tabstop_range| {
 9872                            let mut delta = 0_isize;
 9873                            insertion_ranges.iter().map(move |insertion_range| {
 9874                                let insertion_start = insertion_range.start as isize + delta;
 9875                                delta +=
 9876                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9877
 9878                                let start = ((insertion_start + tabstop_range.start) as usize)
 9879                                    .min(snapshot.len());
 9880                                let end = ((insertion_start + tabstop_range.end) as usize)
 9881                                    .min(snapshot.len());
 9882                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9883                            })
 9884                        })
 9885                        .collect::<Vec<_>>();
 9886                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9887
 9888                    Tabstop {
 9889                        is_end_tabstop,
 9890                        ranges: tabstop_ranges,
 9891                        choices: tabstop.choices.clone(),
 9892                    }
 9893                })
 9894                .collect::<Vec<_>>()
 9895        });
 9896        if let Some(tabstop) = tabstops.first() {
 9897            self.change_selections(Default::default(), window, cx, |s| {
 9898                // Reverse order so that the first range is the newest created selection.
 9899                // Completions will use it and autoscroll will prioritize it.
 9900                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9901            });
 9902
 9903            if let Some(choices) = &tabstop.choices
 9904                && let Some(selection) = tabstop.ranges.first()
 9905            {
 9906                self.show_snippet_choices(choices, selection.clone(), cx)
 9907            }
 9908
 9909            // If we're already at the last tabstop and it's at the end of the snippet,
 9910            // we're done, we don't need to keep the state around.
 9911            if !tabstop.is_end_tabstop {
 9912                let choices = tabstops
 9913                    .iter()
 9914                    .map(|tabstop| tabstop.choices.clone())
 9915                    .collect();
 9916
 9917                let ranges = tabstops
 9918                    .into_iter()
 9919                    .map(|tabstop| tabstop.ranges)
 9920                    .collect::<Vec<_>>();
 9921
 9922                self.snippet_stack.push(SnippetState {
 9923                    active_index: 0,
 9924                    ranges,
 9925                    choices,
 9926                });
 9927            }
 9928
 9929            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9930            if self.autoclose_regions.is_empty() {
 9931                let snapshot = self.buffer.read(cx).snapshot(cx);
 9932                for selection in &mut self.selections.all::<Point>(&self.display_snapshot(cx)) {
 9933                    let selection_head = selection.head();
 9934                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9935                        continue;
 9936                    };
 9937
 9938                    let mut bracket_pair = None;
 9939                    let max_lookup_length = scope
 9940                        .brackets()
 9941                        .map(|(pair, _)| {
 9942                            pair.start
 9943                                .as_str()
 9944                                .chars()
 9945                                .count()
 9946                                .max(pair.end.as_str().chars().count())
 9947                        })
 9948                        .max();
 9949                    if let Some(max_lookup_length) = max_lookup_length {
 9950                        let next_text = snapshot
 9951                            .chars_at(selection_head)
 9952                            .take(max_lookup_length)
 9953                            .collect::<String>();
 9954                        let prev_text = snapshot
 9955                            .reversed_chars_at(selection_head)
 9956                            .take(max_lookup_length)
 9957                            .collect::<String>();
 9958
 9959                        for (pair, enabled) in scope.brackets() {
 9960                            if enabled
 9961                                && pair.close
 9962                                && prev_text.starts_with(pair.start.as_str())
 9963                                && next_text.starts_with(pair.end.as_str())
 9964                            {
 9965                                bracket_pair = Some(pair.clone());
 9966                                break;
 9967                            }
 9968                        }
 9969                    }
 9970
 9971                    if let Some(pair) = bracket_pair {
 9972                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9973                        let autoclose_enabled =
 9974                            self.use_autoclose && snapshot_settings.use_autoclose;
 9975                        if autoclose_enabled {
 9976                            let start = snapshot.anchor_after(selection_head);
 9977                            let end = snapshot.anchor_after(selection_head);
 9978                            self.autoclose_regions.push(AutocloseRegion {
 9979                                selection_id: selection.id,
 9980                                range: start..end,
 9981                                pair,
 9982                            });
 9983                        }
 9984                    }
 9985                }
 9986            }
 9987        }
 9988        Ok(())
 9989    }
 9990
 9991    pub fn move_to_next_snippet_tabstop(
 9992        &mut self,
 9993        window: &mut Window,
 9994        cx: &mut Context<Self>,
 9995    ) -> bool {
 9996        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9997    }
 9998
 9999    pub fn move_to_prev_snippet_tabstop(
10000        &mut self,
10001        window: &mut Window,
10002        cx: &mut Context<Self>,
10003    ) -> bool {
10004        self.move_to_snippet_tabstop(Bias::Left, window, cx)
10005    }
10006
10007    pub fn move_to_snippet_tabstop(
10008        &mut self,
10009        bias: Bias,
10010        window: &mut Window,
10011        cx: &mut Context<Self>,
10012    ) -> bool {
10013        if let Some(mut snippet) = self.snippet_stack.pop() {
10014            match bias {
10015                Bias::Left => {
10016                    if snippet.active_index > 0 {
10017                        snippet.active_index -= 1;
10018                    } else {
10019                        self.snippet_stack.push(snippet);
10020                        return false;
10021                    }
10022                }
10023                Bias::Right => {
10024                    if snippet.active_index + 1 < snippet.ranges.len() {
10025                        snippet.active_index += 1;
10026                    } else {
10027                        self.snippet_stack.push(snippet);
10028                        return false;
10029                    }
10030                }
10031            }
10032            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
10033                self.change_selections(Default::default(), window, cx, |s| {
10034                    // Reverse order so that the first range is the newest created selection.
10035                    // Completions will use it and autoscroll will prioritize it.
10036                    s.select_ranges(current_ranges.iter().rev().cloned())
10037                });
10038
10039                if let Some(choices) = &snippet.choices[snippet.active_index]
10040                    && let Some(selection) = current_ranges.first()
10041                {
10042                    self.show_snippet_choices(choices, selection.clone(), cx);
10043                }
10044
10045                // If snippet state is not at the last tabstop, push it back on the stack
10046                if snippet.active_index + 1 < snippet.ranges.len() {
10047                    self.snippet_stack.push(snippet);
10048                }
10049                return true;
10050            }
10051        }
10052
10053        false
10054    }
10055
10056    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
10057        self.transact(window, cx, |this, window, cx| {
10058            this.select_all(&SelectAll, window, cx);
10059            this.insert("", window, cx);
10060        });
10061    }
10062
10063    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
10064        if self.read_only(cx) {
10065            return;
10066        }
10067        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10068        self.transact(window, cx, |this, window, cx| {
10069            this.select_autoclose_pair(window, cx);
10070
10071            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
10072
10073            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
10074            if !this.linked_edit_ranges.is_empty() {
10075                let selections = this.selections.all::<MultiBufferPoint>(&display_map);
10076                let snapshot = this.buffer.read(cx).snapshot(cx);
10077
10078                for selection in selections.iter() {
10079                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
10080                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
10081                    if selection_start.buffer_id != selection_end.buffer_id {
10082                        continue;
10083                    }
10084                    if let Some(ranges) =
10085                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
10086                    {
10087                        for (buffer, entries) in ranges {
10088                            linked_ranges.entry(buffer).or_default().extend(entries);
10089                        }
10090                    }
10091                }
10092            }
10093
10094            let mut selections = this.selections.all::<MultiBufferPoint>(&display_map);
10095            for selection in &mut selections {
10096                if selection.is_empty() {
10097                    let old_head = selection.head();
10098                    let mut new_head =
10099                        movement::left(&display_map, old_head.to_display_point(&display_map))
10100                            .to_point(&display_map);
10101                    if let Some((buffer, line_buffer_range)) = display_map
10102                        .buffer_snapshot()
10103                        .buffer_line_for_row(MultiBufferRow(old_head.row))
10104                    {
10105                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
10106                        let indent_len = match indent_size.kind {
10107                            IndentKind::Space => {
10108                                buffer.settings_at(line_buffer_range.start, cx).tab_size
10109                            }
10110                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
10111                        };
10112                        if old_head.column <= indent_size.len && old_head.column > 0 {
10113                            let indent_len = indent_len.get();
10114                            new_head = cmp::min(
10115                                new_head,
10116                                MultiBufferPoint::new(
10117                                    old_head.row,
10118                                    ((old_head.column - 1) / indent_len) * indent_len,
10119                                ),
10120                            );
10121                        }
10122                    }
10123
10124                    selection.set_head(new_head, SelectionGoal::None);
10125                }
10126            }
10127
10128            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10129            this.insert("", window, cx);
10130            let empty_str: Arc<str> = Arc::from("");
10131            for (buffer, edits) in linked_ranges {
10132                let snapshot = buffer.read(cx).snapshot();
10133                use text::ToPoint as TP;
10134
10135                let edits = edits
10136                    .into_iter()
10137                    .map(|range| {
10138                        let end_point = TP::to_point(&range.end, &snapshot);
10139                        let mut start_point = TP::to_point(&range.start, &snapshot);
10140
10141                        if end_point == start_point {
10142                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
10143                                .saturating_sub(1);
10144                            start_point =
10145                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
10146                        };
10147
10148                        (start_point..end_point, empty_str.clone())
10149                    })
10150                    .sorted_by_key(|(range, _)| range.start)
10151                    .collect::<Vec<_>>();
10152                buffer.update(cx, |this, cx| {
10153                    this.edit(edits, None, cx);
10154                })
10155            }
10156            this.refresh_edit_prediction(true, false, window, cx);
10157            refresh_linked_ranges(this, window, cx);
10158        });
10159    }
10160
10161    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
10162        if self.read_only(cx) {
10163            return;
10164        }
10165        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10166        self.transact(window, cx, |this, window, cx| {
10167            this.change_selections(Default::default(), window, cx, |s| {
10168                s.move_with(|map, selection| {
10169                    if selection.is_empty() {
10170                        let cursor = movement::right(map, selection.head());
10171                        selection.end = cursor;
10172                        selection.reversed = true;
10173                        selection.goal = SelectionGoal::None;
10174                    }
10175                })
10176            });
10177            this.insert("", window, cx);
10178            this.refresh_edit_prediction(true, false, window, cx);
10179        });
10180    }
10181
10182    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
10183        if self.mode.is_single_line() {
10184            cx.propagate();
10185            return;
10186        }
10187
10188        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10189        if self.move_to_prev_snippet_tabstop(window, cx) {
10190            return;
10191        }
10192        self.outdent(&Outdent, window, cx);
10193    }
10194
10195    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
10196        if self.mode.is_single_line() {
10197            cx.propagate();
10198            return;
10199        }
10200
10201        if self.move_to_next_snippet_tabstop(window, cx) {
10202            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10203            return;
10204        }
10205        if self.read_only(cx) {
10206            return;
10207        }
10208        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10209        let mut selections = self.selections.all_adjusted(&self.display_snapshot(cx));
10210        let buffer = self.buffer.read(cx);
10211        let snapshot = buffer.snapshot(cx);
10212        let rows_iter = selections.iter().map(|s| s.head().row);
10213        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
10214
10215        let has_some_cursor_in_whitespace = selections
10216            .iter()
10217            .filter(|selection| selection.is_empty())
10218            .any(|selection| {
10219                let cursor = selection.head();
10220                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10221                cursor.column < current_indent.len
10222            });
10223
10224        let mut edits = Vec::new();
10225        let mut prev_edited_row = 0;
10226        let mut row_delta = 0;
10227        for selection in &mut selections {
10228            if selection.start.row != prev_edited_row {
10229                row_delta = 0;
10230            }
10231            prev_edited_row = selection.end.row;
10232
10233            // If the selection is non-empty, then increase the indentation of the selected lines.
10234            if !selection.is_empty() {
10235                row_delta =
10236                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10237                continue;
10238            }
10239
10240            let cursor = selection.head();
10241            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10242            if let Some(suggested_indent) =
10243                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
10244            {
10245                // Don't do anything if already at suggested indent
10246                // and there is any other cursor which is not
10247                if has_some_cursor_in_whitespace
10248                    && cursor.column == current_indent.len
10249                    && current_indent.len == suggested_indent.len
10250                {
10251                    continue;
10252                }
10253
10254                // Adjust line and move cursor to suggested indent
10255                // if cursor is not at suggested indent
10256                if cursor.column < suggested_indent.len
10257                    && cursor.column <= current_indent.len
10258                    && current_indent.len <= suggested_indent.len
10259                {
10260                    selection.start = Point::new(cursor.row, suggested_indent.len);
10261                    selection.end = selection.start;
10262                    if row_delta == 0 {
10263                        edits.extend(Buffer::edit_for_indent_size_adjustment(
10264                            cursor.row,
10265                            current_indent,
10266                            suggested_indent,
10267                        ));
10268                        row_delta = suggested_indent.len - current_indent.len;
10269                    }
10270                    continue;
10271                }
10272
10273                // If current indent is more than suggested indent
10274                // only move cursor to current indent and skip indent
10275                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
10276                    selection.start = Point::new(cursor.row, current_indent.len);
10277                    selection.end = selection.start;
10278                    continue;
10279                }
10280            }
10281
10282            // Otherwise, insert a hard or soft tab.
10283            let settings = buffer.language_settings_at(cursor, cx);
10284            let tab_size = if settings.hard_tabs {
10285                IndentSize::tab()
10286            } else {
10287                let tab_size = settings.tab_size.get();
10288                let indent_remainder = snapshot
10289                    .text_for_range(Point::new(cursor.row, 0)..cursor)
10290                    .flat_map(str::chars)
10291                    .fold(row_delta % tab_size, |counter: u32, c| {
10292                        if c == '\t' {
10293                            0
10294                        } else {
10295                            (counter + 1) % tab_size
10296                        }
10297                    });
10298
10299                let chars_to_next_tab_stop = tab_size - indent_remainder;
10300                IndentSize::spaces(chars_to_next_tab_stop)
10301            };
10302            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
10303            selection.end = selection.start;
10304            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
10305            row_delta += tab_size.len;
10306        }
10307
10308        self.transact(window, cx, |this, window, cx| {
10309            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10310            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10311            this.refresh_edit_prediction(true, false, window, cx);
10312        });
10313    }
10314
10315    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10316        if self.read_only(cx) {
10317            return;
10318        }
10319        if self.mode.is_single_line() {
10320            cx.propagate();
10321            return;
10322        }
10323
10324        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10325        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
10326        let mut prev_edited_row = 0;
10327        let mut row_delta = 0;
10328        let mut edits = Vec::new();
10329        let buffer = self.buffer.read(cx);
10330        let snapshot = buffer.snapshot(cx);
10331        for selection in &mut selections {
10332            if selection.start.row != prev_edited_row {
10333                row_delta = 0;
10334            }
10335            prev_edited_row = selection.end.row;
10336
10337            row_delta =
10338                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10339        }
10340
10341        self.transact(window, cx, |this, window, cx| {
10342            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10343            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10344        });
10345    }
10346
10347    fn indent_selection(
10348        buffer: &MultiBuffer,
10349        snapshot: &MultiBufferSnapshot,
10350        selection: &mut Selection<Point>,
10351        edits: &mut Vec<(Range<Point>, String)>,
10352        delta_for_start_row: u32,
10353        cx: &App,
10354    ) -> u32 {
10355        let settings = buffer.language_settings_at(selection.start, cx);
10356        let tab_size = settings.tab_size.get();
10357        let indent_kind = if settings.hard_tabs {
10358            IndentKind::Tab
10359        } else {
10360            IndentKind::Space
10361        };
10362        let mut start_row = selection.start.row;
10363        let mut end_row = selection.end.row + 1;
10364
10365        // If a selection ends at the beginning of a line, don't indent
10366        // that last line.
10367        if selection.end.column == 0 && selection.end.row > selection.start.row {
10368            end_row -= 1;
10369        }
10370
10371        // Avoid re-indenting a row that has already been indented by a
10372        // previous selection, but still update this selection's column
10373        // to reflect that indentation.
10374        if delta_for_start_row > 0 {
10375            start_row += 1;
10376            selection.start.column += delta_for_start_row;
10377            if selection.end.row == selection.start.row {
10378                selection.end.column += delta_for_start_row;
10379            }
10380        }
10381
10382        let mut delta_for_end_row = 0;
10383        let has_multiple_rows = start_row + 1 != end_row;
10384        for row in start_row..end_row {
10385            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10386            let indent_delta = match (current_indent.kind, indent_kind) {
10387                (IndentKind::Space, IndentKind::Space) => {
10388                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10389                    IndentSize::spaces(columns_to_next_tab_stop)
10390                }
10391                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10392                (_, IndentKind::Tab) => IndentSize::tab(),
10393            };
10394
10395            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10396                0
10397            } else {
10398                selection.start.column
10399            };
10400            let row_start = Point::new(row, start);
10401            edits.push((
10402                row_start..row_start,
10403                indent_delta.chars().collect::<String>(),
10404            ));
10405
10406            // Update this selection's endpoints to reflect the indentation.
10407            if row == selection.start.row {
10408                selection.start.column += indent_delta.len;
10409            }
10410            if row == selection.end.row {
10411                selection.end.column += indent_delta.len;
10412                delta_for_end_row = indent_delta.len;
10413            }
10414        }
10415
10416        if selection.start.row == selection.end.row {
10417            delta_for_start_row + delta_for_end_row
10418        } else {
10419            delta_for_end_row
10420        }
10421    }
10422
10423    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10424        if self.read_only(cx) {
10425            return;
10426        }
10427        if self.mode.is_single_line() {
10428            cx.propagate();
10429            return;
10430        }
10431
10432        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10433        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10434        let selections = self.selections.all::<Point>(&display_map);
10435        let mut deletion_ranges = Vec::new();
10436        let mut last_outdent = None;
10437        {
10438            let buffer = self.buffer.read(cx);
10439            let snapshot = buffer.snapshot(cx);
10440            for selection in &selections {
10441                let settings = buffer.language_settings_at(selection.start, cx);
10442                let tab_size = settings.tab_size.get();
10443                let mut rows = selection.spanned_rows(false, &display_map);
10444
10445                // Avoid re-outdenting a row that has already been outdented by a
10446                // previous selection.
10447                if let Some(last_row) = last_outdent
10448                    && last_row == rows.start
10449                {
10450                    rows.start = rows.start.next_row();
10451                }
10452                let has_multiple_rows = rows.len() > 1;
10453                for row in rows.iter_rows() {
10454                    let indent_size = snapshot.indent_size_for_line(row);
10455                    if indent_size.len > 0 {
10456                        let deletion_len = match indent_size.kind {
10457                            IndentKind::Space => {
10458                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10459                                if columns_to_prev_tab_stop == 0 {
10460                                    tab_size
10461                                } else {
10462                                    columns_to_prev_tab_stop
10463                                }
10464                            }
10465                            IndentKind::Tab => 1,
10466                        };
10467                        let start = if has_multiple_rows
10468                            || deletion_len > selection.start.column
10469                            || indent_size.len < selection.start.column
10470                        {
10471                            0
10472                        } else {
10473                            selection.start.column - deletion_len
10474                        };
10475                        deletion_ranges.push(
10476                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10477                        );
10478                        last_outdent = Some(row);
10479                    }
10480                }
10481            }
10482        }
10483
10484        self.transact(window, cx, |this, window, cx| {
10485            this.buffer.update(cx, |buffer, cx| {
10486                let empty_str: Arc<str> = Arc::default();
10487                buffer.edit(
10488                    deletion_ranges
10489                        .into_iter()
10490                        .map(|range| (range, empty_str.clone())),
10491                    None,
10492                    cx,
10493                );
10494            });
10495            let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
10496            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10497        });
10498    }
10499
10500    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10501        if self.read_only(cx) {
10502            return;
10503        }
10504        if self.mode.is_single_line() {
10505            cx.propagate();
10506            return;
10507        }
10508
10509        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10510        let selections = self
10511            .selections
10512            .all::<usize>(&self.display_snapshot(cx))
10513            .into_iter()
10514            .map(|s| s.range());
10515
10516        self.transact(window, cx, |this, window, cx| {
10517            this.buffer.update(cx, |buffer, cx| {
10518                buffer.autoindent_ranges(selections, cx);
10519            });
10520            let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
10521            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10522        });
10523    }
10524
10525    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10526        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10527        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10528        let selections = self.selections.all::<Point>(&display_map);
10529
10530        let mut new_cursors = Vec::new();
10531        let mut edit_ranges = Vec::new();
10532        let mut selections = selections.iter().peekable();
10533        while let Some(selection) = selections.next() {
10534            let mut rows = selection.spanned_rows(false, &display_map);
10535
10536            // Accumulate contiguous regions of rows that we want to delete.
10537            while let Some(next_selection) = selections.peek() {
10538                let next_rows = next_selection.spanned_rows(false, &display_map);
10539                if next_rows.start <= rows.end {
10540                    rows.end = next_rows.end;
10541                    selections.next().unwrap();
10542                } else {
10543                    break;
10544                }
10545            }
10546
10547            let buffer = display_map.buffer_snapshot();
10548            let mut edit_start = ToOffset::to_offset(&Point::new(rows.start.0, 0), buffer);
10549            let (edit_end, target_row) = if buffer.max_point().row >= rows.end.0 {
10550                // If there's a line after the range, delete the \n from the end of the row range
10551                (
10552                    ToOffset::to_offset(&Point::new(rows.end.0, 0), buffer),
10553                    rows.end,
10554                )
10555            } else {
10556                // If there isn't a line after the range, delete the \n from the line before the
10557                // start of the row range
10558                edit_start = edit_start.saturating_sub(1);
10559                (buffer.len(), rows.start.previous_row())
10560            };
10561
10562            let text_layout_details = self.text_layout_details(window);
10563            let x = display_map.x_for_display_point(
10564                selection.head().to_display_point(&display_map),
10565                &text_layout_details,
10566            );
10567            let row = Point::new(target_row.0, 0)
10568                .to_display_point(&display_map)
10569                .row();
10570            let column = display_map.display_column_for_x(row, x, &text_layout_details);
10571
10572            new_cursors.push((
10573                selection.id,
10574                buffer.anchor_after(DisplayPoint::new(row, column).to_point(&display_map)),
10575                SelectionGoal::None,
10576            ));
10577            edit_ranges.push(edit_start..edit_end);
10578        }
10579
10580        self.transact(window, cx, |this, window, cx| {
10581            let buffer = this.buffer.update(cx, |buffer, cx| {
10582                let empty_str: Arc<str> = Arc::default();
10583                buffer.edit(
10584                    edit_ranges
10585                        .into_iter()
10586                        .map(|range| (range, empty_str.clone())),
10587                    None,
10588                    cx,
10589                );
10590                buffer.snapshot(cx)
10591            });
10592            let new_selections = new_cursors
10593                .into_iter()
10594                .map(|(id, cursor, goal)| {
10595                    let cursor = cursor.to_point(&buffer);
10596                    Selection {
10597                        id,
10598                        start: cursor,
10599                        end: cursor,
10600                        reversed: false,
10601                        goal,
10602                    }
10603                })
10604                .collect();
10605
10606            this.change_selections(Default::default(), window, cx, |s| {
10607                s.select(new_selections);
10608            });
10609        });
10610    }
10611
10612    pub fn join_lines_impl(
10613        &mut self,
10614        insert_whitespace: bool,
10615        window: &mut Window,
10616        cx: &mut Context<Self>,
10617    ) {
10618        if self.read_only(cx) {
10619            return;
10620        }
10621        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10622        for selection in self.selections.all::<Point>(&self.display_snapshot(cx)) {
10623            let start = MultiBufferRow(selection.start.row);
10624            // Treat single line selections as if they include the next line. Otherwise this action
10625            // would do nothing for single line selections individual cursors.
10626            let end = if selection.start.row == selection.end.row {
10627                MultiBufferRow(selection.start.row + 1)
10628            } else {
10629                MultiBufferRow(selection.end.row)
10630            };
10631
10632            if let Some(last_row_range) = row_ranges.last_mut()
10633                && start <= last_row_range.end
10634            {
10635                last_row_range.end = end;
10636                continue;
10637            }
10638            row_ranges.push(start..end);
10639        }
10640
10641        let snapshot = self.buffer.read(cx).snapshot(cx);
10642        let mut cursor_positions = Vec::new();
10643        for row_range in &row_ranges {
10644            let anchor = snapshot.anchor_before(Point::new(
10645                row_range.end.previous_row().0,
10646                snapshot.line_len(row_range.end.previous_row()),
10647            ));
10648            cursor_positions.push(anchor..anchor);
10649        }
10650
10651        self.transact(window, cx, |this, window, cx| {
10652            for row_range in row_ranges.into_iter().rev() {
10653                for row in row_range.iter_rows().rev() {
10654                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10655                    let next_line_row = row.next_row();
10656                    let indent = snapshot.indent_size_for_line(next_line_row);
10657                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10658
10659                    let replace =
10660                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10661                            " "
10662                        } else {
10663                            ""
10664                        };
10665
10666                    this.buffer.update(cx, |buffer, cx| {
10667                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10668                    });
10669                }
10670            }
10671
10672            this.change_selections(Default::default(), window, cx, |s| {
10673                s.select_anchor_ranges(cursor_positions)
10674            });
10675        });
10676    }
10677
10678    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10679        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10680        self.join_lines_impl(true, window, cx);
10681    }
10682
10683    pub fn sort_lines_case_sensitive(
10684        &mut self,
10685        _: &SortLinesCaseSensitive,
10686        window: &mut Window,
10687        cx: &mut Context<Self>,
10688    ) {
10689        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10690    }
10691
10692    pub fn sort_lines_by_length(
10693        &mut self,
10694        _: &SortLinesByLength,
10695        window: &mut Window,
10696        cx: &mut Context<Self>,
10697    ) {
10698        self.manipulate_immutable_lines(window, cx, |lines| {
10699            lines.sort_by_key(|&line| line.chars().count())
10700        })
10701    }
10702
10703    pub fn sort_lines_case_insensitive(
10704        &mut self,
10705        _: &SortLinesCaseInsensitive,
10706        window: &mut Window,
10707        cx: &mut Context<Self>,
10708    ) {
10709        self.manipulate_immutable_lines(window, cx, |lines| {
10710            lines.sort_by_key(|line| line.to_lowercase())
10711        })
10712    }
10713
10714    pub fn unique_lines_case_insensitive(
10715        &mut self,
10716        _: &UniqueLinesCaseInsensitive,
10717        window: &mut Window,
10718        cx: &mut Context<Self>,
10719    ) {
10720        self.manipulate_immutable_lines(window, cx, |lines| {
10721            let mut seen = HashSet::default();
10722            lines.retain(|line| seen.insert(line.to_lowercase()));
10723        })
10724    }
10725
10726    pub fn unique_lines_case_sensitive(
10727        &mut self,
10728        _: &UniqueLinesCaseSensitive,
10729        window: &mut Window,
10730        cx: &mut Context<Self>,
10731    ) {
10732        self.manipulate_immutable_lines(window, cx, |lines| {
10733            let mut seen = HashSet::default();
10734            lines.retain(|line| seen.insert(*line));
10735        })
10736    }
10737
10738    fn enable_wrap_selections_in_tag(&self, cx: &App) -> bool {
10739        let snapshot = self.buffer.read(cx).snapshot(cx);
10740        for selection in self.selections.disjoint_anchors_arc().iter() {
10741            if snapshot
10742                .language_at(selection.start)
10743                .and_then(|lang| lang.config().wrap_characters.as_ref())
10744                .is_some()
10745            {
10746                return true;
10747            }
10748        }
10749        false
10750    }
10751
10752    fn wrap_selections_in_tag(
10753        &mut self,
10754        _: &WrapSelectionsInTag,
10755        window: &mut Window,
10756        cx: &mut Context<Self>,
10757    ) {
10758        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10759
10760        let snapshot = self.buffer.read(cx).snapshot(cx);
10761
10762        let mut edits = Vec::new();
10763        let mut boundaries = Vec::new();
10764
10765        for selection in self
10766            .selections
10767            .all::<Point>(&self.display_snapshot(cx))
10768            .iter()
10769        {
10770            let Some(wrap_config) = snapshot
10771                .language_at(selection.start)
10772                .and_then(|lang| lang.config().wrap_characters.clone())
10773            else {
10774                continue;
10775            };
10776
10777            let open_tag = format!("{}{}", wrap_config.start_prefix, wrap_config.start_suffix);
10778            let close_tag = format!("{}{}", wrap_config.end_prefix, wrap_config.end_suffix);
10779
10780            let start_before = snapshot.anchor_before(selection.start);
10781            let end_after = snapshot.anchor_after(selection.end);
10782
10783            edits.push((start_before..start_before, open_tag));
10784            edits.push((end_after..end_after, close_tag));
10785
10786            boundaries.push((
10787                start_before,
10788                end_after,
10789                wrap_config.start_prefix.len(),
10790                wrap_config.end_suffix.len(),
10791            ));
10792        }
10793
10794        if edits.is_empty() {
10795            return;
10796        }
10797
10798        self.transact(window, cx, |this, window, cx| {
10799            let buffer = this.buffer.update(cx, |buffer, cx| {
10800                buffer.edit(edits, None, cx);
10801                buffer.snapshot(cx)
10802            });
10803
10804            let mut new_selections = Vec::with_capacity(boundaries.len() * 2);
10805            for (start_before, end_after, start_prefix_len, end_suffix_len) in
10806                boundaries.into_iter()
10807            {
10808                let open_offset = start_before.to_offset(&buffer) + start_prefix_len;
10809                let close_offset = end_after.to_offset(&buffer).saturating_sub(end_suffix_len);
10810                new_selections.push(open_offset..open_offset);
10811                new_selections.push(close_offset..close_offset);
10812            }
10813
10814            this.change_selections(Default::default(), window, cx, |s| {
10815                s.select_ranges(new_selections);
10816            });
10817
10818            this.request_autoscroll(Autoscroll::fit(), cx);
10819        });
10820    }
10821
10822    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10823        let Some(project) = self.project.clone() else {
10824            return;
10825        };
10826        self.reload(project, window, cx)
10827            .detach_and_notify_err(window, cx);
10828    }
10829
10830    pub fn restore_file(
10831        &mut self,
10832        _: &::git::RestoreFile,
10833        window: &mut Window,
10834        cx: &mut Context<Self>,
10835    ) {
10836        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10837        let mut buffer_ids = HashSet::default();
10838        let snapshot = self.buffer().read(cx).snapshot(cx);
10839        for selection in self.selections.all::<usize>(&self.display_snapshot(cx)) {
10840            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10841        }
10842
10843        let buffer = self.buffer().read(cx);
10844        let ranges = buffer_ids
10845            .into_iter()
10846            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10847            .collect::<Vec<_>>();
10848
10849        self.restore_hunks_in_ranges(ranges, window, cx);
10850    }
10851
10852    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10853        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10854        let selections = self
10855            .selections
10856            .all(&self.display_snapshot(cx))
10857            .into_iter()
10858            .map(|s| s.range())
10859            .collect();
10860        self.restore_hunks_in_ranges(selections, window, cx);
10861    }
10862
10863    pub fn restore_hunks_in_ranges(
10864        &mut self,
10865        ranges: Vec<Range<Point>>,
10866        window: &mut Window,
10867        cx: &mut Context<Editor>,
10868    ) {
10869        let mut revert_changes = HashMap::default();
10870        let chunk_by = self
10871            .snapshot(window, cx)
10872            .hunks_for_ranges(ranges)
10873            .into_iter()
10874            .chunk_by(|hunk| hunk.buffer_id);
10875        for (buffer_id, hunks) in &chunk_by {
10876            let hunks = hunks.collect::<Vec<_>>();
10877            for hunk in &hunks {
10878                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10879            }
10880            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10881        }
10882        drop(chunk_by);
10883        if !revert_changes.is_empty() {
10884            self.transact(window, cx, |editor, window, cx| {
10885                editor.restore(revert_changes, window, cx);
10886            });
10887        }
10888    }
10889
10890    pub fn open_active_item_in_terminal(
10891        &mut self,
10892        _: &OpenInTerminal,
10893        window: &mut Window,
10894        cx: &mut Context<Self>,
10895    ) {
10896        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10897            let project_path = buffer.read(cx).project_path(cx)?;
10898            let project = self.project()?.read(cx);
10899            let entry = project.entry_for_path(&project_path, cx)?;
10900            let parent = match &entry.canonical_path {
10901                Some(canonical_path) => canonical_path.to_path_buf(),
10902                None => project.absolute_path(&project_path, cx)?,
10903            }
10904            .parent()?
10905            .to_path_buf();
10906            Some(parent)
10907        }) {
10908            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10909        }
10910    }
10911
10912    fn set_breakpoint_context_menu(
10913        &mut self,
10914        display_row: DisplayRow,
10915        position: Option<Anchor>,
10916        clicked_point: gpui::Point<Pixels>,
10917        window: &mut Window,
10918        cx: &mut Context<Self>,
10919    ) {
10920        let source = self
10921            .buffer
10922            .read(cx)
10923            .snapshot(cx)
10924            .anchor_before(Point::new(display_row.0, 0u32));
10925
10926        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10927
10928        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10929            self,
10930            source,
10931            clicked_point,
10932            context_menu,
10933            window,
10934            cx,
10935        );
10936    }
10937
10938    fn add_edit_breakpoint_block(
10939        &mut self,
10940        anchor: Anchor,
10941        breakpoint: &Breakpoint,
10942        edit_action: BreakpointPromptEditAction,
10943        window: &mut Window,
10944        cx: &mut Context<Self>,
10945    ) {
10946        let weak_editor = cx.weak_entity();
10947        let bp_prompt = cx.new(|cx| {
10948            BreakpointPromptEditor::new(
10949                weak_editor,
10950                anchor,
10951                breakpoint.clone(),
10952                edit_action,
10953                window,
10954                cx,
10955            )
10956        });
10957
10958        let height = bp_prompt.update(cx, |this, cx| {
10959            this.prompt
10960                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10961        });
10962        let cloned_prompt = bp_prompt.clone();
10963        let blocks = vec![BlockProperties {
10964            style: BlockStyle::Sticky,
10965            placement: BlockPlacement::Above(anchor),
10966            height: Some(height),
10967            render: Arc::new(move |cx| {
10968                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10969                cloned_prompt.clone().into_any_element()
10970            }),
10971            priority: 0,
10972        }];
10973
10974        let focus_handle = bp_prompt.focus_handle(cx);
10975        window.focus(&focus_handle);
10976
10977        let block_ids = self.insert_blocks(blocks, None, cx);
10978        bp_prompt.update(cx, |prompt, _| {
10979            prompt.add_block_ids(block_ids);
10980        });
10981    }
10982
10983    pub(crate) fn breakpoint_at_row(
10984        &self,
10985        row: u32,
10986        window: &mut Window,
10987        cx: &mut Context<Self>,
10988    ) -> Option<(Anchor, Breakpoint)> {
10989        let snapshot = self.snapshot(window, cx);
10990        let breakpoint_position = snapshot.buffer_snapshot().anchor_before(Point::new(row, 0));
10991
10992        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10993    }
10994
10995    pub(crate) fn breakpoint_at_anchor(
10996        &self,
10997        breakpoint_position: Anchor,
10998        snapshot: &EditorSnapshot,
10999        cx: &mut Context<Self>,
11000    ) -> Option<(Anchor, Breakpoint)> {
11001        let buffer = self
11002            .buffer
11003            .read(cx)
11004            .buffer_for_anchor(breakpoint_position, cx)?;
11005
11006        let enclosing_excerpt = breakpoint_position.excerpt_id;
11007        let buffer_snapshot = buffer.read(cx).snapshot();
11008
11009        let row = buffer_snapshot
11010            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
11011            .row;
11012
11013        let line_len = snapshot.buffer_snapshot().line_len(MultiBufferRow(row));
11014        let anchor_end = snapshot
11015            .buffer_snapshot()
11016            .anchor_after(Point::new(row, line_len));
11017
11018        self.breakpoint_store
11019            .as_ref()?
11020            .read_with(cx, |breakpoint_store, cx| {
11021                breakpoint_store
11022                    .breakpoints(
11023                        &buffer,
11024                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
11025                        &buffer_snapshot,
11026                        cx,
11027                    )
11028                    .next()
11029                    .and_then(|(bp, _)| {
11030                        let breakpoint_row = buffer_snapshot
11031                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
11032                            .row;
11033
11034                        if breakpoint_row == row {
11035                            snapshot
11036                                .buffer_snapshot()
11037                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
11038                                .map(|position| (position, bp.bp.clone()))
11039                        } else {
11040                            None
11041                        }
11042                    })
11043            })
11044    }
11045
11046    pub fn edit_log_breakpoint(
11047        &mut self,
11048        _: &EditLogBreakpoint,
11049        window: &mut Window,
11050        cx: &mut Context<Self>,
11051    ) {
11052        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11053            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
11054                message: None,
11055                state: BreakpointState::Enabled,
11056                condition: None,
11057                hit_condition: None,
11058            });
11059
11060            self.add_edit_breakpoint_block(
11061                anchor,
11062                &breakpoint,
11063                BreakpointPromptEditAction::Log,
11064                window,
11065                cx,
11066            );
11067        }
11068    }
11069
11070    fn breakpoints_at_cursors(
11071        &self,
11072        window: &mut Window,
11073        cx: &mut Context<Self>,
11074    ) -> Vec<(Anchor, Option<Breakpoint>)> {
11075        let snapshot = self.snapshot(window, cx);
11076        let cursors = self
11077            .selections
11078            .disjoint_anchors_arc()
11079            .iter()
11080            .map(|selection| {
11081                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot());
11082
11083                let breakpoint_position = self
11084                    .breakpoint_at_row(cursor_position.row, window, cx)
11085                    .map(|bp| bp.0)
11086                    .unwrap_or_else(|| {
11087                        snapshot
11088                            .display_snapshot
11089                            .buffer_snapshot()
11090                            .anchor_after(Point::new(cursor_position.row, 0))
11091                    });
11092
11093                let breakpoint = self
11094                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11095                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
11096
11097                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
11098            })
11099            // There might be multiple cursors on the same line; all of them should have the same anchors though as their breakpoints positions, which makes it possible to sort and dedup the list.
11100            .collect::<HashMap<Anchor, _>>();
11101
11102        cursors.into_iter().collect()
11103    }
11104
11105    pub fn enable_breakpoint(
11106        &mut self,
11107        _: &crate::actions::EnableBreakpoint,
11108        window: &mut Window,
11109        cx: &mut Context<Self>,
11110    ) {
11111        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11112            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
11113                continue;
11114            };
11115            self.edit_breakpoint_at_anchor(
11116                anchor,
11117                breakpoint,
11118                BreakpointEditAction::InvertState,
11119                cx,
11120            );
11121        }
11122    }
11123
11124    pub fn disable_breakpoint(
11125        &mut self,
11126        _: &crate::actions::DisableBreakpoint,
11127        window: &mut Window,
11128        cx: &mut Context<Self>,
11129    ) {
11130        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11131            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
11132                continue;
11133            };
11134            self.edit_breakpoint_at_anchor(
11135                anchor,
11136                breakpoint,
11137                BreakpointEditAction::InvertState,
11138                cx,
11139            );
11140        }
11141    }
11142
11143    pub fn toggle_breakpoint(
11144        &mut self,
11145        _: &crate::actions::ToggleBreakpoint,
11146        window: &mut Window,
11147        cx: &mut Context<Self>,
11148    ) {
11149        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11150            if let Some(breakpoint) = breakpoint {
11151                self.edit_breakpoint_at_anchor(
11152                    anchor,
11153                    breakpoint,
11154                    BreakpointEditAction::Toggle,
11155                    cx,
11156                );
11157            } else {
11158                self.edit_breakpoint_at_anchor(
11159                    anchor,
11160                    Breakpoint::new_standard(),
11161                    BreakpointEditAction::Toggle,
11162                    cx,
11163                );
11164            }
11165        }
11166    }
11167
11168    pub fn edit_breakpoint_at_anchor(
11169        &mut self,
11170        breakpoint_position: Anchor,
11171        breakpoint: Breakpoint,
11172        edit_action: BreakpointEditAction,
11173        cx: &mut Context<Self>,
11174    ) {
11175        let Some(breakpoint_store) = &self.breakpoint_store else {
11176            return;
11177        };
11178
11179        let Some(buffer) = self
11180            .buffer
11181            .read(cx)
11182            .buffer_for_anchor(breakpoint_position, cx)
11183        else {
11184            return;
11185        };
11186
11187        breakpoint_store.update(cx, |breakpoint_store, cx| {
11188            breakpoint_store.toggle_breakpoint(
11189                buffer,
11190                BreakpointWithPosition {
11191                    position: breakpoint_position.text_anchor,
11192                    bp: breakpoint,
11193                },
11194                edit_action,
11195                cx,
11196            );
11197        });
11198
11199        cx.notify();
11200    }
11201
11202    #[cfg(any(test, feature = "test-support"))]
11203    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
11204        self.breakpoint_store.clone()
11205    }
11206
11207    pub fn prepare_restore_change(
11208        &self,
11209        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
11210        hunk: &MultiBufferDiffHunk,
11211        cx: &mut App,
11212    ) -> Option<()> {
11213        if hunk.is_created_file() {
11214            return None;
11215        }
11216        let buffer = self.buffer.read(cx);
11217        let diff = buffer.diff_for(hunk.buffer_id)?;
11218        let buffer = buffer.buffer(hunk.buffer_id)?;
11219        let buffer = buffer.read(cx);
11220        let original_text = diff
11221            .read(cx)
11222            .base_text()
11223            .as_rope()
11224            .slice(hunk.diff_base_byte_range.clone());
11225        let buffer_snapshot = buffer.snapshot();
11226        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
11227        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
11228            probe
11229                .0
11230                .start
11231                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
11232                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
11233        }) {
11234            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
11235            Some(())
11236        } else {
11237            None
11238        }
11239    }
11240
11241    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
11242        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
11243    }
11244
11245    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
11246        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut rand::rng()))
11247    }
11248
11249    fn manipulate_lines<M>(
11250        &mut self,
11251        window: &mut Window,
11252        cx: &mut Context<Self>,
11253        mut manipulate: M,
11254    ) where
11255        M: FnMut(&str) -> LineManipulationResult,
11256    {
11257        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11258
11259        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11260        let buffer = self.buffer.read(cx).snapshot(cx);
11261
11262        let mut edits = Vec::new();
11263
11264        let selections = self.selections.all::<Point>(&display_map);
11265        let mut selections = selections.iter().peekable();
11266        let mut contiguous_row_selections = Vec::new();
11267        let mut new_selections = Vec::new();
11268        let mut added_lines = 0;
11269        let mut removed_lines = 0;
11270
11271        while let Some(selection) = selections.next() {
11272            let (start_row, end_row) = consume_contiguous_rows(
11273                &mut contiguous_row_selections,
11274                selection,
11275                &display_map,
11276                &mut selections,
11277            );
11278
11279            let start_point = Point::new(start_row.0, 0);
11280            let end_point = Point::new(
11281                end_row.previous_row().0,
11282                buffer.line_len(end_row.previous_row()),
11283            );
11284            let text = buffer
11285                .text_for_range(start_point..end_point)
11286                .collect::<String>();
11287
11288            let LineManipulationResult {
11289                new_text,
11290                line_count_before,
11291                line_count_after,
11292            } = manipulate(&text);
11293
11294            edits.push((start_point..end_point, new_text));
11295
11296            // Selections must change based on added and removed line count
11297            let start_row =
11298                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
11299            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
11300            new_selections.push(Selection {
11301                id: selection.id,
11302                start: start_row,
11303                end: end_row,
11304                goal: SelectionGoal::None,
11305                reversed: selection.reversed,
11306            });
11307
11308            if line_count_after > line_count_before {
11309                added_lines += line_count_after - line_count_before;
11310            } else if line_count_before > line_count_after {
11311                removed_lines += line_count_before - line_count_after;
11312            }
11313        }
11314
11315        self.transact(window, cx, |this, window, cx| {
11316            let buffer = this.buffer.update(cx, |buffer, cx| {
11317                buffer.edit(edits, None, cx);
11318                buffer.snapshot(cx)
11319            });
11320
11321            // Recalculate offsets on newly edited buffer
11322            let new_selections = new_selections
11323                .iter()
11324                .map(|s| {
11325                    let start_point = Point::new(s.start.0, 0);
11326                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
11327                    Selection {
11328                        id: s.id,
11329                        start: buffer.point_to_offset(start_point),
11330                        end: buffer.point_to_offset(end_point),
11331                        goal: s.goal,
11332                        reversed: s.reversed,
11333                    }
11334                })
11335                .collect();
11336
11337            this.change_selections(Default::default(), window, cx, |s| {
11338                s.select(new_selections);
11339            });
11340
11341            this.request_autoscroll(Autoscroll::fit(), cx);
11342        });
11343    }
11344
11345    fn manipulate_immutable_lines<Fn>(
11346        &mut self,
11347        window: &mut Window,
11348        cx: &mut Context<Self>,
11349        mut callback: Fn,
11350    ) where
11351        Fn: FnMut(&mut Vec<&str>),
11352    {
11353        self.manipulate_lines(window, cx, |text| {
11354            let mut lines: Vec<&str> = text.split('\n').collect();
11355            let line_count_before = lines.len();
11356
11357            callback(&mut lines);
11358
11359            LineManipulationResult {
11360                new_text: lines.join("\n"),
11361                line_count_before,
11362                line_count_after: lines.len(),
11363            }
11364        });
11365    }
11366
11367    fn manipulate_mutable_lines<Fn>(
11368        &mut self,
11369        window: &mut Window,
11370        cx: &mut Context<Self>,
11371        mut callback: Fn,
11372    ) where
11373        Fn: FnMut(&mut Vec<Cow<'_, str>>),
11374    {
11375        self.manipulate_lines(window, cx, |text| {
11376            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
11377            let line_count_before = lines.len();
11378
11379            callback(&mut lines);
11380
11381            LineManipulationResult {
11382                new_text: lines.join("\n"),
11383                line_count_before,
11384                line_count_after: lines.len(),
11385            }
11386        });
11387    }
11388
11389    pub fn convert_indentation_to_spaces(
11390        &mut self,
11391        _: &ConvertIndentationToSpaces,
11392        window: &mut Window,
11393        cx: &mut Context<Self>,
11394    ) {
11395        let settings = self.buffer.read(cx).language_settings(cx);
11396        let tab_size = settings.tab_size.get() as usize;
11397
11398        self.manipulate_mutable_lines(window, cx, |lines| {
11399            // Allocates a reasonably sized scratch buffer once for the whole loop
11400            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11401            // Avoids recomputing spaces that could be inserted many times
11402            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11403                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11404                .collect();
11405
11406            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11407                let mut chars = line.as_ref().chars();
11408                let mut col = 0;
11409                let mut changed = false;
11410
11411                for ch in chars.by_ref() {
11412                    match ch {
11413                        ' ' => {
11414                            reindented_line.push(' ');
11415                            col += 1;
11416                        }
11417                        '\t' => {
11418                            // \t are converted to spaces depending on the current column
11419                            let spaces_len = tab_size - (col % tab_size);
11420                            reindented_line.extend(&space_cache[spaces_len - 1]);
11421                            col += spaces_len;
11422                            changed = true;
11423                        }
11424                        _ => {
11425                            // If we dont append before break, the character is consumed
11426                            reindented_line.push(ch);
11427                            break;
11428                        }
11429                    }
11430                }
11431
11432                if !changed {
11433                    reindented_line.clear();
11434                    continue;
11435                }
11436                // Append the rest of the line and replace old reference with new one
11437                reindented_line.extend(chars);
11438                *line = Cow::Owned(reindented_line.clone());
11439                reindented_line.clear();
11440            }
11441        });
11442    }
11443
11444    pub fn convert_indentation_to_tabs(
11445        &mut self,
11446        _: &ConvertIndentationToTabs,
11447        window: &mut Window,
11448        cx: &mut Context<Self>,
11449    ) {
11450        let settings = self.buffer.read(cx).language_settings(cx);
11451        let tab_size = settings.tab_size.get() as usize;
11452
11453        self.manipulate_mutable_lines(window, cx, |lines| {
11454            // Allocates a reasonably sized buffer once for the whole loop
11455            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11456            // Avoids recomputing spaces that could be inserted many times
11457            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11458                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11459                .collect();
11460
11461            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11462                let mut chars = line.chars();
11463                let mut spaces_count = 0;
11464                let mut first_non_indent_char = None;
11465                let mut changed = false;
11466
11467                for ch in chars.by_ref() {
11468                    match ch {
11469                        ' ' => {
11470                            // Keep track of spaces. Append \t when we reach tab_size
11471                            spaces_count += 1;
11472                            changed = true;
11473                            if spaces_count == tab_size {
11474                                reindented_line.push('\t');
11475                                spaces_count = 0;
11476                            }
11477                        }
11478                        '\t' => {
11479                            reindented_line.push('\t');
11480                            spaces_count = 0;
11481                        }
11482                        _ => {
11483                            // Dont append it yet, we might have remaining spaces
11484                            first_non_indent_char = Some(ch);
11485                            break;
11486                        }
11487                    }
11488                }
11489
11490                if !changed {
11491                    reindented_line.clear();
11492                    continue;
11493                }
11494                // Remaining spaces that didn't make a full tab stop
11495                if spaces_count > 0 {
11496                    reindented_line.extend(&space_cache[spaces_count - 1]);
11497                }
11498                // If we consume an extra character that was not indentation, add it back
11499                if let Some(extra_char) = first_non_indent_char {
11500                    reindented_line.push(extra_char);
11501                }
11502                // Append the rest of the line and replace old reference with new one
11503                reindented_line.extend(chars);
11504                *line = Cow::Owned(reindented_line.clone());
11505                reindented_line.clear();
11506            }
11507        });
11508    }
11509
11510    pub fn convert_to_upper_case(
11511        &mut self,
11512        _: &ConvertToUpperCase,
11513        window: &mut Window,
11514        cx: &mut Context<Self>,
11515    ) {
11516        self.manipulate_text(window, cx, |text| text.to_uppercase())
11517    }
11518
11519    pub fn convert_to_lower_case(
11520        &mut self,
11521        _: &ConvertToLowerCase,
11522        window: &mut Window,
11523        cx: &mut Context<Self>,
11524    ) {
11525        self.manipulate_text(window, cx, |text| text.to_lowercase())
11526    }
11527
11528    pub fn convert_to_title_case(
11529        &mut self,
11530        _: &ConvertToTitleCase,
11531        window: &mut Window,
11532        cx: &mut Context<Self>,
11533    ) {
11534        self.manipulate_text(window, cx, |text| {
11535            text.split('\n')
11536                .map(|line| line.to_case(Case::Title))
11537                .join("\n")
11538        })
11539    }
11540
11541    pub fn convert_to_snake_case(
11542        &mut self,
11543        _: &ConvertToSnakeCase,
11544        window: &mut Window,
11545        cx: &mut Context<Self>,
11546    ) {
11547        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11548    }
11549
11550    pub fn convert_to_kebab_case(
11551        &mut self,
11552        _: &ConvertToKebabCase,
11553        window: &mut Window,
11554        cx: &mut Context<Self>,
11555    ) {
11556        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11557    }
11558
11559    pub fn convert_to_upper_camel_case(
11560        &mut self,
11561        _: &ConvertToUpperCamelCase,
11562        window: &mut Window,
11563        cx: &mut Context<Self>,
11564    ) {
11565        self.manipulate_text(window, cx, |text| {
11566            text.split('\n')
11567                .map(|line| line.to_case(Case::UpperCamel))
11568                .join("\n")
11569        })
11570    }
11571
11572    pub fn convert_to_lower_camel_case(
11573        &mut self,
11574        _: &ConvertToLowerCamelCase,
11575        window: &mut Window,
11576        cx: &mut Context<Self>,
11577    ) {
11578        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11579    }
11580
11581    pub fn convert_to_opposite_case(
11582        &mut self,
11583        _: &ConvertToOppositeCase,
11584        window: &mut Window,
11585        cx: &mut Context<Self>,
11586    ) {
11587        self.manipulate_text(window, cx, |text| {
11588            text.chars()
11589                .fold(String::with_capacity(text.len()), |mut t, c| {
11590                    if c.is_uppercase() {
11591                        t.extend(c.to_lowercase());
11592                    } else {
11593                        t.extend(c.to_uppercase());
11594                    }
11595                    t
11596                })
11597        })
11598    }
11599
11600    pub fn convert_to_sentence_case(
11601        &mut self,
11602        _: &ConvertToSentenceCase,
11603        window: &mut Window,
11604        cx: &mut Context<Self>,
11605    ) {
11606        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
11607    }
11608
11609    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
11610        self.manipulate_text(window, cx, |text| {
11611            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
11612            if has_upper_case_characters {
11613                text.to_lowercase()
11614            } else {
11615                text.to_uppercase()
11616            }
11617        })
11618    }
11619
11620    pub fn convert_to_rot13(
11621        &mut self,
11622        _: &ConvertToRot13,
11623        window: &mut Window,
11624        cx: &mut Context<Self>,
11625    ) {
11626        self.manipulate_text(window, cx, |text| {
11627            text.chars()
11628                .map(|c| match c {
11629                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11630                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11631                    _ => c,
11632                })
11633                .collect()
11634        })
11635    }
11636
11637    pub fn convert_to_rot47(
11638        &mut self,
11639        _: &ConvertToRot47,
11640        window: &mut Window,
11641        cx: &mut Context<Self>,
11642    ) {
11643        self.manipulate_text(window, cx, |text| {
11644            text.chars()
11645                .map(|c| {
11646                    let code_point = c as u32;
11647                    if code_point >= 33 && code_point <= 126 {
11648                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11649                    }
11650                    c
11651                })
11652                .collect()
11653        })
11654    }
11655
11656    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11657    where
11658        Fn: FnMut(&str) -> String,
11659    {
11660        let buffer = self.buffer.read(cx).snapshot(cx);
11661
11662        let mut new_selections = Vec::new();
11663        let mut edits = Vec::new();
11664        let mut selection_adjustment = 0i32;
11665
11666        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
11667            let selection_is_empty = selection.is_empty();
11668
11669            let (start, end) = if selection_is_empty {
11670                let (word_range, _) = buffer.surrounding_word(selection.start, None);
11671                (word_range.start, word_range.end)
11672            } else {
11673                (
11674                    buffer.point_to_offset(selection.start),
11675                    buffer.point_to_offset(selection.end),
11676                )
11677            };
11678
11679            let text = buffer.text_for_range(start..end).collect::<String>();
11680            let old_length = text.len() as i32;
11681            let text = callback(&text);
11682
11683            new_selections.push(Selection {
11684                start: (start as i32 - selection_adjustment) as usize,
11685                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
11686                goal: SelectionGoal::None,
11687                id: selection.id,
11688                reversed: selection.reversed,
11689            });
11690
11691            selection_adjustment += old_length - text.len() as i32;
11692
11693            edits.push((start..end, text));
11694        }
11695
11696        self.transact(window, cx, |this, window, cx| {
11697            this.buffer.update(cx, |buffer, cx| {
11698                buffer.edit(edits, None, cx);
11699            });
11700
11701            this.change_selections(Default::default(), window, cx, |s| {
11702                s.select(new_selections);
11703            });
11704
11705            this.request_autoscroll(Autoscroll::fit(), cx);
11706        });
11707    }
11708
11709    pub fn move_selection_on_drop(
11710        &mut self,
11711        selection: &Selection<Anchor>,
11712        target: DisplayPoint,
11713        is_cut: bool,
11714        window: &mut Window,
11715        cx: &mut Context<Self>,
11716    ) {
11717        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11718        let buffer = display_map.buffer_snapshot();
11719        let mut edits = Vec::new();
11720        let insert_point = display_map
11721            .clip_point(target, Bias::Left)
11722            .to_point(&display_map);
11723        let text = buffer
11724            .text_for_range(selection.start..selection.end)
11725            .collect::<String>();
11726        if is_cut {
11727            edits.push(((selection.start..selection.end), String::new()));
11728        }
11729        let insert_anchor = buffer.anchor_before(insert_point);
11730        edits.push(((insert_anchor..insert_anchor), text));
11731        let last_edit_start = insert_anchor.bias_left(buffer);
11732        let last_edit_end = insert_anchor.bias_right(buffer);
11733        self.transact(window, cx, |this, window, cx| {
11734            this.buffer.update(cx, |buffer, cx| {
11735                buffer.edit(edits, None, cx);
11736            });
11737            this.change_selections(Default::default(), window, cx, |s| {
11738                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11739            });
11740        });
11741    }
11742
11743    pub fn clear_selection_drag_state(&mut self) {
11744        self.selection_drag_state = SelectionDragState::None;
11745    }
11746
11747    pub fn duplicate(
11748        &mut self,
11749        upwards: bool,
11750        whole_lines: bool,
11751        window: &mut Window,
11752        cx: &mut Context<Self>,
11753    ) {
11754        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11755
11756        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11757        let buffer = display_map.buffer_snapshot();
11758        let selections = self.selections.all::<Point>(&display_map);
11759
11760        let mut edits = Vec::new();
11761        let mut selections_iter = selections.iter().peekable();
11762        while let Some(selection) = selections_iter.next() {
11763            let mut rows = selection.spanned_rows(false, &display_map);
11764            // duplicate line-wise
11765            if whole_lines || selection.start == selection.end {
11766                // Avoid duplicating the same lines twice.
11767                while let Some(next_selection) = selections_iter.peek() {
11768                    let next_rows = next_selection.spanned_rows(false, &display_map);
11769                    if next_rows.start < rows.end {
11770                        rows.end = next_rows.end;
11771                        selections_iter.next().unwrap();
11772                    } else {
11773                        break;
11774                    }
11775                }
11776
11777                // Copy the text from the selected row region and splice it either at the start
11778                // or end of the region.
11779                let start = Point::new(rows.start.0, 0);
11780                let end = Point::new(
11781                    rows.end.previous_row().0,
11782                    buffer.line_len(rows.end.previous_row()),
11783                );
11784
11785                let mut text = buffer.text_for_range(start..end).collect::<String>();
11786
11787                let insert_location = if upwards {
11788                    // When duplicating upward, we need to insert before the current line.
11789                    // If we're on the last line and it doesn't end with a newline,
11790                    // we need to add a newline before the duplicated content.
11791                    let needs_leading_newline = rows.end.0 >= buffer.max_point().row
11792                        && buffer.max_point().column > 0
11793                        && !text.ends_with('\n');
11794
11795                    if needs_leading_newline {
11796                        text.insert(0, '\n');
11797                        end
11798                    } else {
11799                        text.push('\n');
11800                        Point::new(rows.end.0, 0)
11801                    }
11802                } else {
11803                    text.push('\n');
11804                    start
11805                };
11806                edits.push((insert_location..insert_location, text));
11807            } else {
11808                // duplicate character-wise
11809                let start = selection.start;
11810                let end = selection.end;
11811                let text = buffer.text_for_range(start..end).collect::<String>();
11812                edits.push((selection.end..selection.end, text));
11813            }
11814        }
11815
11816        self.transact(window, cx, |this, _, cx| {
11817            this.buffer.update(cx, |buffer, cx| {
11818                buffer.edit(edits, None, cx);
11819            });
11820
11821            this.request_autoscroll(Autoscroll::fit(), cx);
11822        });
11823    }
11824
11825    pub fn duplicate_line_up(
11826        &mut self,
11827        _: &DuplicateLineUp,
11828        window: &mut Window,
11829        cx: &mut Context<Self>,
11830    ) {
11831        self.duplicate(true, true, window, cx);
11832    }
11833
11834    pub fn duplicate_line_down(
11835        &mut self,
11836        _: &DuplicateLineDown,
11837        window: &mut Window,
11838        cx: &mut Context<Self>,
11839    ) {
11840        self.duplicate(false, true, window, cx);
11841    }
11842
11843    pub fn duplicate_selection(
11844        &mut self,
11845        _: &DuplicateSelection,
11846        window: &mut Window,
11847        cx: &mut Context<Self>,
11848    ) {
11849        self.duplicate(false, false, window, cx);
11850    }
11851
11852    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11853        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11854        if self.mode.is_single_line() {
11855            cx.propagate();
11856            return;
11857        }
11858
11859        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11860        let buffer = self.buffer.read(cx).snapshot(cx);
11861
11862        let mut edits = Vec::new();
11863        let mut unfold_ranges = Vec::new();
11864        let mut refold_creases = Vec::new();
11865
11866        let selections = self.selections.all::<Point>(&display_map);
11867        let mut selections = selections.iter().peekable();
11868        let mut contiguous_row_selections = Vec::new();
11869        let mut new_selections = Vec::new();
11870
11871        while let Some(selection) = selections.next() {
11872            // Find all the selections that span a contiguous row range
11873            let (start_row, end_row) = consume_contiguous_rows(
11874                &mut contiguous_row_selections,
11875                selection,
11876                &display_map,
11877                &mut selections,
11878            );
11879
11880            // Move the text spanned by the row range to be before the line preceding the row range
11881            if start_row.0 > 0 {
11882                let range_to_move = Point::new(
11883                    start_row.previous_row().0,
11884                    buffer.line_len(start_row.previous_row()),
11885                )
11886                    ..Point::new(
11887                        end_row.previous_row().0,
11888                        buffer.line_len(end_row.previous_row()),
11889                    );
11890                let insertion_point = display_map
11891                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11892                    .0;
11893
11894                // Don't move lines across excerpts
11895                if buffer
11896                    .excerpt_containing(insertion_point..range_to_move.end)
11897                    .is_some()
11898                {
11899                    let text = buffer
11900                        .text_for_range(range_to_move.clone())
11901                        .flat_map(|s| s.chars())
11902                        .skip(1)
11903                        .chain(['\n'])
11904                        .collect::<String>();
11905
11906                    edits.push((
11907                        buffer.anchor_after(range_to_move.start)
11908                            ..buffer.anchor_before(range_to_move.end),
11909                        String::new(),
11910                    ));
11911                    let insertion_anchor = buffer.anchor_after(insertion_point);
11912                    edits.push((insertion_anchor..insertion_anchor, text));
11913
11914                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11915
11916                    // Move selections up
11917                    new_selections.extend(contiguous_row_selections.drain(..).map(
11918                        |mut selection| {
11919                            selection.start.row -= row_delta;
11920                            selection.end.row -= row_delta;
11921                            selection
11922                        },
11923                    ));
11924
11925                    // Move folds up
11926                    unfold_ranges.push(range_to_move.clone());
11927                    for fold in display_map.folds_in_range(
11928                        buffer.anchor_before(range_to_move.start)
11929                            ..buffer.anchor_after(range_to_move.end),
11930                    ) {
11931                        let mut start = fold.range.start.to_point(&buffer);
11932                        let mut end = fold.range.end.to_point(&buffer);
11933                        start.row -= row_delta;
11934                        end.row -= row_delta;
11935                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11936                    }
11937                }
11938            }
11939
11940            // If we didn't move line(s), preserve the existing selections
11941            new_selections.append(&mut contiguous_row_selections);
11942        }
11943
11944        self.transact(window, cx, |this, window, cx| {
11945            this.unfold_ranges(&unfold_ranges, true, true, cx);
11946            this.buffer.update(cx, |buffer, cx| {
11947                for (range, text) in edits {
11948                    buffer.edit([(range, text)], None, cx);
11949                }
11950            });
11951            this.fold_creases(refold_creases, true, window, cx);
11952            this.change_selections(Default::default(), window, cx, |s| {
11953                s.select(new_selections);
11954            })
11955        });
11956    }
11957
11958    pub fn move_line_down(
11959        &mut self,
11960        _: &MoveLineDown,
11961        window: &mut Window,
11962        cx: &mut Context<Self>,
11963    ) {
11964        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11965        if self.mode.is_single_line() {
11966            cx.propagate();
11967            return;
11968        }
11969
11970        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11971        let buffer = self.buffer.read(cx).snapshot(cx);
11972
11973        let mut edits = Vec::new();
11974        let mut unfold_ranges = Vec::new();
11975        let mut refold_creases = Vec::new();
11976
11977        let selections = self.selections.all::<Point>(&display_map);
11978        let mut selections = selections.iter().peekable();
11979        let mut contiguous_row_selections = Vec::new();
11980        let mut new_selections = Vec::new();
11981
11982        while let Some(selection) = selections.next() {
11983            // Find all the selections that span a contiguous row range
11984            let (start_row, end_row) = consume_contiguous_rows(
11985                &mut contiguous_row_selections,
11986                selection,
11987                &display_map,
11988                &mut selections,
11989            );
11990
11991            // Move the text spanned by the row range to be after the last line of the row range
11992            if end_row.0 <= buffer.max_point().row {
11993                let range_to_move =
11994                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11995                let insertion_point = display_map
11996                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11997                    .0;
11998
11999                // Don't move lines across excerpt boundaries
12000                if buffer
12001                    .excerpt_containing(range_to_move.start..insertion_point)
12002                    .is_some()
12003                {
12004                    let mut text = String::from("\n");
12005                    text.extend(buffer.text_for_range(range_to_move.clone()));
12006                    text.pop(); // Drop trailing newline
12007                    edits.push((
12008                        buffer.anchor_after(range_to_move.start)
12009                            ..buffer.anchor_before(range_to_move.end),
12010                        String::new(),
12011                    ));
12012                    let insertion_anchor = buffer.anchor_after(insertion_point);
12013                    edits.push((insertion_anchor..insertion_anchor, text));
12014
12015                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
12016
12017                    // Move selections down
12018                    new_selections.extend(contiguous_row_selections.drain(..).map(
12019                        |mut selection| {
12020                            selection.start.row += row_delta;
12021                            selection.end.row += row_delta;
12022                            selection
12023                        },
12024                    ));
12025
12026                    // Move folds down
12027                    unfold_ranges.push(range_to_move.clone());
12028                    for fold in display_map.folds_in_range(
12029                        buffer.anchor_before(range_to_move.start)
12030                            ..buffer.anchor_after(range_to_move.end),
12031                    ) {
12032                        let mut start = fold.range.start.to_point(&buffer);
12033                        let mut end = fold.range.end.to_point(&buffer);
12034                        start.row += row_delta;
12035                        end.row += row_delta;
12036                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
12037                    }
12038                }
12039            }
12040
12041            // If we didn't move line(s), preserve the existing selections
12042            new_selections.append(&mut contiguous_row_selections);
12043        }
12044
12045        self.transact(window, cx, |this, window, cx| {
12046            this.unfold_ranges(&unfold_ranges, true, true, cx);
12047            this.buffer.update(cx, |buffer, cx| {
12048                for (range, text) in edits {
12049                    buffer.edit([(range, text)], None, cx);
12050                }
12051            });
12052            this.fold_creases(refold_creases, true, window, cx);
12053            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
12054        });
12055    }
12056
12057    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
12058        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12059        let text_layout_details = &self.text_layout_details(window);
12060        self.transact(window, cx, |this, window, cx| {
12061            let edits = this.change_selections(Default::default(), window, cx, |s| {
12062                let mut edits: Vec<(Range<usize>, String)> = Default::default();
12063                s.move_with(|display_map, selection| {
12064                    if !selection.is_empty() {
12065                        return;
12066                    }
12067
12068                    let mut head = selection.head();
12069                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
12070                    if head.column() == display_map.line_len(head.row()) {
12071                        transpose_offset = display_map
12072                            .buffer_snapshot()
12073                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
12074                    }
12075
12076                    if transpose_offset == 0 {
12077                        return;
12078                    }
12079
12080                    *head.column_mut() += 1;
12081                    head = display_map.clip_point(head, Bias::Right);
12082                    let goal = SelectionGoal::HorizontalPosition(
12083                        display_map
12084                            .x_for_display_point(head, text_layout_details)
12085                            .into(),
12086                    );
12087                    selection.collapse_to(head, goal);
12088
12089                    let transpose_start = display_map
12090                        .buffer_snapshot()
12091                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
12092                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
12093                        let transpose_end = display_map
12094                            .buffer_snapshot()
12095                            .clip_offset(transpose_offset + 1, Bias::Right);
12096                        if let Some(ch) = display_map
12097                            .buffer_snapshot()
12098                            .chars_at(transpose_start)
12099                            .next()
12100                        {
12101                            edits.push((transpose_start..transpose_offset, String::new()));
12102                            edits.push((transpose_end..transpose_end, ch.to_string()));
12103                        }
12104                    }
12105                });
12106                edits
12107            });
12108            this.buffer
12109                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12110            let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
12111            this.change_selections(Default::default(), window, cx, |s| {
12112                s.select(selections);
12113            });
12114        });
12115    }
12116
12117    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
12118        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12119        if self.mode.is_single_line() {
12120            cx.propagate();
12121            return;
12122        }
12123
12124        self.rewrap_impl(RewrapOptions::default(), cx)
12125    }
12126
12127    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
12128        let buffer = self.buffer.read(cx).snapshot(cx);
12129        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12130
12131        #[derive(Clone, Debug, PartialEq)]
12132        enum CommentFormat {
12133            /// single line comment, with prefix for line
12134            Line(String),
12135            /// single line within a block comment, with prefix for line
12136            BlockLine(String),
12137            /// a single line of a block comment that includes the initial delimiter
12138            BlockCommentWithStart(BlockCommentConfig),
12139            /// a single line of a block comment that includes the ending delimiter
12140            BlockCommentWithEnd(BlockCommentConfig),
12141        }
12142
12143        // Split selections to respect paragraph, indent, and comment prefix boundaries.
12144        let wrap_ranges = selections.into_iter().flat_map(|selection| {
12145            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
12146                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
12147                .peekable();
12148
12149            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
12150                row
12151            } else {
12152                return Vec::new();
12153            };
12154
12155            let language_settings = buffer.language_settings_at(selection.head(), cx);
12156            let language_scope = buffer.language_scope_at(selection.head());
12157
12158            let indent_and_prefix_for_row =
12159                |row: u32| -> (IndentSize, Option<CommentFormat>, Option<String>) {
12160                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
12161                    let (comment_prefix, rewrap_prefix) = if let Some(language_scope) =
12162                        &language_scope
12163                    {
12164                        let indent_end = Point::new(row, indent.len);
12165                        let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12166                        let line_text_after_indent = buffer
12167                            .text_for_range(indent_end..line_end)
12168                            .collect::<String>();
12169
12170                        let is_within_comment_override = buffer
12171                            .language_scope_at(indent_end)
12172                            .is_some_and(|scope| scope.override_name() == Some("comment"));
12173                        let comment_delimiters = if is_within_comment_override {
12174                            // we are within a comment syntax node, but we don't
12175                            // yet know what kind of comment: block, doc or line
12176                            match (
12177                                language_scope.documentation_comment(),
12178                                language_scope.block_comment(),
12179                            ) {
12180                                (Some(config), _) | (_, Some(config))
12181                                    if buffer.contains_str_at(indent_end, &config.start) =>
12182                                {
12183                                    Some(CommentFormat::BlockCommentWithStart(config.clone()))
12184                                }
12185                                (Some(config), _) | (_, Some(config))
12186                                    if line_text_after_indent.ends_with(config.end.as_ref()) =>
12187                                {
12188                                    Some(CommentFormat::BlockCommentWithEnd(config.clone()))
12189                                }
12190                                (Some(config), _) | (_, Some(config))
12191                                    if buffer.contains_str_at(indent_end, &config.prefix) =>
12192                                {
12193                                    Some(CommentFormat::BlockLine(config.prefix.to_string()))
12194                                }
12195                                (_, _) => language_scope
12196                                    .line_comment_prefixes()
12197                                    .iter()
12198                                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12199                                    .map(|prefix| CommentFormat::Line(prefix.to_string())),
12200                            }
12201                        } else {
12202                            // we not in an overridden comment node, but we may
12203                            // be within a non-overridden line comment node
12204                            language_scope
12205                                .line_comment_prefixes()
12206                                .iter()
12207                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12208                                .map(|prefix| CommentFormat::Line(prefix.to_string()))
12209                        };
12210
12211                        let rewrap_prefix = language_scope
12212                            .rewrap_prefixes()
12213                            .iter()
12214                            .find_map(|prefix_regex| {
12215                                prefix_regex.find(&line_text_after_indent).map(|mat| {
12216                                    if mat.start() == 0 {
12217                                        Some(mat.as_str().to_string())
12218                                    } else {
12219                                        None
12220                                    }
12221                                })
12222                            })
12223                            .flatten();
12224                        (comment_delimiters, rewrap_prefix)
12225                    } else {
12226                        (None, None)
12227                    };
12228                    (indent, comment_prefix, rewrap_prefix)
12229                };
12230
12231            let mut ranges = Vec::new();
12232            let from_empty_selection = selection.is_empty();
12233
12234            let mut current_range_start = first_row;
12235            let mut prev_row = first_row;
12236            let (
12237                mut current_range_indent,
12238                mut current_range_comment_delimiters,
12239                mut current_range_rewrap_prefix,
12240            ) = indent_and_prefix_for_row(first_row);
12241
12242            for row in non_blank_rows_iter.skip(1) {
12243                let has_paragraph_break = row > prev_row + 1;
12244
12245                let (row_indent, row_comment_delimiters, row_rewrap_prefix) =
12246                    indent_and_prefix_for_row(row);
12247
12248                let has_indent_change = row_indent != current_range_indent;
12249                let has_comment_change = row_comment_delimiters != current_range_comment_delimiters;
12250
12251                let has_boundary_change = has_comment_change
12252                    || row_rewrap_prefix.is_some()
12253                    || (has_indent_change && current_range_comment_delimiters.is_some());
12254
12255                if has_paragraph_break || has_boundary_change {
12256                    ranges.push((
12257                        language_settings.clone(),
12258                        Point::new(current_range_start, 0)
12259                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12260                        current_range_indent,
12261                        current_range_comment_delimiters.clone(),
12262                        current_range_rewrap_prefix.clone(),
12263                        from_empty_selection,
12264                    ));
12265                    current_range_start = row;
12266                    current_range_indent = row_indent;
12267                    current_range_comment_delimiters = row_comment_delimiters;
12268                    current_range_rewrap_prefix = row_rewrap_prefix;
12269                }
12270                prev_row = row;
12271            }
12272
12273            ranges.push((
12274                language_settings.clone(),
12275                Point::new(current_range_start, 0)
12276                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12277                current_range_indent,
12278                current_range_comment_delimiters,
12279                current_range_rewrap_prefix,
12280                from_empty_selection,
12281            ));
12282
12283            ranges
12284        });
12285
12286        let mut edits = Vec::new();
12287        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
12288
12289        for (
12290            language_settings,
12291            wrap_range,
12292            mut indent_size,
12293            comment_prefix,
12294            rewrap_prefix,
12295            from_empty_selection,
12296        ) in wrap_ranges
12297        {
12298            let mut start_row = wrap_range.start.row;
12299            let mut end_row = wrap_range.end.row;
12300
12301            // Skip selections that overlap with a range that has already been rewrapped.
12302            let selection_range = start_row..end_row;
12303            if rewrapped_row_ranges
12304                .iter()
12305                .any(|range| range.overlaps(&selection_range))
12306            {
12307                continue;
12308            }
12309
12310            let tab_size = language_settings.tab_size;
12311
12312            let (line_prefix, inside_comment) = match &comment_prefix {
12313                Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
12314                    (Some(prefix.as_str()), true)
12315                }
12316                Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig { prefix, .. })) => {
12317                    (Some(prefix.as_ref()), true)
12318                }
12319                Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12320                    start: _,
12321                    end: _,
12322                    prefix,
12323                    tab_size,
12324                })) => {
12325                    indent_size.len += tab_size;
12326                    (Some(prefix.as_ref()), true)
12327                }
12328                None => (None, false),
12329            };
12330            let indent_prefix = indent_size.chars().collect::<String>();
12331            let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
12332
12333            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
12334                RewrapBehavior::InComments => inside_comment,
12335                RewrapBehavior::InSelections => !wrap_range.is_empty(),
12336                RewrapBehavior::Anywhere => true,
12337            };
12338
12339            let should_rewrap = options.override_language_settings
12340                || allow_rewrap_based_on_language
12341                || self.hard_wrap.is_some();
12342            if !should_rewrap {
12343                continue;
12344            }
12345
12346            if from_empty_selection {
12347                'expand_upwards: while start_row > 0 {
12348                    let prev_row = start_row - 1;
12349                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
12350                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
12351                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
12352                    {
12353                        start_row = prev_row;
12354                    } else {
12355                        break 'expand_upwards;
12356                    }
12357                }
12358
12359                'expand_downwards: while end_row < buffer.max_point().row {
12360                    let next_row = end_row + 1;
12361                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
12362                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
12363                        && !buffer.is_line_blank(MultiBufferRow(next_row))
12364                    {
12365                        end_row = next_row;
12366                    } else {
12367                        break 'expand_downwards;
12368                    }
12369                }
12370            }
12371
12372            let start = Point::new(start_row, 0);
12373            let start_offset = ToOffset::to_offset(&start, &buffer);
12374            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
12375            let selection_text = buffer.text_for_range(start..end).collect::<String>();
12376            let mut first_line_delimiter = None;
12377            let mut last_line_delimiter = None;
12378            let Some(lines_without_prefixes) = selection_text
12379                .lines()
12380                .enumerate()
12381                .map(|(ix, line)| {
12382                    let line_trimmed = line.trim_start();
12383                    if rewrap_prefix.is_some() && ix > 0 {
12384                        Ok(line_trimmed)
12385                    } else if let Some(
12386                        CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12387                            start,
12388                            prefix,
12389                            end,
12390                            tab_size,
12391                        })
12392                        | CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
12393                            start,
12394                            prefix,
12395                            end,
12396                            tab_size,
12397                        }),
12398                    ) = &comment_prefix
12399                    {
12400                        let line_trimmed = line_trimmed
12401                            .strip_prefix(start.as_ref())
12402                            .map(|s| {
12403                                let mut indent_size = indent_size;
12404                                indent_size.len -= tab_size;
12405                                let indent_prefix: String = indent_size.chars().collect();
12406                                first_line_delimiter = Some((indent_prefix, start));
12407                                s.trim_start()
12408                            })
12409                            .unwrap_or(line_trimmed);
12410                        let line_trimmed = line_trimmed
12411                            .strip_suffix(end.as_ref())
12412                            .map(|s| {
12413                                last_line_delimiter = Some(end);
12414                                s.trim_end()
12415                            })
12416                            .unwrap_or(line_trimmed);
12417                        let line_trimmed = line_trimmed
12418                            .strip_prefix(prefix.as_ref())
12419                            .unwrap_or(line_trimmed);
12420                        Ok(line_trimmed)
12421                    } else if let Some(CommentFormat::BlockLine(prefix)) = &comment_prefix {
12422                        line_trimmed.strip_prefix(prefix).with_context(|| {
12423                            format!("line did not start with prefix {prefix:?}: {line:?}")
12424                        })
12425                    } else {
12426                        line_trimmed
12427                            .strip_prefix(&line_prefix.trim_start())
12428                            .with_context(|| {
12429                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
12430                            })
12431                    }
12432                })
12433                .collect::<Result<Vec<_>, _>>()
12434                .log_err()
12435            else {
12436                continue;
12437            };
12438
12439            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
12440                buffer
12441                    .language_settings_at(Point::new(start_row, 0), cx)
12442                    .preferred_line_length as usize
12443            });
12444
12445            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
12446                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
12447            } else {
12448                line_prefix.clone()
12449            };
12450
12451            let wrapped_text = {
12452                let mut wrapped_text = wrap_with_prefix(
12453                    line_prefix,
12454                    subsequent_lines_prefix,
12455                    lines_without_prefixes.join("\n"),
12456                    wrap_column,
12457                    tab_size,
12458                    options.preserve_existing_whitespace,
12459                );
12460
12461                if let Some((indent, delimiter)) = first_line_delimiter {
12462                    wrapped_text = format!("{indent}{delimiter}\n{wrapped_text}");
12463                }
12464                if let Some(last_line) = last_line_delimiter {
12465                    wrapped_text = format!("{wrapped_text}\n{indent_prefix}{last_line}");
12466                }
12467
12468                wrapped_text
12469            };
12470
12471            // TODO: should always use char-based diff while still supporting cursor behavior that
12472            // matches vim.
12473            let mut diff_options = DiffOptions::default();
12474            if options.override_language_settings {
12475                diff_options.max_word_diff_len = 0;
12476                diff_options.max_word_diff_line_count = 0;
12477            } else {
12478                diff_options.max_word_diff_len = usize::MAX;
12479                diff_options.max_word_diff_line_count = usize::MAX;
12480            }
12481
12482            for (old_range, new_text) in
12483                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
12484            {
12485                let edit_start = buffer.anchor_after(start_offset + old_range.start);
12486                let edit_end = buffer.anchor_after(start_offset + old_range.end);
12487                edits.push((edit_start..edit_end, new_text));
12488            }
12489
12490            rewrapped_row_ranges.push(start_row..=end_row);
12491        }
12492
12493        self.buffer
12494            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12495    }
12496
12497    pub fn cut_common(
12498        &mut self,
12499        cut_no_selection_line: bool,
12500        window: &mut Window,
12501        cx: &mut Context<Self>,
12502    ) -> ClipboardItem {
12503        let mut text = String::new();
12504        let buffer = self.buffer.read(cx).snapshot(cx);
12505        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12506        let mut clipboard_selections = Vec::with_capacity(selections.len());
12507        {
12508            let max_point = buffer.max_point();
12509            let mut is_first = true;
12510            for selection in &mut selections {
12511                let is_entire_line =
12512                    (selection.is_empty() && cut_no_selection_line) || self.selections.line_mode();
12513                if is_entire_line {
12514                    selection.start = Point::new(selection.start.row, 0);
12515                    if !selection.is_empty() && selection.end.column == 0 {
12516                        selection.end = cmp::min(max_point, selection.end);
12517                    } else {
12518                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
12519                    }
12520                    selection.goal = SelectionGoal::None;
12521                }
12522                if is_first {
12523                    is_first = false;
12524                } else {
12525                    text += "\n";
12526                }
12527                let mut len = 0;
12528                for chunk in buffer.text_for_range(selection.start..selection.end) {
12529                    text.push_str(chunk);
12530                    len += chunk.len();
12531                }
12532                clipboard_selections.push(ClipboardSelection {
12533                    len,
12534                    is_entire_line,
12535                    first_line_indent: buffer
12536                        .indent_size_for_line(MultiBufferRow(selection.start.row))
12537                        .len,
12538                });
12539            }
12540        }
12541
12542        self.transact(window, cx, |this, window, cx| {
12543            this.change_selections(Default::default(), window, cx, |s| {
12544                s.select(selections);
12545            });
12546            this.insert("", window, cx);
12547        });
12548        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
12549    }
12550
12551    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
12552        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12553        let item = self.cut_common(true, window, cx);
12554        cx.write_to_clipboard(item);
12555    }
12556
12557    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
12558        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12559        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12560            s.move_with(|snapshot, sel| {
12561                if sel.is_empty() {
12562                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()));
12563                }
12564                if sel.is_empty() {
12565                    sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
12566                }
12567            });
12568        });
12569        let item = self.cut_common(false, window, cx);
12570        cx.set_global(KillRing(item))
12571    }
12572
12573    pub fn kill_ring_yank(
12574        &mut self,
12575        _: &KillRingYank,
12576        window: &mut Window,
12577        cx: &mut Context<Self>,
12578    ) {
12579        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12580        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
12581            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
12582                (kill_ring.text().to_string(), kill_ring.metadata_json())
12583            } else {
12584                return;
12585            }
12586        } else {
12587            return;
12588        };
12589        self.do_paste(&text, metadata, false, window, cx);
12590    }
12591
12592    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
12593        self.do_copy(true, cx);
12594    }
12595
12596    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
12597        self.do_copy(false, cx);
12598    }
12599
12600    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
12601        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12602        let buffer = self.buffer.read(cx).read(cx);
12603        let mut text = String::new();
12604
12605        let mut clipboard_selections = Vec::with_capacity(selections.len());
12606        {
12607            let max_point = buffer.max_point();
12608            let mut is_first = true;
12609            for selection in &selections {
12610                let mut start = selection.start;
12611                let mut end = selection.end;
12612                let is_entire_line = selection.is_empty() || self.selections.line_mode();
12613                let mut add_trailing_newline = false;
12614                if is_entire_line {
12615                    start = Point::new(start.row, 0);
12616                    let next_line_start = Point::new(end.row + 1, 0);
12617                    if next_line_start <= max_point {
12618                        end = next_line_start;
12619                    } else {
12620                        // We're on the last line without a trailing newline.
12621                        // Copy to the end of the line and add a newline afterwards.
12622                        end = Point::new(end.row, buffer.line_len(MultiBufferRow(end.row)));
12623                        add_trailing_newline = true;
12624                    }
12625                }
12626
12627                let mut trimmed_selections = Vec::new();
12628                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
12629                    let row = MultiBufferRow(start.row);
12630                    let first_indent = buffer.indent_size_for_line(row);
12631                    if first_indent.len == 0 || start.column > first_indent.len {
12632                        trimmed_selections.push(start..end);
12633                    } else {
12634                        trimmed_selections.push(
12635                            Point::new(row.0, first_indent.len)
12636                                ..Point::new(row.0, buffer.line_len(row)),
12637                        );
12638                        for row in start.row + 1..=end.row {
12639                            let mut line_len = buffer.line_len(MultiBufferRow(row));
12640                            if row == end.row {
12641                                line_len = end.column;
12642                            }
12643                            if line_len == 0 {
12644                                trimmed_selections
12645                                    .push(Point::new(row, 0)..Point::new(row, line_len));
12646                                continue;
12647                            }
12648                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
12649                            if row_indent_size.len >= first_indent.len {
12650                                trimmed_selections.push(
12651                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
12652                                );
12653                            } else {
12654                                trimmed_selections.clear();
12655                                trimmed_selections.push(start..end);
12656                                break;
12657                            }
12658                        }
12659                    }
12660                } else {
12661                    trimmed_selections.push(start..end);
12662                }
12663
12664                for trimmed_range in trimmed_selections {
12665                    if is_first {
12666                        is_first = false;
12667                    } else {
12668                        text += "\n";
12669                    }
12670                    let mut len = 0;
12671                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12672                        text.push_str(chunk);
12673                        len += chunk.len();
12674                    }
12675                    if add_trailing_newline {
12676                        text.push('\n');
12677                        len += 1;
12678                    }
12679                    clipboard_selections.push(ClipboardSelection {
12680                        len,
12681                        is_entire_line,
12682                        first_line_indent: buffer
12683                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12684                            .len,
12685                    });
12686                }
12687            }
12688        }
12689
12690        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12691            text,
12692            clipboard_selections,
12693        ));
12694    }
12695
12696    pub fn do_paste(
12697        &mut self,
12698        text: &String,
12699        clipboard_selections: Option<Vec<ClipboardSelection>>,
12700        handle_entire_lines: bool,
12701        window: &mut Window,
12702        cx: &mut Context<Self>,
12703    ) {
12704        if self.read_only(cx) {
12705            return;
12706        }
12707
12708        let clipboard_text = Cow::Borrowed(text.as_str());
12709
12710        self.transact(window, cx, |this, window, cx| {
12711            let had_active_edit_prediction = this.has_active_edit_prediction();
12712            let display_map = this.display_snapshot(cx);
12713            let old_selections = this.selections.all::<usize>(&display_map);
12714            let cursor_offset = this.selections.last::<usize>(&display_map).head();
12715
12716            if let Some(mut clipboard_selections) = clipboard_selections {
12717                let all_selections_were_entire_line =
12718                    clipboard_selections.iter().all(|s| s.is_entire_line);
12719                let first_selection_indent_column =
12720                    clipboard_selections.first().map(|s| s.first_line_indent);
12721                if clipboard_selections.len() != old_selections.len() {
12722                    clipboard_selections.drain(..);
12723                }
12724                let mut auto_indent_on_paste = true;
12725
12726                this.buffer.update(cx, |buffer, cx| {
12727                    let snapshot = buffer.read(cx);
12728                    auto_indent_on_paste = snapshot
12729                        .language_settings_at(cursor_offset, cx)
12730                        .auto_indent_on_paste;
12731
12732                    let mut start_offset = 0;
12733                    let mut edits = Vec::new();
12734                    let mut original_indent_columns = Vec::new();
12735                    for (ix, selection) in old_selections.iter().enumerate() {
12736                        let to_insert;
12737                        let entire_line;
12738                        let original_indent_column;
12739                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12740                            let end_offset = start_offset + clipboard_selection.len;
12741                            to_insert = &clipboard_text[start_offset..end_offset];
12742                            entire_line = clipboard_selection.is_entire_line;
12743                            start_offset = end_offset + 1;
12744                            original_indent_column = Some(clipboard_selection.first_line_indent);
12745                        } else {
12746                            to_insert = &*clipboard_text;
12747                            entire_line = all_selections_were_entire_line;
12748                            original_indent_column = first_selection_indent_column
12749                        }
12750
12751                        let (range, to_insert) =
12752                            if selection.is_empty() && handle_entire_lines && entire_line {
12753                                // If the corresponding selection was empty when this slice of the
12754                                // clipboard text was written, then the entire line containing the
12755                                // selection was copied. If this selection is also currently empty,
12756                                // then paste the line before the current line of the buffer.
12757                                let column = selection.start.to_point(&snapshot).column as usize;
12758                                let line_start = selection.start - column;
12759                                (line_start..line_start, Cow::Borrowed(to_insert))
12760                            } else {
12761                                let language = snapshot.language_at(selection.head());
12762                                let range = selection.range();
12763                                if let Some(language) = language
12764                                    && language.name() == "Markdown".into()
12765                                {
12766                                    edit_for_markdown_paste(
12767                                        &snapshot,
12768                                        range,
12769                                        to_insert,
12770                                        url::Url::parse(to_insert).ok(),
12771                                    )
12772                                } else {
12773                                    (range, Cow::Borrowed(to_insert))
12774                                }
12775                            };
12776
12777                        edits.push((range, to_insert));
12778                        original_indent_columns.push(original_indent_column);
12779                    }
12780                    drop(snapshot);
12781
12782                    buffer.edit(
12783                        edits,
12784                        if auto_indent_on_paste {
12785                            Some(AutoindentMode::Block {
12786                                original_indent_columns,
12787                            })
12788                        } else {
12789                            None
12790                        },
12791                        cx,
12792                    );
12793                });
12794
12795                let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
12796                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12797            } else {
12798                let url = url::Url::parse(&clipboard_text).ok();
12799
12800                let auto_indent_mode = if !clipboard_text.is_empty() {
12801                    Some(AutoindentMode::Block {
12802                        original_indent_columns: Vec::new(),
12803                    })
12804                } else {
12805                    None
12806                };
12807
12808                let selection_anchors = this.buffer.update(cx, |buffer, cx| {
12809                    let snapshot = buffer.snapshot(cx);
12810
12811                    let anchors = old_selections
12812                        .iter()
12813                        .map(|s| {
12814                            let anchor = snapshot.anchor_after(s.head());
12815                            s.map(|_| anchor)
12816                        })
12817                        .collect::<Vec<_>>();
12818
12819                    let mut edits = Vec::new();
12820
12821                    for selection in old_selections.iter() {
12822                        let language = snapshot.language_at(selection.head());
12823                        let range = selection.range();
12824
12825                        let (edit_range, edit_text) = if let Some(language) = language
12826                            && language.name() == "Markdown".into()
12827                        {
12828                            edit_for_markdown_paste(&snapshot, range, &clipboard_text, url.clone())
12829                        } else {
12830                            (range, clipboard_text.clone())
12831                        };
12832
12833                        edits.push((edit_range, edit_text));
12834                    }
12835
12836                    drop(snapshot);
12837                    buffer.edit(edits, auto_indent_mode, cx);
12838
12839                    anchors
12840                });
12841
12842                this.change_selections(Default::default(), window, cx, |s| {
12843                    s.select_anchors(selection_anchors);
12844                });
12845            }
12846
12847            let trigger_in_words =
12848                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
12849
12850            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
12851        });
12852    }
12853
12854    pub fn diff_clipboard_with_selection(
12855        &mut self,
12856        _: &DiffClipboardWithSelection,
12857        window: &mut Window,
12858        cx: &mut Context<Self>,
12859    ) {
12860        let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
12861
12862        if selections.is_empty() {
12863            log::warn!("There should always be at least one selection in Zed. This is a bug.");
12864            return;
12865        };
12866
12867        let clipboard_text = match cx.read_from_clipboard() {
12868            Some(item) => match item.entries().first() {
12869                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
12870                _ => None,
12871            },
12872            None => None,
12873        };
12874
12875        let Some(clipboard_text) = clipboard_text else {
12876            log::warn!("Clipboard doesn't contain text.");
12877            return;
12878        };
12879
12880        window.dispatch_action(
12881            Box::new(DiffClipboardWithSelectionData {
12882                clipboard_text,
12883                editor: cx.entity(),
12884            }),
12885            cx,
12886        );
12887    }
12888
12889    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
12890        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12891        if let Some(item) = cx.read_from_clipboard() {
12892            let entries = item.entries();
12893
12894            match entries.first() {
12895                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
12896                // of all the pasted entries.
12897                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
12898                    .do_paste(
12899                        clipboard_string.text(),
12900                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
12901                        true,
12902                        window,
12903                        cx,
12904                    ),
12905                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
12906            }
12907        }
12908    }
12909
12910    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
12911        if self.read_only(cx) {
12912            return;
12913        }
12914
12915        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12916
12917        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
12918            if let Some((selections, _)) =
12919                self.selection_history.transaction(transaction_id).cloned()
12920            {
12921                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12922                    s.select_anchors(selections.to_vec());
12923                });
12924            } else {
12925                log::error!(
12926                    "No entry in selection_history found for undo. \
12927                     This may correspond to a bug where undo does not update the selection. \
12928                     If this is occurring, please add details to \
12929                     https://github.com/zed-industries/zed/issues/22692"
12930                );
12931            }
12932            self.request_autoscroll(Autoscroll::fit(), cx);
12933            self.unmark_text(window, cx);
12934            self.refresh_edit_prediction(true, false, window, cx);
12935            cx.emit(EditorEvent::Edited { transaction_id });
12936            cx.emit(EditorEvent::TransactionUndone { transaction_id });
12937        }
12938    }
12939
12940    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
12941        if self.read_only(cx) {
12942            return;
12943        }
12944
12945        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12946
12947        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
12948            if let Some((_, Some(selections))) =
12949                self.selection_history.transaction(transaction_id).cloned()
12950            {
12951                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12952                    s.select_anchors(selections.to_vec());
12953                });
12954            } else {
12955                log::error!(
12956                    "No entry in selection_history found for redo. \
12957                     This may correspond to a bug where undo does not update the selection. \
12958                     If this is occurring, please add details to \
12959                     https://github.com/zed-industries/zed/issues/22692"
12960                );
12961            }
12962            self.request_autoscroll(Autoscroll::fit(), cx);
12963            self.unmark_text(window, cx);
12964            self.refresh_edit_prediction(true, false, window, cx);
12965            cx.emit(EditorEvent::Edited { transaction_id });
12966        }
12967    }
12968
12969    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
12970        self.buffer
12971            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
12972    }
12973
12974    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
12975        self.buffer
12976            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
12977    }
12978
12979    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
12980        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12981        self.change_selections(Default::default(), window, cx, |s| {
12982            s.move_with(|map, selection| {
12983                let cursor = if selection.is_empty() {
12984                    movement::left(map, selection.start)
12985                } else {
12986                    selection.start
12987                };
12988                selection.collapse_to(cursor, SelectionGoal::None);
12989            });
12990        })
12991    }
12992
12993    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
12994        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12995        self.change_selections(Default::default(), window, cx, |s| {
12996            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
12997        })
12998    }
12999
13000    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
13001        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13002        self.change_selections(Default::default(), window, cx, |s| {
13003            s.move_with(|map, selection| {
13004                let cursor = if selection.is_empty() {
13005                    movement::right(map, selection.end)
13006                } else {
13007                    selection.end
13008                };
13009                selection.collapse_to(cursor, SelectionGoal::None)
13010            });
13011        })
13012    }
13013
13014    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
13015        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13016        self.change_selections(Default::default(), window, cx, |s| {
13017            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
13018        });
13019    }
13020
13021    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
13022        if self.take_rename(true, window, cx).is_some() {
13023            return;
13024        }
13025
13026        if self.mode.is_single_line() {
13027            cx.propagate();
13028            return;
13029        }
13030
13031        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13032
13033        let text_layout_details = &self.text_layout_details(window);
13034        let selection_count = self.selections.count();
13035        let first_selection = self.selections.first_anchor();
13036
13037        self.change_selections(Default::default(), window, cx, |s| {
13038            s.move_with(|map, selection| {
13039                if !selection.is_empty() {
13040                    selection.goal = SelectionGoal::None;
13041                }
13042                let (cursor, goal) = movement::up(
13043                    map,
13044                    selection.start,
13045                    selection.goal,
13046                    false,
13047                    text_layout_details,
13048                );
13049                selection.collapse_to(cursor, goal);
13050            });
13051        });
13052
13053        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13054        {
13055            cx.propagate();
13056        }
13057    }
13058
13059    pub fn move_up_by_lines(
13060        &mut self,
13061        action: &MoveUpByLines,
13062        window: &mut Window,
13063        cx: &mut Context<Self>,
13064    ) {
13065        if self.take_rename(true, window, cx).is_some() {
13066            return;
13067        }
13068
13069        if self.mode.is_single_line() {
13070            cx.propagate();
13071            return;
13072        }
13073
13074        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13075
13076        let text_layout_details = &self.text_layout_details(window);
13077
13078        self.change_selections(Default::default(), window, cx, |s| {
13079            s.move_with(|map, selection| {
13080                if !selection.is_empty() {
13081                    selection.goal = SelectionGoal::None;
13082                }
13083                let (cursor, goal) = movement::up_by_rows(
13084                    map,
13085                    selection.start,
13086                    action.lines,
13087                    selection.goal,
13088                    false,
13089                    text_layout_details,
13090                );
13091                selection.collapse_to(cursor, goal);
13092            });
13093        })
13094    }
13095
13096    pub fn move_down_by_lines(
13097        &mut self,
13098        action: &MoveDownByLines,
13099        window: &mut Window,
13100        cx: &mut Context<Self>,
13101    ) {
13102        if self.take_rename(true, window, cx).is_some() {
13103            return;
13104        }
13105
13106        if self.mode.is_single_line() {
13107            cx.propagate();
13108            return;
13109        }
13110
13111        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13112
13113        let text_layout_details = &self.text_layout_details(window);
13114
13115        self.change_selections(Default::default(), window, cx, |s| {
13116            s.move_with(|map, selection| {
13117                if !selection.is_empty() {
13118                    selection.goal = SelectionGoal::None;
13119                }
13120                let (cursor, goal) = movement::down_by_rows(
13121                    map,
13122                    selection.start,
13123                    action.lines,
13124                    selection.goal,
13125                    false,
13126                    text_layout_details,
13127                );
13128                selection.collapse_to(cursor, goal);
13129            });
13130        })
13131    }
13132
13133    pub fn select_down_by_lines(
13134        &mut self,
13135        action: &SelectDownByLines,
13136        window: &mut Window,
13137        cx: &mut Context<Self>,
13138    ) {
13139        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13140        let text_layout_details = &self.text_layout_details(window);
13141        self.change_selections(Default::default(), window, cx, |s| {
13142            s.move_heads_with(|map, head, goal| {
13143                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
13144            })
13145        })
13146    }
13147
13148    pub fn select_up_by_lines(
13149        &mut self,
13150        action: &SelectUpByLines,
13151        window: &mut Window,
13152        cx: &mut Context<Self>,
13153    ) {
13154        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13155        let text_layout_details = &self.text_layout_details(window);
13156        self.change_selections(Default::default(), window, cx, |s| {
13157            s.move_heads_with(|map, head, goal| {
13158                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
13159            })
13160        })
13161    }
13162
13163    pub fn select_page_up(
13164        &mut self,
13165        _: &SelectPageUp,
13166        window: &mut Window,
13167        cx: &mut Context<Self>,
13168    ) {
13169        let Some(row_count) = self.visible_row_count() else {
13170            return;
13171        };
13172
13173        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13174
13175        let text_layout_details = &self.text_layout_details(window);
13176
13177        self.change_selections(Default::default(), window, cx, |s| {
13178            s.move_heads_with(|map, head, goal| {
13179                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
13180            })
13181        })
13182    }
13183
13184    pub fn move_page_up(
13185        &mut self,
13186        action: &MovePageUp,
13187        window: &mut Window,
13188        cx: &mut Context<Self>,
13189    ) {
13190        if self.take_rename(true, window, cx).is_some() {
13191            return;
13192        }
13193
13194        if self
13195            .context_menu
13196            .borrow_mut()
13197            .as_mut()
13198            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
13199            .unwrap_or(false)
13200        {
13201            return;
13202        }
13203
13204        if matches!(self.mode, EditorMode::SingleLine) {
13205            cx.propagate();
13206            return;
13207        }
13208
13209        let Some(row_count) = self.visible_row_count() else {
13210            return;
13211        };
13212
13213        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13214
13215        let effects = if action.center_cursor {
13216            SelectionEffects::scroll(Autoscroll::center())
13217        } else {
13218            SelectionEffects::default()
13219        };
13220
13221        let text_layout_details = &self.text_layout_details(window);
13222
13223        self.change_selections(effects, window, cx, |s| {
13224            s.move_with(|map, selection| {
13225                if !selection.is_empty() {
13226                    selection.goal = SelectionGoal::None;
13227                }
13228                let (cursor, goal) = movement::up_by_rows(
13229                    map,
13230                    selection.end,
13231                    row_count,
13232                    selection.goal,
13233                    false,
13234                    text_layout_details,
13235                );
13236                selection.collapse_to(cursor, goal);
13237            });
13238        });
13239    }
13240
13241    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
13242        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13243        let text_layout_details = &self.text_layout_details(window);
13244        self.change_selections(Default::default(), window, cx, |s| {
13245            s.move_heads_with(|map, head, goal| {
13246                movement::up(map, head, goal, false, text_layout_details)
13247            })
13248        })
13249    }
13250
13251    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
13252        self.take_rename(true, window, cx);
13253
13254        if self.mode.is_single_line() {
13255            cx.propagate();
13256            return;
13257        }
13258
13259        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13260
13261        let text_layout_details = &self.text_layout_details(window);
13262        let selection_count = self.selections.count();
13263        let first_selection = self.selections.first_anchor();
13264
13265        self.change_selections(Default::default(), window, cx, |s| {
13266            s.move_with(|map, selection| {
13267                if !selection.is_empty() {
13268                    selection.goal = SelectionGoal::None;
13269                }
13270                let (cursor, goal) = movement::down(
13271                    map,
13272                    selection.end,
13273                    selection.goal,
13274                    false,
13275                    text_layout_details,
13276                );
13277                selection.collapse_to(cursor, goal);
13278            });
13279        });
13280
13281        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13282        {
13283            cx.propagate();
13284        }
13285    }
13286
13287    pub fn select_page_down(
13288        &mut self,
13289        _: &SelectPageDown,
13290        window: &mut Window,
13291        cx: &mut Context<Self>,
13292    ) {
13293        let Some(row_count) = self.visible_row_count() else {
13294            return;
13295        };
13296
13297        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13298
13299        let text_layout_details = &self.text_layout_details(window);
13300
13301        self.change_selections(Default::default(), window, cx, |s| {
13302            s.move_heads_with(|map, head, goal| {
13303                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
13304            })
13305        })
13306    }
13307
13308    pub fn move_page_down(
13309        &mut self,
13310        action: &MovePageDown,
13311        window: &mut Window,
13312        cx: &mut Context<Self>,
13313    ) {
13314        if self.take_rename(true, window, cx).is_some() {
13315            return;
13316        }
13317
13318        if self
13319            .context_menu
13320            .borrow_mut()
13321            .as_mut()
13322            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
13323            .unwrap_or(false)
13324        {
13325            return;
13326        }
13327
13328        if matches!(self.mode, EditorMode::SingleLine) {
13329            cx.propagate();
13330            return;
13331        }
13332
13333        let Some(row_count) = self.visible_row_count() else {
13334            return;
13335        };
13336
13337        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13338
13339        let effects = if action.center_cursor {
13340            SelectionEffects::scroll(Autoscroll::center())
13341        } else {
13342            SelectionEffects::default()
13343        };
13344
13345        let text_layout_details = &self.text_layout_details(window);
13346        self.change_selections(effects, window, cx, |s| {
13347            s.move_with(|map, selection| {
13348                if !selection.is_empty() {
13349                    selection.goal = SelectionGoal::None;
13350                }
13351                let (cursor, goal) = movement::down_by_rows(
13352                    map,
13353                    selection.end,
13354                    row_count,
13355                    selection.goal,
13356                    false,
13357                    text_layout_details,
13358                );
13359                selection.collapse_to(cursor, goal);
13360            });
13361        });
13362    }
13363
13364    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
13365        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13366        let text_layout_details = &self.text_layout_details(window);
13367        self.change_selections(Default::default(), window, cx, |s| {
13368            s.move_heads_with(|map, head, goal| {
13369                movement::down(map, head, goal, false, text_layout_details)
13370            })
13371        });
13372    }
13373
13374    pub fn context_menu_first(
13375        &mut self,
13376        _: &ContextMenuFirst,
13377        window: &mut Window,
13378        cx: &mut Context<Self>,
13379    ) {
13380        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13381            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
13382        }
13383    }
13384
13385    pub fn context_menu_prev(
13386        &mut self,
13387        _: &ContextMenuPrevious,
13388        window: &mut Window,
13389        cx: &mut Context<Self>,
13390    ) {
13391        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13392            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
13393        }
13394    }
13395
13396    pub fn context_menu_next(
13397        &mut self,
13398        _: &ContextMenuNext,
13399        window: &mut Window,
13400        cx: &mut Context<Self>,
13401    ) {
13402        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13403            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
13404        }
13405    }
13406
13407    pub fn context_menu_last(
13408        &mut self,
13409        _: &ContextMenuLast,
13410        window: &mut Window,
13411        cx: &mut Context<Self>,
13412    ) {
13413        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13414            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
13415        }
13416    }
13417
13418    pub fn signature_help_prev(
13419        &mut self,
13420        _: &SignatureHelpPrevious,
13421        _: &mut Window,
13422        cx: &mut Context<Self>,
13423    ) {
13424        if let Some(popover) = self.signature_help_state.popover_mut() {
13425            if popover.current_signature == 0 {
13426                popover.current_signature = popover.signatures.len() - 1;
13427            } else {
13428                popover.current_signature -= 1;
13429            }
13430            cx.notify();
13431        }
13432    }
13433
13434    pub fn signature_help_next(
13435        &mut self,
13436        _: &SignatureHelpNext,
13437        _: &mut Window,
13438        cx: &mut Context<Self>,
13439    ) {
13440        if let Some(popover) = self.signature_help_state.popover_mut() {
13441            if popover.current_signature + 1 == popover.signatures.len() {
13442                popover.current_signature = 0;
13443            } else {
13444                popover.current_signature += 1;
13445            }
13446            cx.notify();
13447        }
13448    }
13449
13450    pub fn move_to_previous_word_start(
13451        &mut self,
13452        _: &MoveToPreviousWordStart,
13453        window: &mut Window,
13454        cx: &mut Context<Self>,
13455    ) {
13456        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13457        self.change_selections(Default::default(), window, cx, |s| {
13458            s.move_cursors_with(|map, head, _| {
13459                (
13460                    movement::previous_word_start(map, head),
13461                    SelectionGoal::None,
13462                )
13463            });
13464        })
13465    }
13466
13467    pub fn move_to_previous_subword_start(
13468        &mut self,
13469        _: &MoveToPreviousSubwordStart,
13470        window: &mut Window,
13471        cx: &mut Context<Self>,
13472    ) {
13473        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13474        self.change_selections(Default::default(), window, cx, |s| {
13475            s.move_cursors_with(|map, head, _| {
13476                (
13477                    movement::previous_subword_start(map, head),
13478                    SelectionGoal::None,
13479                )
13480            });
13481        })
13482    }
13483
13484    pub fn select_to_previous_word_start(
13485        &mut self,
13486        _: &SelectToPreviousWordStart,
13487        window: &mut Window,
13488        cx: &mut Context<Self>,
13489    ) {
13490        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13491        self.change_selections(Default::default(), window, cx, |s| {
13492            s.move_heads_with(|map, head, _| {
13493                (
13494                    movement::previous_word_start(map, head),
13495                    SelectionGoal::None,
13496                )
13497            });
13498        })
13499    }
13500
13501    pub fn select_to_previous_subword_start(
13502        &mut self,
13503        _: &SelectToPreviousSubwordStart,
13504        window: &mut Window,
13505        cx: &mut Context<Self>,
13506    ) {
13507        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13508        self.change_selections(Default::default(), window, cx, |s| {
13509            s.move_heads_with(|map, head, _| {
13510                (
13511                    movement::previous_subword_start(map, head),
13512                    SelectionGoal::None,
13513                )
13514            });
13515        })
13516    }
13517
13518    pub fn delete_to_previous_word_start(
13519        &mut self,
13520        action: &DeleteToPreviousWordStart,
13521        window: &mut Window,
13522        cx: &mut Context<Self>,
13523    ) {
13524        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13525        self.transact(window, cx, |this, window, cx| {
13526            this.select_autoclose_pair(window, cx);
13527            this.change_selections(Default::default(), window, cx, |s| {
13528                s.move_with(|map, selection| {
13529                    if selection.is_empty() {
13530                        let mut cursor = if action.ignore_newlines {
13531                            movement::previous_word_start(map, selection.head())
13532                        } else {
13533                            movement::previous_word_start_or_newline(map, selection.head())
13534                        };
13535                        cursor = movement::adjust_greedy_deletion(
13536                            map,
13537                            selection.head(),
13538                            cursor,
13539                            action.ignore_brackets,
13540                        );
13541                        selection.set_head(cursor, SelectionGoal::None);
13542                    }
13543                });
13544            });
13545            this.insert("", window, cx);
13546        });
13547    }
13548
13549    pub fn delete_to_previous_subword_start(
13550        &mut self,
13551        _: &DeleteToPreviousSubwordStart,
13552        window: &mut Window,
13553        cx: &mut Context<Self>,
13554    ) {
13555        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13556        self.transact(window, cx, |this, window, cx| {
13557            this.select_autoclose_pair(window, cx);
13558            this.change_selections(Default::default(), window, cx, |s| {
13559                s.move_with(|map, selection| {
13560                    if selection.is_empty() {
13561                        let mut cursor = movement::previous_subword_start(map, selection.head());
13562                        cursor =
13563                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13564                        selection.set_head(cursor, SelectionGoal::None);
13565                    }
13566                });
13567            });
13568            this.insert("", window, cx);
13569        });
13570    }
13571
13572    pub fn move_to_next_word_end(
13573        &mut self,
13574        _: &MoveToNextWordEnd,
13575        window: &mut Window,
13576        cx: &mut Context<Self>,
13577    ) {
13578        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13579        self.change_selections(Default::default(), window, cx, |s| {
13580            s.move_cursors_with(|map, head, _| {
13581                (movement::next_word_end(map, head), SelectionGoal::None)
13582            });
13583        })
13584    }
13585
13586    pub fn move_to_next_subword_end(
13587        &mut self,
13588        _: &MoveToNextSubwordEnd,
13589        window: &mut Window,
13590        cx: &mut Context<Self>,
13591    ) {
13592        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13593        self.change_selections(Default::default(), window, cx, |s| {
13594            s.move_cursors_with(|map, head, _| {
13595                (movement::next_subword_end(map, head), SelectionGoal::None)
13596            });
13597        })
13598    }
13599
13600    pub fn select_to_next_word_end(
13601        &mut self,
13602        _: &SelectToNextWordEnd,
13603        window: &mut Window,
13604        cx: &mut Context<Self>,
13605    ) {
13606        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13607        self.change_selections(Default::default(), window, cx, |s| {
13608            s.move_heads_with(|map, head, _| {
13609                (movement::next_word_end(map, head), SelectionGoal::None)
13610            });
13611        })
13612    }
13613
13614    pub fn select_to_next_subword_end(
13615        &mut self,
13616        _: &SelectToNextSubwordEnd,
13617        window: &mut Window,
13618        cx: &mut Context<Self>,
13619    ) {
13620        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13621        self.change_selections(Default::default(), window, cx, |s| {
13622            s.move_heads_with(|map, head, _| {
13623                (movement::next_subword_end(map, head), SelectionGoal::None)
13624            });
13625        })
13626    }
13627
13628    pub fn delete_to_next_word_end(
13629        &mut self,
13630        action: &DeleteToNextWordEnd,
13631        window: &mut Window,
13632        cx: &mut Context<Self>,
13633    ) {
13634        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13635        self.transact(window, cx, |this, window, cx| {
13636            this.change_selections(Default::default(), window, cx, |s| {
13637                s.move_with(|map, selection| {
13638                    if selection.is_empty() {
13639                        let mut cursor = if action.ignore_newlines {
13640                            movement::next_word_end(map, selection.head())
13641                        } else {
13642                            movement::next_word_end_or_newline(map, selection.head())
13643                        };
13644                        cursor = movement::adjust_greedy_deletion(
13645                            map,
13646                            selection.head(),
13647                            cursor,
13648                            action.ignore_brackets,
13649                        );
13650                        selection.set_head(cursor, SelectionGoal::None);
13651                    }
13652                });
13653            });
13654            this.insert("", window, cx);
13655        });
13656    }
13657
13658    pub fn delete_to_next_subword_end(
13659        &mut self,
13660        _: &DeleteToNextSubwordEnd,
13661        window: &mut Window,
13662        cx: &mut Context<Self>,
13663    ) {
13664        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13665        self.transact(window, cx, |this, window, cx| {
13666            this.change_selections(Default::default(), window, cx, |s| {
13667                s.move_with(|map, selection| {
13668                    if selection.is_empty() {
13669                        let mut cursor = movement::next_subword_end(map, selection.head());
13670                        cursor =
13671                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13672                        selection.set_head(cursor, SelectionGoal::None);
13673                    }
13674                });
13675            });
13676            this.insert("", window, cx);
13677        });
13678    }
13679
13680    pub fn move_to_beginning_of_line(
13681        &mut self,
13682        action: &MoveToBeginningOfLine,
13683        window: &mut Window,
13684        cx: &mut Context<Self>,
13685    ) {
13686        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13687        self.change_selections(Default::default(), window, cx, |s| {
13688            s.move_cursors_with(|map, head, _| {
13689                (
13690                    movement::indented_line_beginning(
13691                        map,
13692                        head,
13693                        action.stop_at_soft_wraps,
13694                        action.stop_at_indent,
13695                    ),
13696                    SelectionGoal::None,
13697                )
13698            });
13699        })
13700    }
13701
13702    pub fn select_to_beginning_of_line(
13703        &mut self,
13704        action: &SelectToBeginningOfLine,
13705        window: &mut Window,
13706        cx: &mut Context<Self>,
13707    ) {
13708        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13709        self.change_selections(Default::default(), window, cx, |s| {
13710            s.move_heads_with(|map, head, _| {
13711                (
13712                    movement::indented_line_beginning(
13713                        map,
13714                        head,
13715                        action.stop_at_soft_wraps,
13716                        action.stop_at_indent,
13717                    ),
13718                    SelectionGoal::None,
13719                )
13720            });
13721        });
13722    }
13723
13724    pub fn delete_to_beginning_of_line(
13725        &mut self,
13726        action: &DeleteToBeginningOfLine,
13727        window: &mut Window,
13728        cx: &mut Context<Self>,
13729    ) {
13730        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13731        self.transact(window, cx, |this, window, cx| {
13732            this.change_selections(Default::default(), window, cx, |s| {
13733                s.move_with(|_, selection| {
13734                    selection.reversed = true;
13735                });
13736            });
13737
13738            this.select_to_beginning_of_line(
13739                &SelectToBeginningOfLine {
13740                    stop_at_soft_wraps: false,
13741                    stop_at_indent: action.stop_at_indent,
13742                },
13743                window,
13744                cx,
13745            );
13746            this.backspace(&Backspace, window, cx);
13747        });
13748    }
13749
13750    pub fn move_to_end_of_line(
13751        &mut self,
13752        action: &MoveToEndOfLine,
13753        window: &mut Window,
13754        cx: &mut Context<Self>,
13755    ) {
13756        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13757        self.change_selections(Default::default(), window, cx, |s| {
13758            s.move_cursors_with(|map, head, _| {
13759                (
13760                    movement::line_end(map, head, action.stop_at_soft_wraps),
13761                    SelectionGoal::None,
13762                )
13763            });
13764        })
13765    }
13766
13767    pub fn select_to_end_of_line(
13768        &mut self,
13769        action: &SelectToEndOfLine,
13770        window: &mut Window,
13771        cx: &mut Context<Self>,
13772    ) {
13773        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13774        self.change_selections(Default::default(), window, cx, |s| {
13775            s.move_heads_with(|map, head, _| {
13776                (
13777                    movement::line_end(map, head, action.stop_at_soft_wraps),
13778                    SelectionGoal::None,
13779                )
13780            });
13781        })
13782    }
13783
13784    pub fn delete_to_end_of_line(
13785        &mut self,
13786        _: &DeleteToEndOfLine,
13787        window: &mut Window,
13788        cx: &mut Context<Self>,
13789    ) {
13790        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13791        self.transact(window, cx, |this, window, cx| {
13792            this.select_to_end_of_line(
13793                &SelectToEndOfLine {
13794                    stop_at_soft_wraps: false,
13795                },
13796                window,
13797                cx,
13798            );
13799            this.delete(&Delete, window, cx);
13800        });
13801    }
13802
13803    pub fn cut_to_end_of_line(
13804        &mut self,
13805        action: &CutToEndOfLine,
13806        window: &mut Window,
13807        cx: &mut Context<Self>,
13808    ) {
13809        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13810        self.transact(window, cx, |this, window, cx| {
13811            this.select_to_end_of_line(
13812                &SelectToEndOfLine {
13813                    stop_at_soft_wraps: false,
13814                },
13815                window,
13816                cx,
13817            );
13818            if !action.stop_at_newlines {
13819                this.change_selections(Default::default(), window, cx, |s| {
13820                    s.move_with(|_, sel| {
13821                        if sel.is_empty() {
13822                            sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
13823                        }
13824                    });
13825                });
13826            }
13827            this.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13828            let item = this.cut_common(false, window, cx);
13829            cx.write_to_clipboard(item);
13830        });
13831    }
13832
13833    pub fn move_to_start_of_paragraph(
13834        &mut self,
13835        _: &MoveToStartOfParagraph,
13836        window: &mut Window,
13837        cx: &mut Context<Self>,
13838    ) {
13839        if matches!(self.mode, EditorMode::SingleLine) {
13840            cx.propagate();
13841            return;
13842        }
13843        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13844        self.change_selections(Default::default(), window, cx, |s| {
13845            s.move_with(|map, selection| {
13846                selection.collapse_to(
13847                    movement::start_of_paragraph(map, selection.head(), 1),
13848                    SelectionGoal::None,
13849                )
13850            });
13851        })
13852    }
13853
13854    pub fn move_to_end_of_paragraph(
13855        &mut self,
13856        _: &MoveToEndOfParagraph,
13857        window: &mut Window,
13858        cx: &mut Context<Self>,
13859    ) {
13860        if matches!(self.mode, EditorMode::SingleLine) {
13861            cx.propagate();
13862            return;
13863        }
13864        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13865        self.change_selections(Default::default(), window, cx, |s| {
13866            s.move_with(|map, selection| {
13867                selection.collapse_to(
13868                    movement::end_of_paragraph(map, selection.head(), 1),
13869                    SelectionGoal::None,
13870                )
13871            });
13872        })
13873    }
13874
13875    pub fn select_to_start_of_paragraph(
13876        &mut self,
13877        _: &SelectToStartOfParagraph,
13878        window: &mut Window,
13879        cx: &mut Context<Self>,
13880    ) {
13881        if matches!(self.mode, EditorMode::SingleLine) {
13882            cx.propagate();
13883            return;
13884        }
13885        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13886        self.change_selections(Default::default(), window, cx, |s| {
13887            s.move_heads_with(|map, head, _| {
13888                (
13889                    movement::start_of_paragraph(map, head, 1),
13890                    SelectionGoal::None,
13891                )
13892            });
13893        })
13894    }
13895
13896    pub fn select_to_end_of_paragraph(
13897        &mut self,
13898        _: &SelectToEndOfParagraph,
13899        window: &mut Window,
13900        cx: &mut Context<Self>,
13901    ) {
13902        if matches!(self.mode, EditorMode::SingleLine) {
13903            cx.propagate();
13904            return;
13905        }
13906        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13907        self.change_selections(Default::default(), window, cx, |s| {
13908            s.move_heads_with(|map, head, _| {
13909                (
13910                    movement::end_of_paragraph(map, head, 1),
13911                    SelectionGoal::None,
13912                )
13913            });
13914        })
13915    }
13916
13917    pub fn move_to_start_of_excerpt(
13918        &mut self,
13919        _: &MoveToStartOfExcerpt,
13920        window: &mut Window,
13921        cx: &mut Context<Self>,
13922    ) {
13923        if matches!(self.mode, EditorMode::SingleLine) {
13924            cx.propagate();
13925            return;
13926        }
13927        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13928        self.change_selections(Default::default(), window, cx, |s| {
13929            s.move_with(|map, selection| {
13930                selection.collapse_to(
13931                    movement::start_of_excerpt(
13932                        map,
13933                        selection.head(),
13934                        workspace::searchable::Direction::Prev,
13935                    ),
13936                    SelectionGoal::None,
13937                )
13938            });
13939        })
13940    }
13941
13942    pub fn move_to_start_of_next_excerpt(
13943        &mut self,
13944        _: &MoveToStartOfNextExcerpt,
13945        window: &mut Window,
13946        cx: &mut Context<Self>,
13947    ) {
13948        if matches!(self.mode, EditorMode::SingleLine) {
13949            cx.propagate();
13950            return;
13951        }
13952
13953        self.change_selections(Default::default(), window, cx, |s| {
13954            s.move_with(|map, selection| {
13955                selection.collapse_to(
13956                    movement::start_of_excerpt(
13957                        map,
13958                        selection.head(),
13959                        workspace::searchable::Direction::Next,
13960                    ),
13961                    SelectionGoal::None,
13962                )
13963            });
13964        })
13965    }
13966
13967    pub fn move_to_end_of_excerpt(
13968        &mut self,
13969        _: &MoveToEndOfExcerpt,
13970        window: &mut Window,
13971        cx: &mut Context<Self>,
13972    ) {
13973        if matches!(self.mode, EditorMode::SingleLine) {
13974            cx.propagate();
13975            return;
13976        }
13977        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13978        self.change_selections(Default::default(), window, cx, |s| {
13979            s.move_with(|map, selection| {
13980                selection.collapse_to(
13981                    movement::end_of_excerpt(
13982                        map,
13983                        selection.head(),
13984                        workspace::searchable::Direction::Next,
13985                    ),
13986                    SelectionGoal::None,
13987                )
13988            });
13989        })
13990    }
13991
13992    pub fn move_to_end_of_previous_excerpt(
13993        &mut self,
13994        _: &MoveToEndOfPreviousExcerpt,
13995        window: &mut Window,
13996        cx: &mut Context<Self>,
13997    ) {
13998        if matches!(self.mode, EditorMode::SingleLine) {
13999            cx.propagate();
14000            return;
14001        }
14002        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14003        self.change_selections(Default::default(), window, cx, |s| {
14004            s.move_with(|map, selection| {
14005                selection.collapse_to(
14006                    movement::end_of_excerpt(
14007                        map,
14008                        selection.head(),
14009                        workspace::searchable::Direction::Prev,
14010                    ),
14011                    SelectionGoal::None,
14012                )
14013            });
14014        })
14015    }
14016
14017    pub fn select_to_start_of_excerpt(
14018        &mut self,
14019        _: &SelectToStartOfExcerpt,
14020        window: &mut Window,
14021        cx: &mut Context<Self>,
14022    ) {
14023        if matches!(self.mode, EditorMode::SingleLine) {
14024            cx.propagate();
14025            return;
14026        }
14027        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14028        self.change_selections(Default::default(), window, cx, |s| {
14029            s.move_heads_with(|map, head, _| {
14030                (
14031                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
14032                    SelectionGoal::None,
14033                )
14034            });
14035        })
14036    }
14037
14038    pub fn select_to_start_of_next_excerpt(
14039        &mut self,
14040        _: &SelectToStartOfNextExcerpt,
14041        window: &mut Window,
14042        cx: &mut Context<Self>,
14043    ) {
14044        if matches!(self.mode, EditorMode::SingleLine) {
14045            cx.propagate();
14046            return;
14047        }
14048        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14049        self.change_selections(Default::default(), window, cx, |s| {
14050            s.move_heads_with(|map, head, _| {
14051                (
14052                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
14053                    SelectionGoal::None,
14054                )
14055            });
14056        })
14057    }
14058
14059    pub fn select_to_end_of_excerpt(
14060        &mut self,
14061        _: &SelectToEndOfExcerpt,
14062        window: &mut Window,
14063        cx: &mut Context<Self>,
14064    ) {
14065        if matches!(self.mode, EditorMode::SingleLine) {
14066            cx.propagate();
14067            return;
14068        }
14069        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14070        self.change_selections(Default::default(), window, cx, |s| {
14071            s.move_heads_with(|map, head, _| {
14072                (
14073                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
14074                    SelectionGoal::None,
14075                )
14076            });
14077        })
14078    }
14079
14080    pub fn select_to_end_of_previous_excerpt(
14081        &mut self,
14082        _: &SelectToEndOfPreviousExcerpt,
14083        window: &mut Window,
14084        cx: &mut Context<Self>,
14085    ) {
14086        if matches!(self.mode, EditorMode::SingleLine) {
14087            cx.propagate();
14088            return;
14089        }
14090        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14091        self.change_selections(Default::default(), window, cx, |s| {
14092            s.move_heads_with(|map, head, _| {
14093                (
14094                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
14095                    SelectionGoal::None,
14096                )
14097            });
14098        })
14099    }
14100
14101    pub fn move_to_beginning(
14102        &mut self,
14103        _: &MoveToBeginning,
14104        window: &mut Window,
14105        cx: &mut Context<Self>,
14106    ) {
14107        if matches!(self.mode, EditorMode::SingleLine) {
14108            cx.propagate();
14109            return;
14110        }
14111        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14112        self.change_selections(Default::default(), window, cx, |s| {
14113            s.select_ranges(vec![0..0]);
14114        });
14115    }
14116
14117    pub fn select_to_beginning(
14118        &mut self,
14119        _: &SelectToBeginning,
14120        window: &mut Window,
14121        cx: &mut Context<Self>,
14122    ) {
14123        let mut selection = self.selections.last::<Point>(&self.display_snapshot(cx));
14124        selection.set_head(Point::zero(), SelectionGoal::None);
14125        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14126        self.change_selections(Default::default(), window, cx, |s| {
14127            s.select(vec![selection]);
14128        });
14129    }
14130
14131    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
14132        if matches!(self.mode, EditorMode::SingleLine) {
14133            cx.propagate();
14134            return;
14135        }
14136        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14137        let cursor = self.buffer.read(cx).read(cx).len();
14138        self.change_selections(Default::default(), window, cx, |s| {
14139            s.select_ranges(vec![cursor..cursor])
14140        });
14141    }
14142
14143    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
14144        self.nav_history = nav_history;
14145    }
14146
14147    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
14148        self.nav_history.as_ref()
14149    }
14150
14151    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
14152        self.push_to_nav_history(
14153            self.selections.newest_anchor().head(),
14154            None,
14155            false,
14156            true,
14157            cx,
14158        );
14159    }
14160
14161    fn push_to_nav_history(
14162        &mut self,
14163        cursor_anchor: Anchor,
14164        new_position: Option<Point>,
14165        is_deactivate: bool,
14166        always: bool,
14167        cx: &mut Context<Self>,
14168    ) {
14169        if let Some(nav_history) = self.nav_history.as_mut() {
14170            let buffer = self.buffer.read(cx).read(cx);
14171            let cursor_position = cursor_anchor.to_point(&buffer);
14172            let scroll_state = self.scroll_manager.anchor();
14173            let scroll_top_row = scroll_state.top_row(&buffer);
14174            drop(buffer);
14175
14176            if let Some(new_position) = new_position {
14177                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
14178                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
14179                    return;
14180                }
14181            }
14182
14183            nav_history.push(
14184                Some(NavigationData {
14185                    cursor_anchor,
14186                    cursor_position,
14187                    scroll_anchor: scroll_state,
14188                    scroll_top_row,
14189                }),
14190                cx,
14191            );
14192            cx.emit(EditorEvent::PushedToNavHistory {
14193                anchor: cursor_anchor,
14194                is_deactivate,
14195            })
14196        }
14197    }
14198
14199    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
14200        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14201        let buffer = self.buffer.read(cx).snapshot(cx);
14202        let mut selection = self.selections.first::<usize>(&self.display_snapshot(cx));
14203        selection.set_head(buffer.len(), SelectionGoal::None);
14204        self.change_selections(Default::default(), window, cx, |s| {
14205            s.select(vec![selection]);
14206        });
14207    }
14208
14209    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
14210        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14211        let end = self.buffer.read(cx).read(cx).len();
14212        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14213            s.select_ranges(vec![0..end]);
14214        });
14215    }
14216
14217    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
14218        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14219        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14220        let mut selections = self.selections.all::<Point>(&display_map);
14221        let max_point = display_map.buffer_snapshot().max_point();
14222        for selection in &mut selections {
14223            let rows = selection.spanned_rows(true, &display_map);
14224            selection.start = Point::new(rows.start.0, 0);
14225            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
14226            selection.reversed = false;
14227        }
14228        self.change_selections(Default::default(), window, cx, |s| {
14229            s.select(selections);
14230        });
14231    }
14232
14233    pub fn split_selection_into_lines(
14234        &mut self,
14235        action: &SplitSelectionIntoLines,
14236        window: &mut Window,
14237        cx: &mut Context<Self>,
14238    ) {
14239        let selections = self
14240            .selections
14241            .all::<Point>(&self.display_snapshot(cx))
14242            .into_iter()
14243            .map(|selection| selection.start..selection.end)
14244            .collect::<Vec<_>>();
14245        self.unfold_ranges(&selections, true, true, cx);
14246
14247        let mut new_selection_ranges = Vec::new();
14248        {
14249            let buffer = self.buffer.read(cx).read(cx);
14250            for selection in selections {
14251                for row in selection.start.row..selection.end.row {
14252                    let line_start = Point::new(row, 0);
14253                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
14254
14255                    if action.keep_selections {
14256                        // Keep the selection range for each line
14257                        let selection_start = if row == selection.start.row {
14258                            selection.start
14259                        } else {
14260                            line_start
14261                        };
14262                        new_selection_ranges.push(selection_start..line_end);
14263                    } else {
14264                        // Collapse to cursor at end of line
14265                        new_selection_ranges.push(line_end..line_end);
14266                    }
14267                }
14268
14269                let is_multiline_selection = selection.start.row != selection.end.row;
14270                // Don't insert last one if it's a multi-line selection ending at the start of a line,
14271                // so this action feels more ergonomic when paired with other selection operations
14272                let should_skip_last = is_multiline_selection && selection.end.column == 0;
14273                if !should_skip_last {
14274                    if action.keep_selections {
14275                        if is_multiline_selection {
14276                            let line_start = Point::new(selection.end.row, 0);
14277                            new_selection_ranges.push(line_start..selection.end);
14278                        } else {
14279                            new_selection_ranges.push(selection.start..selection.end);
14280                        }
14281                    } else {
14282                        new_selection_ranges.push(selection.end..selection.end);
14283                    }
14284                }
14285            }
14286        }
14287        self.change_selections(Default::default(), window, cx, |s| {
14288            s.select_ranges(new_selection_ranges);
14289        });
14290    }
14291
14292    pub fn add_selection_above(
14293        &mut self,
14294        action: &AddSelectionAbove,
14295        window: &mut Window,
14296        cx: &mut Context<Self>,
14297    ) {
14298        self.add_selection(true, action.skip_soft_wrap, window, cx);
14299    }
14300
14301    pub fn add_selection_below(
14302        &mut self,
14303        action: &AddSelectionBelow,
14304        window: &mut Window,
14305        cx: &mut Context<Self>,
14306    ) {
14307        self.add_selection(false, action.skip_soft_wrap, window, cx);
14308    }
14309
14310    fn add_selection(
14311        &mut self,
14312        above: bool,
14313        skip_soft_wrap: bool,
14314        window: &mut Window,
14315        cx: &mut Context<Self>,
14316    ) {
14317        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14318
14319        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14320        let all_selections = self.selections.all::<Point>(&display_map);
14321        let text_layout_details = self.text_layout_details(window);
14322
14323        let (mut columnar_selections, new_selections_to_columnarize) = {
14324            if let Some(state) = self.add_selections_state.as_ref() {
14325                let columnar_selection_ids: HashSet<_> = state
14326                    .groups
14327                    .iter()
14328                    .flat_map(|group| group.stack.iter())
14329                    .copied()
14330                    .collect();
14331
14332                all_selections
14333                    .into_iter()
14334                    .partition(|s| columnar_selection_ids.contains(&s.id))
14335            } else {
14336                (Vec::new(), all_selections)
14337            }
14338        };
14339
14340        let mut state = self
14341            .add_selections_state
14342            .take()
14343            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
14344
14345        for selection in new_selections_to_columnarize {
14346            let range = selection.display_range(&display_map).sorted();
14347            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
14348            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
14349            let positions = start_x.min(end_x)..start_x.max(end_x);
14350            let mut stack = Vec::new();
14351            for row in range.start.row().0..=range.end.row().0 {
14352                if let Some(selection) = self.selections.build_columnar_selection(
14353                    &display_map,
14354                    DisplayRow(row),
14355                    &positions,
14356                    selection.reversed,
14357                    &text_layout_details,
14358                ) {
14359                    stack.push(selection.id);
14360                    columnar_selections.push(selection);
14361                }
14362            }
14363            if !stack.is_empty() {
14364                if above {
14365                    stack.reverse();
14366                }
14367                state.groups.push(AddSelectionsGroup { above, stack });
14368            }
14369        }
14370
14371        let mut final_selections = Vec::new();
14372        let end_row = if above {
14373            DisplayRow(0)
14374        } else {
14375            display_map.max_point().row()
14376        };
14377
14378        let mut last_added_item_per_group = HashMap::default();
14379        for group in state.groups.iter_mut() {
14380            if let Some(last_id) = group.stack.last() {
14381                last_added_item_per_group.insert(*last_id, group);
14382            }
14383        }
14384
14385        for selection in columnar_selections {
14386            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
14387                if above == group.above {
14388                    let range = selection.display_range(&display_map).sorted();
14389                    debug_assert_eq!(range.start.row(), range.end.row());
14390                    let mut row = range.start.row();
14391                    let positions =
14392                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
14393                            Pixels::from(start)..Pixels::from(end)
14394                        } else {
14395                            let start_x =
14396                                display_map.x_for_display_point(range.start, &text_layout_details);
14397                            let end_x =
14398                                display_map.x_for_display_point(range.end, &text_layout_details);
14399                            start_x.min(end_x)..start_x.max(end_x)
14400                        };
14401
14402                    let mut maybe_new_selection = None;
14403                    let direction = if above { -1 } else { 1 };
14404
14405                    while row != end_row {
14406                        if skip_soft_wrap {
14407                            row = display_map
14408                                .start_of_relative_buffer_row(DisplayPoint::new(row, 0), direction)
14409                                .row();
14410                        } else if above {
14411                            row.0 -= 1;
14412                        } else {
14413                            row.0 += 1;
14414                        }
14415
14416                        if let Some(new_selection) = self.selections.build_columnar_selection(
14417                            &display_map,
14418                            row,
14419                            &positions,
14420                            selection.reversed,
14421                            &text_layout_details,
14422                        ) {
14423                            maybe_new_selection = Some(new_selection);
14424                            break;
14425                        }
14426                    }
14427
14428                    if let Some(new_selection) = maybe_new_selection {
14429                        group.stack.push(new_selection.id);
14430                        if above {
14431                            final_selections.push(new_selection);
14432                            final_selections.push(selection);
14433                        } else {
14434                            final_selections.push(selection);
14435                            final_selections.push(new_selection);
14436                        }
14437                    } else {
14438                        final_selections.push(selection);
14439                    }
14440                } else {
14441                    group.stack.pop();
14442                }
14443            } else {
14444                final_selections.push(selection);
14445            }
14446        }
14447
14448        self.change_selections(Default::default(), window, cx, |s| {
14449            s.select(final_selections);
14450        });
14451
14452        let final_selection_ids: HashSet<_> = self
14453            .selections
14454            .all::<Point>(&display_map)
14455            .iter()
14456            .map(|s| s.id)
14457            .collect();
14458        state.groups.retain_mut(|group| {
14459            // selections might get merged above so we remove invalid items from stacks
14460            group.stack.retain(|id| final_selection_ids.contains(id));
14461
14462            // single selection in stack can be treated as initial state
14463            group.stack.len() > 1
14464        });
14465
14466        if !state.groups.is_empty() {
14467            self.add_selections_state = Some(state);
14468        }
14469    }
14470
14471    fn select_match_ranges(
14472        &mut self,
14473        range: Range<usize>,
14474        reversed: bool,
14475        replace_newest: bool,
14476        auto_scroll: Option<Autoscroll>,
14477        window: &mut Window,
14478        cx: &mut Context<Editor>,
14479    ) {
14480        self.unfold_ranges(
14481            std::slice::from_ref(&range),
14482            false,
14483            auto_scroll.is_some(),
14484            cx,
14485        );
14486        let effects = if let Some(scroll) = auto_scroll {
14487            SelectionEffects::scroll(scroll)
14488        } else {
14489            SelectionEffects::no_scroll()
14490        };
14491        self.change_selections(effects, window, cx, |s| {
14492            if replace_newest {
14493                s.delete(s.newest_anchor().id);
14494            }
14495            if reversed {
14496                s.insert_range(range.end..range.start);
14497            } else {
14498                s.insert_range(range);
14499            }
14500        });
14501    }
14502
14503    pub fn select_next_match_internal(
14504        &mut self,
14505        display_map: &DisplaySnapshot,
14506        replace_newest: bool,
14507        autoscroll: Option<Autoscroll>,
14508        window: &mut Window,
14509        cx: &mut Context<Self>,
14510    ) -> Result<()> {
14511        let buffer = display_map.buffer_snapshot();
14512        let mut selections = self.selections.all::<usize>(&display_map);
14513        if let Some(mut select_next_state) = self.select_next_state.take() {
14514            let query = &select_next_state.query;
14515            if !select_next_state.done {
14516                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14517                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14518                let mut next_selected_range = None;
14519
14520                // Collect and sort selection ranges for efficient overlap checking
14521                let mut selection_ranges: Vec<_> = selections.iter().map(|s| s.range()).collect();
14522                selection_ranges.sort_by_key(|r| r.start);
14523
14524                let bytes_after_last_selection =
14525                    buffer.bytes_in_range(last_selection.end..buffer.len());
14526                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
14527                let query_matches = query
14528                    .stream_find_iter(bytes_after_last_selection)
14529                    .map(|result| (last_selection.end, result))
14530                    .chain(
14531                        query
14532                            .stream_find_iter(bytes_before_first_selection)
14533                            .map(|result| (0, result)),
14534                    );
14535
14536                for (start_offset, query_match) in query_matches {
14537                    let query_match = query_match.unwrap(); // can only fail due to I/O
14538                    let offset_range =
14539                        start_offset + query_match.start()..start_offset + query_match.end();
14540
14541                    if !select_next_state.wordwise
14542                        || (!buffer.is_inside_word(offset_range.start, None)
14543                            && !buffer.is_inside_word(offset_range.end, None))
14544                    {
14545                        // Use binary search to check for overlap (O(log n))
14546                        let overlaps = selection_ranges
14547                            .binary_search_by(|range| {
14548                                if range.end <= offset_range.start {
14549                                    std::cmp::Ordering::Less
14550                                } else if range.start >= offset_range.end {
14551                                    std::cmp::Ordering::Greater
14552                                } else {
14553                                    std::cmp::Ordering::Equal
14554                                }
14555                            })
14556                            .is_ok();
14557
14558                        if !overlaps {
14559                            next_selected_range = Some(offset_range);
14560                            break;
14561                        }
14562                    }
14563                }
14564
14565                if let Some(next_selected_range) = next_selected_range {
14566                    self.select_match_ranges(
14567                        next_selected_range,
14568                        last_selection.reversed,
14569                        replace_newest,
14570                        autoscroll,
14571                        window,
14572                        cx,
14573                    );
14574                } else {
14575                    select_next_state.done = true;
14576                }
14577            }
14578
14579            self.select_next_state = Some(select_next_state);
14580        } else {
14581            let mut only_carets = true;
14582            let mut same_text_selected = true;
14583            let mut selected_text = None;
14584
14585            let mut selections_iter = selections.iter().peekable();
14586            while let Some(selection) = selections_iter.next() {
14587                if selection.start != selection.end {
14588                    only_carets = false;
14589                }
14590
14591                if same_text_selected {
14592                    if selected_text.is_none() {
14593                        selected_text =
14594                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14595                    }
14596
14597                    if let Some(next_selection) = selections_iter.peek() {
14598                        if next_selection.range().len() == selection.range().len() {
14599                            let next_selected_text = buffer
14600                                .text_for_range(next_selection.range())
14601                                .collect::<String>();
14602                            if Some(next_selected_text) != selected_text {
14603                                same_text_selected = false;
14604                                selected_text = None;
14605                            }
14606                        } else {
14607                            same_text_selected = false;
14608                            selected_text = None;
14609                        }
14610                    }
14611                }
14612            }
14613
14614            if only_carets {
14615                for selection in &mut selections {
14616                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14617                    selection.start = word_range.start;
14618                    selection.end = word_range.end;
14619                    selection.goal = SelectionGoal::None;
14620                    selection.reversed = false;
14621                    self.select_match_ranges(
14622                        selection.start..selection.end,
14623                        selection.reversed,
14624                        replace_newest,
14625                        autoscroll,
14626                        window,
14627                        cx,
14628                    );
14629                }
14630
14631                if selections.len() == 1 {
14632                    let selection = selections
14633                        .last()
14634                        .expect("ensured that there's only one selection");
14635                    let query = buffer
14636                        .text_for_range(selection.start..selection.end)
14637                        .collect::<String>();
14638                    let is_empty = query.is_empty();
14639                    let select_state = SelectNextState {
14640                        query: AhoCorasick::new(&[query])?,
14641                        wordwise: true,
14642                        done: is_empty,
14643                    };
14644                    self.select_next_state = Some(select_state);
14645                } else {
14646                    self.select_next_state = None;
14647                }
14648            } else if let Some(selected_text) = selected_text {
14649                self.select_next_state = Some(SelectNextState {
14650                    query: AhoCorasick::new(&[selected_text])?,
14651                    wordwise: false,
14652                    done: false,
14653                });
14654                self.select_next_match_internal(
14655                    display_map,
14656                    replace_newest,
14657                    autoscroll,
14658                    window,
14659                    cx,
14660                )?;
14661            }
14662        }
14663        Ok(())
14664    }
14665
14666    pub fn select_all_matches(
14667        &mut self,
14668        _action: &SelectAllMatches,
14669        window: &mut Window,
14670        cx: &mut Context<Self>,
14671    ) -> Result<()> {
14672        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14673
14674        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14675
14676        self.select_next_match_internal(&display_map, false, None, window, cx)?;
14677        let Some(select_next_state) = self.select_next_state.as_mut() else {
14678            return Ok(());
14679        };
14680        if select_next_state.done {
14681            return Ok(());
14682        }
14683
14684        let mut new_selections = Vec::new();
14685
14686        let reversed = self.selections.oldest::<usize>(&display_map).reversed;
14687        let buffer = display_map.buffer_snapshot();
14688        let query_matches = select_next_state
14689            .query
14690            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
14691
14692        for query_match in query_matches.into_iter() {
14693            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
14694            let offset_range = if reversed {
14695                query_match.end()..query_match.start()
14696            } else {
14697                query_match.start()..query_match.end()
14698            };
14699
14700            if !select_next_state.wordwise
14701                || (!buffer.is_inside_word(offset_range.start, None)
14702                    && !buffer.is_inside_word(offset_range.end, None))
14703            {
14704                new_selections.push(offset_range.start..offset_range.end);
14705            }
14706        }
14707
14708        select_next_state.done = true;
14709
14710        if new_selections.is_empty() {
14711            log::error!("bug: new_selections is empty in select_all_matches");
14712            return Ok(());
14713        }
14714
14715        self.unfold_ranges(&new_selections.clone(), false, false, cx);
14716        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
14717            selections.select_ranges(new_selections)
14718        });
14719
14720        Ok(())
14721    }
14722
14723    pub fn select_next(
14724        &mut self,
14725        action: &SelectNext,
14726        window: &mut Window,
14727        cx: &mut Context<Self>,
14728    ) -> Result<()> {
14729        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14730        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14731        self.select_next_match_internal(
14732            &display_map,
14733            action.replace_newest,
14734            Some(Autoscroll::newest()),
14735            window,
14736            cx,
14737        )?;
14738        Ok(())
14739    }
14740
14741    pub fn select_previous(
14742        &mut self,
14743        action: &SelectPrevious,
14744        window: &mut Window,
14745        cx: &mut Context<Self>,
14746    ) -> Result<()> {
14747        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14748        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14749        let buffer = display_map.buffer_snapshot();
14750        let mut selections = self.selections.all::<usize>(&display_map);
14751        if let Some(mut select_prev_state) = self.select_prev_state.take() {
14752            let query = &select_prev_state.query;
14753            if !select_prev_state.done {
14754                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14755                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14756                let mut next_selected_range = None;
14757                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
14758                let bytes_before_last_selection =
14759                    buffer.reversed_bytes_in_range(0..last_selection.start);
14760                let bytes_after_first_selection =
14761                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
14762                let query_matches = query
14763                    .stream_find_iter(bytes_before_last_selection)
14764                    .map(|result| (last_selection.start, result))
14765                    .chain(
14766                        query
14767                            .stream_find_iter(bytes_after_first_selection)
14768                            .map(|result| (buffer.len(), result)),
14769                    );
14770                for (end_offset, query_match) in query_matches {
14771                    let query_match = query_match.unwrap(); // can only fail due to I/O
14772                    let offset_range =
14773                        end_offset - query_match.end()..end_offset - query_match.start();
14774
14775                    if !select_prev_state.wordwise
14776                        || (!buffer.is_inside_word(offset_range.start, None)
14777                            && !buffer.is_inside_word(offset_range.end, None))
14778                    {
14779                        next_selected_range = Some(offset_range);
14780                        break;
14781                    }
14782                }
14783
14784                if let Some(next_selected_range) = next_selected_range {
14785                    self.select_match_ranges(
14786                        next_selected_range,
14787                        last_selection.reversed,
14788                        action.replace_newest,
14789                        Some(Autoscroll::newest()),
14790                        window,
14791                        cx,
14792                    );
14793                } else {
14794                    select_prev_state.done = true;
14795                }
14796            }
14797
14798            self.select_prev_state = Some(select_prev_state);
14799        } else {
14800            let mut only_carets = true;
14801            let mut same_text_selected = true;
14802            let mut selected_text = None;
14803
14804            let mut selections_iter = selections.iter().peekable();
14805            while let Some(selection) = selections_iter.next() {
14806                if selection.start != selection.end {
14807                    only_carets = false;
14808                }
14809
14810                if same_text_selected {
14811                    if selected_text.is_none() {
14812                        selected_text =
14813                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14814                    }
14815
14816                    if let Some(next_selection) = selections_iter.peek() {
14817                        if next_selection.range().len() == selection.range().len() {
14818                            let next_selected_text = buffer
14819                                .text_for_range(next_selection.range())
14820                                .collect::<String>();
14821                            if Some(next_selected_text) != selected_text {
14822                                same_text_selected = false;
14823                                selected_text = None;
14824                            }
14825                        } else {
14826                            same_text_selected = false;
14827                            selected_text = None;
14828                        }
14829                    }
14830                }
14831            }
14832
14833            if only_carets {
14834                for selection in &mut selections {
14835                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14836                    selection.start = word_range.start;
14837                    selection.end = word_range.end;
14838                    selection.goal = SelectionGoal::None;
14839                    selection.reversed = false;
14840                    self.select_match_ranges(
14841                        selection.start..selection.end,
14842                        selection.reversed,
14843                        action.replace_newest,
14844                        Some(Autoscroll::newest()),
14845                        window,
14846                        cx,
14847                    );
14848                }
14849                if selections.len() == 1 {
14850                    let selection = selections
14851                        .last()
14852                        .expect("ensured that there's only one selection");
14853                    let query = buffer
14854                        .text_for_range(selection.start..selection.end)
14855                        .collect::<String>();
14856                    let is_empty = query.is_empty();
14857                    let select_state = SelectNextState {
14858                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
14859                        wordwise: true,
14860                        done: is_empty,
14861                    };
14862                    self.select_prev_state = Some(select_state);
14863                } else {
14864                    self.select_prev_state = None;
14865                }
14866            } else if let Some(selected_text) = selected_text {
14867                self.select_prev_state = Some(SelectNextState {
14868                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
14869                    wordwise: false,
14870                    done: false,
14871                });
14872                self.select_previous(action, window, cx)?;
14873            }
14874        }
14875        Ok(())
14876    }
14877
14878    pub fn find_next_match(
14879        &mut self,
14880        _: &FindNextMatch,
14881        window: &mut Window,
14882        cx: &mut Context<Self>,
14883    ) -> Result<()> {
14884        let selections = self.selections.disjoint_anchors_arc();
14885        match selections.first() {
14886            Some(first) if selections.len() >= 2 => {
14887                self.change_selections(Default::default(), window, cx, |s| {
14888                    s.select_ranges([first.range()]);
14889                });
14890            }
14891            _ => self.select_next(
14892                &SelectNext {
14893                    replace_newest: true,
14894                },
14895                window,
14896                cx,
14897            )?,
14898        }
14899        Ok(())
14900    }
14901
14902    pub fn find_previous_match(
14903        &mut self,
14904        _: &FindPreviousMatch,
14905        window: &mut Window,
14906        cx: &mut Context<Self>,
14907    ) -> Result<()> {
14908        let selections = self.selections.disjoint_anchors_arc();
14909        match selections.last() {
14910            Some(last) if selections.len() >= 2 => {
14911                self.change_selections(Default::default(), window, cx, |s| {
14912                    s.select_ranges([last.range()]);
14913                });
14914            }
14915            _ => self.select_previous(
14916                &SelectPrevious {
14917                    replace_newest: true,
14918                },
14919                window,
14920                cx,
14921            )?,
14922        }
14923        Ok(())
14924    }
14925
14926    pub fn toggle_comments(
14927        &mut self,
14928        action: &ToggleComments,
14929        window: &mut Window,
14930        cx: &mut Context<Self>,
14931    ) {
14932        if self.read_only(cx) {
14933            return;
14934        }
14935        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14936        let text_layout_details = &self.text_layout_details(window);
14937        self.transact(window, cx, |this, window, cx| {
14938            let mut selections = this
14939                .selections
14940                .all::<MultiBufferPoint>(&this.display_snapshot(cx));
14941            let mut edits = Vec::new();
14942            let mut selection_edit_ranges = Vec::new();
14943            let mut last_toggled_row = None;
14944            let snapshot = this.buffer.read(cx).read(cx);
14945            let empty_str: Arc<str> = Arc::default();
14946            let mut suffixes_inserted = Vec::new();
14947            let ignore_indent = action.ignore_indent;
14948
14949            fn comment_prefix_range(
14950                snapshot: &MultiBufferSnapshot,
14951                row: MultiBufferRow,
14952                comment_prefix: &str,
14953                comment_prefix_whitespace: &str,
14954                ignore_indent: bool,
14955            ) -> Range<Point> {
14956                let indent_size = if ignore_indent {
14957                    0
14958                } else {
14959                    snapshot.indent_size_for_line(row).len
14960                };
14961
14962                let start = Point::new(row.0, indent_size);
14963
14964                let mut line_bytes = snapshot
14965                    .bytes_in_range(start..snapshot.max_point())
14966                    .flatten()
14967                    .copied();
14968
14969                // If this line currently begins with the line comment prefix, then record
14970                // the range containing the prefix.
14971                if line_bytes
14972                    .by_ref()
14973                    .take(comment_prefix.len())
14974                    .eq(comment_prefix.bytes())
14975                {
14976                    // Include any whitespace that matches the comment prefix.
14977                    let matching_whitespace_len = line_bytes
14978                        .zip(comment_prefix_whitespace.bytes())
14979                        .take_while(|(a, b)| a == b)
14980                        .count() as u32;
14981                    let end = Point::new(
14982                        start.row,
14983                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
14984                    );
14985                    start..end
14986                } else {
14987                    start..start
14988                }
14989            }
14990
14991            fn comment_suffix_range(
14992                snapshot: &MultiBufferSnapshot,
14993                row: MultiBufferRow,
14994                comment_suffix: &str,
14995                comment_suffix_has_leading_space: bool,
14996            ) -> Range<Point> {
14997                let end = Point::new(row.0, snapshot.line_len(row));
14998                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
14999
15000                let mut line_end_bytes = snapshot
15001                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
15002                    .flatten()
15003                    .copied();
15004
15005                let leading_space_len = if suffix_start_column > 0
15006                    && line_end_bytes.next() == Some(b' ')
15007                    && comment_suffix_has_leading_space
15008                {
15009                    1
15010                } else {
15011                    0
15012                };
15013
15014                // If this line currently begins with the line comment prefix, then record
15015                // the range containing the prefix.
15016                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
15017                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
15018                    start..end
15019                } else {
15020                    end..end
15021                }
15022            }
15023
15024            // TODO: Handle selections that cross excerpts
15025            for selection in &mut selections {
15026                let start_column = snapshot
15027                    .indent_size_for_line(MultiBufferRow(selection.start.row))
15028                    .len;
15029                let language = if let Some(language) =
15030                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
15031                {
15032                    language
15033                } else {
15034                    continue;
15035                };
15036
15037                selection_edit_ranges.clear();
15038
15039                // If multiple selections contain a given row, avoid processing that
15040                // row more than once.
15041                let mut start_row = MultiBufferRow(selection.start.row);
15042                if last_toggled_row == Some(start_row) {
15043                    start_row = start_row.next_row();
15044                }
15045                let end_row =
15046                    if selection.end.row > selection.start.row && selection.end.column == 0 {
15047                        MultiBufferRow(selection.end.row - 1)
15048                    } else {
15049                        MultiBufferRow(selection.end.row)
15050                    };
15051                last_toggled_row = Some(end_row);
15052
15053                if start_row > end_row {
15054                    continue;
15055                }
15056
15057                // If the language has line comments, toggle those.
15058                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
15059
15060                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
15061                if ignore_indent {
15062                    full_comment_prefixes = full_comment_prefixes
15063                        .into_iter()
15064                        .map(|s| Arc::from(s.trim_end()))
15065                        .collect();
15066                }
15067
15068                if !full_comment_prefixes.is_empty() {
15069                    let first_prefix = full_comment_prefixes
15070                        .first()
15071                        .expect("prefixes is non-empty");
15072                    let prefix_trimmed_lengths = full_comment_prefixes
15073                        .iter()
15074                        .map(|p| p.trim_end_matches(' ').len())
15075                        .collect::<SmallVec<[usize; 4]>>();
15076
15077                    let mut all_selection_lines_are_comments = true;
15078
15079                    for row in start_row.0..=end_row.0 {
15080                        let row = MultiBufferRow(row);
15081                        if start_row < end_row && snapshot.is_line_blank(row) {
15082                            continue;
15083                        }
15084
15085                        let prefix_range = full_comment_prefixes
15086                            .iter()
15087                            .zip(prefix_trimmed_lengths.iter().copied())
15088                            .map(|(prefix, trimmed_prefix_len)| {
15089                                comment_prefix_range(
15090                                    snapshot.deref(),
15091                                    row,
15092                                    &prefix[..trimmed_prefix_len],
15093                                    &prefix[trimmed_prefix_len..],
15094                                    ignore_indent,
15095                                )
15096                            })
15097                            .max_by_key(|range| range.end.column - range.start.column)
15098                            .expect("prefixes is non-empty");
15099
15100                        if prefix_range.is_empty() {
15101                            all_selection_lines_are_comments = false;
15102                        }
15103
15104                        selection_edit_ranges.push(prefix_range);
15105                    }
15106
15107                    if all_selection_lines_are_comments {
15108                        edits.extend(
15109                            selection_edit_ranges
15110                                .iter()
15111                                .cloned()
15112                                .map(|range| (range, empty_str.clone())),
15113                        );
15114                    } else {
15115                        let min_column = selection_edit_ranges
15116                            .iter()
15117                            .map(|range| range.start.column)
15118                            .min()
15119                            .unwrap_or(0);
15120                        edits.extend(selection_edit_ranges.iter().map(|range| {
15121                            let position = Point::new(range.start.row, min_column);
15122                            (position..position, first_prefix.clone())
15123                        }));
15124                    }
15125                } else if let Some(BlockCommentConfig {
15126                    start: full_comment_prefix,
15127                    end: comment_suffix,
15128                    ..
15129                }) = language.block_comment()
15130                {
15131                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
15132                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
15133                    let prefix_range = comment_prefix_range(
15134                        snapshot.deref(),
15135                        start_row,
15136                        comment_prefix,
15137                        comment_prefix_whitespace,
15138                        ignore_indent,
15139                    );
15140                    let suffix_range = comment_suffix_range(
15141                        snapshot.deref(),
15142                        end_row,
15143                        comment_suffix.trim_start_matches(' '),
15144                        comment_suffix.starts_with(' '),
15145                    );
15146
15147                    if prefix_range.is_empty() || suffix_range.is_empty() {
15148                        edits.push((
15149                            prefix_range.start..prefix_range.start,
15150                            full_comment_prefix.clone(),
15151                        ));
15152                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
15153                        suffixes_inserted.push((end_row, comment_suffix.len()));
15154                    } else {
15155                        edits.push((prefix_range, empty_str.clone()));
15156                        edits.push((suffix_range, empty_str.clone()));
15157                    }
15158                } else {
15159                    continue;
15160                }
15161            }
15162
15163            drop(snapshot);
15164            this.buffer.update(cx, |buffer, cx| {
15165                buffer.edit(edits, None, cx);
15166            });
15167
15168            // Adjust selections so that they end before any comment suffixes that
15169            // were inserted.
15170            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
15171            let mut selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15172            let snapshot = this.buffer.read(cx).read(cx);
15173            for selection in &mut selections {
15174                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
15175                    match row.cmp(&MultiBufferRow(selection.end.row)) {
15176                        Ordering::Less => {
15177                            suffixes_inserted.next();
15178                            continue;
15179                        }
15180                        Ordering::Greater => break,
15181                        Ordering::Equal => {
15182                            if selection.end.column == snapshot.line_len(row) {
15183                                if selection.is_empty() {
15184                                    selection.start.column -= suffix_len as u32;
15185                                }
15186                                selection.end.column -= suffix_len as u32;
15187                            }
15188                            break;
15189                        }
15190                    }
15191                }
15192            }
15193
15194            drop(snapshot);
15195            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
15196
15197            let selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15198            let selections_on_single_row = selections.windows(2).all(|selections| {
15199                selections[0].start.row == selections[1].start.row
15200                    && selections[0].end.row == selections[1].end.row
15201                    && selections[0].start.row == selections[0].end.row
15202            });
15203            let selections_selecting = selections
15204                .iter()
15205                .any(|selection| selection.start != selection.end);
15206            let advance_downwards = action.advance_downwards
15207                && selections_on_single_row
15208                && !selections_selecting
15209                && !matches!(this.mode, EditorMode::SingleLine);
15210
15211            if advance_downwards {
15212                let snapshot = this.buffer.read(cx).snapshot(cx);
15213
15214                this.change_selections(Default::default(), window, cx, |s| {
15215                    s.move_cursors_with(|display_snapshot, display_point, _| {
15216                        let mut point = display_point.to_point(display_snapshot);
15217                        point.row += 1;
15218                        point = snapshot.clip_point(point, Bias::Left);
15219                        let display_point = point.to_display_point(display_snapshot);
15220                        let goal = SelectionGoal::HorizontalPosition(
15221                            display_snapshot
15222                                .x_for_display_point(display_point, text_layout_details)
15223                                .into(),
15224                        );
15225                        (display_point, goal)
15226                    })
15227                });
15228            }
15229        });
15230    }
15231
15232    pub fn select_enclosing_symbol(
15233        &mut self,
15234        _: &SelectEnclosingSymbol,
15235        window: &mut Window,
15236        cx: &mut Context<Self>,
15237    ) {
15238        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15239
15240        let buffer = self.buffer.read(cx).snapshot(cx);
15241        let old_selections = self
15242            .selections
15243            .all::<usize>(&self.display_snapshot(cx))
15244            .into_boxed_slice();
15245
15246        fn update_selection(
15247            selection: &Selection<usize>,
15248            buffer_snap: &MultiBufferSnapshot,
15249        ) -> Option<Selection<usize>> {
15250            let cursor = selection.head();
15251            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
15252            for symbol in symbols.iter().rev() {
15253                let start = symbol.range.start.to_offset(buffer_snap);
15254                let end = symbol.range.end.to_offset(buffer_snap);
15255                let new_range = start..end;
15256                if start < selection.start || end > selection.end {
15257                    return Some(Selection {
15258                        id: selection.id,
15259                        start: new_range.start,
15260                        end: new_range.end,
15261                        goal: SelectionGoal::None,
15262                        reversed: selection.reversed,
15263                    });
15264                }
15265            }
15266            None
15267        }
15268
15269        let mut selected_larger_symbol = false;
15270        let new_selections = old_selections
15271            .iter()
15272            .map(|selection| match update_selection(selection, &buffer) {
15273                Some(new_selection) => {
15274                    if new_selection.range() != selection.range() {
15275                        selected_larger_symbol = true;
15276                    }
15277                    new_selection
15278                }
15279                None => selection.clone(),
15280            })
15281            .collect::<Vec<_>>();
15282
15283        if selected_larger_symbol {
15284            self.change_selections(Default::default(), window, cx, |s| {
15285                s.select(new_selections);
15286            });
15287        }
15288    }
15289
15290    pub fn select_larger_syntax_node(
15291        &mut self,
15292        _: &SelectLargerSyntaxNode,
15293        window: &mut Window,
15294        cx: &mut Context<Self>,
15295    ) {
15296        let Some(visible_row_count) = self.visible_row_count() else {
15297            return;
15298        };
15299        let old_selections: Box<[_]> = self
15300            .selections
15301            .all::<usize>(&self.display_snapshot(cx))
15302            .into();
15303        if old_selections.is_empty() {
15304            return;
15305        }
15306
15307        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15308
15309        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15310        let buffer = self.buffer.read(cx).snapshot(cx);
15311
15312        let mut selected_larger_node = false;
15313        let mut new_selections = old_selections
15314            .iter()
15315            .map(|selection| {
15316                let old_range = selection.start..selection.end;
15317
15318                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
15319                    // manually select word at selection
15320                    if ["string_content", "inline"].contains(&node.kind()) {
15321                        let (word_range, _) = buffer.surrounding_word(old_range.start, None);
15322                        // ignore if word is already selected
15323                        if !word_range.is_empty() && old_range != word_range {
15324                            let (last_word_range, _) = buffer.surrounding_word(old_range.end, None);
15325                            // only select word if start and end point belongs to same word
15326                            if word_range == last_word_range {
15327                                selected_larger_node = true;
15328                                return Selection {
15329                                    id: selection.id,
15330                                    start: word_range.start,
15331                                    end: word_range.end,
15332                                    goal: SelectionGoal::None,
15333                                    reversed: selection.reversed,
15334                                };
15335                            }
15336                        }
15337                    }
15338                }
15339
15340                let mut new_range = old_range.clone();
15341                while let Some((node, range)) = buffer.syntax_ancestor(new_range.clone()) {
15342                    new_range = range;
15343                    if !node.is_named() {
15344                        continue;
15345                    }
15346                    if !display_map.intersects_fold(new_range.start)
15347                        && !display_map.intersects_fold(new_range.end)
15348                    {
15349                        break;
15350                    }
15351                }
15352
15353                selected_larger_node |= new_range != old_range;
15354                Selection {
15355                    id: selection.id,
15356                    start: new_range.start,
15357                    end: new_range.end,
15358                    goal: SelectionGoal::None,
15359                    reversed: selection.reversed,
15360                }
15361            })
15362            .collect::<Vec<_>>();
15363
15364        if !selected_larger_node {
15365            return; // don't put this call in the history
15366        }
15367
15368        // scroll based on transformation done to the last selection created by the user
15369        let (last_old, last_new) = old_selections
15370            .last()
15371            .zip(new_selections.last().cloned())
15372            .expect("old_selections isn't empty");
15373
15374        // revert selection
15375        let is_selection_reversed = {
15376            let should_newest_selection_be_reversed = last_old.start != last_new.start;
15377            new_selections.last_mut().expect("checked above").reversed =
15378                should_newest_selection_be_reversed;
15379            should_newest_selection_be_reversed
15380        };
15381
15382        if selected_larger_node {
15383            self.select_syntax_node_history.disable_clearing = true;
15384            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15385                s.select(new_selections.clone());
15386            });
15387            self.select_syntax_node_history.disable_clearing = false;
15388        }
15389
15390        let start_row = last_new.start.to_display_point(&display_map).row().0;
15391        let end_row = last_new.end.to_display_point(&display_map).row().0;
15392        let selection_height = end_row - start_row + 1;
15393        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
15394
15395        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
15396        let scroll_behavior = if fits_on_the_screen {
15397            self.request_autoscroll(Autoscroll::fit(), cx);
15398            SelectSyntaxNodeScrollBehavior::FitSelection
15399        } else if is_selection_reversed {
15400            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15401            SelectSyntaxNodeScrollBehavior::CursorTop
15402        } else {
15403            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15404            SelectSyntaxNodeScrollBehavior::CursorBottom
15405        };
15406
15407        self.select_syntax_node_history.push((
15408            old_selections,
15409            scroll_behavior,
15410            is_selection_reversed,
15411        ));
15412    }
15413
15414    pub fn select_smaller_syntax_node(
15415        &mut self,
15416        _: &SelectSmallerSyntaxNode,
15417        window: &mut Window,
15418        cx: &mut Context<Self>,
15419    ) {
15420        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15421
15422        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
15423            self.select_syntax_node_history.pop()
15424        {
15425            if let Some(selection) = selections.last_mut() {
15426                selection.reversed = is_selection_reversed;
15427            }
15428
15429            self.select_syntax_node_history.disable_clearing = true;
15430            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15431                s.select(selections.to_vec());
15432            });
15433            self.select_syntax_node_history.disable_clearing = false;
15434
15435            match scroll_behavior {
15436                SelectSyntaxNodeScrollBehavior::CursorTop => {
15437                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15438                }
15439                SelectSyntaxNodeScrollBehavior::FitSelection => {
15440                    self.request_autoscroll(Autoscroll::fit(), cx);
15441                }
15442                SelectSyntaxNodeScrollBehavior::CursorBottom => {
15443                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15444                }
15445            }
15446        }
15447    }
15448
15449    pub fn unwrap_syntax_node(
15450        &mut self,
15451        _: &UnwrapSyntaxNode,
15452        window: &mut Window,
15453        cx: &mut Context<Self>,
15454    ) {
15455        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15456
15457        let buffer = self.buffer.read(cx).snapshot(cx);
15458        let selections = self
15459            .selections
15460            .all::<usize>(&self.display_snapshot(cx))
15461            .into_iter()
15462            // subtracting the offset requires sorting
15463            .sorted_by_key(|i| i.start);
15464
15465        let full_edits = selections
15466            .into_iter()
15467            .filter_map(|selection| {
15468                let child = if selection.is_empty()
15469                    && let Some((_, ancestor_range)) =
15470                        buffer.syntax_ancestor(selection.start..selection.end)
15471                {
15472                    ancestor_range
15473                } else {
15474                    selection.range()
15475                };
15476
15477                let mut parent = child.clone();
15478                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
15479                    parent = ancestor_range;
15480                    if parent.start < child.start || parent.end > child.end {
15481                        break;
15482                    }
15483                }
15484
15485                if parent == child {
15486                    return None;
15487                }
15488                let text = buffer.text_for_range(child).collect::<String>();
15489                Some((selection.id, parent, text))
15490            })
15491            .collect::<Vec<_>>();
15492        if full_edits.is_empty() {
15493            return;
15494        }
15495
15496        self.transact(window, cx, |this, window, cx| {
15497            this.buffer.update(cx, |buffer, cx| {
15498                buffer.edit(
15499                    full_edits
15500                        .iter()
15501                        .map(|(_, p, t)| (p.clone(), t.clone()))
15502                        .collect::<Vec<_>>(),
15503                    None,
15504                    cx,
15505                );
15506            });
15507            this.change_selections(Default::default(), window, cx, |s| {
15508                let mut offset = 0;
15509                let mut selections = vec![];
15510                for (id, parent, text) in full_edits {
15511                    let start = parent.start - offset;
15512                    offset += parent.len() - text.len();
15513                    selections.push(Selection {
15514                        id,
15515                        start,
15516                        end: start + text.len(),
15517                        reversed: false,
15518                        goal: Default::default(),
15519                    });
15520                }
15521                s.select(selections);
15522            });
15523        });
15524    }
15525
15526    pub fn select_next_syntax_node(
15527        &mut self,
15528        _: &SelectNextSyntaxNode,
15529        window: &mut Window,
15530        cx: &mut Context<Self>,
15531    ) {
15532        let old_selections: Box<[_]> = self
15533            .selections
15534            .all::<usize>(&self.display_snapshot(cx))
15535            .into();
15536        if old_selections.is_empty() {
15537            return;
15538        }
15539
15540        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15541
15542        let buffer = self.buffer.read(cx).snapshot(cx);
15543        let mut selected_sibling = false;
15544
15545        let new_selections = old_selections
15546            .iter()
15547            .map(|selection| {
15548                let old_range = selection.start..selection.end;
15549
15550                if let Some(node) = buffer.syntax_next_sibling(old_range) {
15551                    let new_range = node.byte_range();
15552                    selected_sibling = true;
15553                    Selection {
15554                        id: selection.id,
15555                        start: new_range.start,
15556                        end: new_range.end,
15557                        goal: SelectionGoal::None,
15558                        reversed: selection.reversed,
15559                    }
15560                } else {
15561                    selection.clone()
15562                }
15563            })
15564            .collect::<Vec<_>>();
15565
15566        if selected_sibling {
15567            self.change_selections(
15568                SelectionEffects::scroll(Autoscroll::fit()),
15569                window,
15570                cx,
15571                |s| {
15572                    s.select(new_selections);
15573                },
15574            );
15575        }
15576    }
15577
15578    pub fn select_prev_syntax_node(
15579        &mut self,
15580        _: &SelectPreviousSyntaxNode,
15581        window: &mut Window,
15582        cx: &mut Context<Self>,
15583    ) {
15584        let old_selections: Box<[_]> = self
15585            .selections
15586            .all::<usize>(&self.display_snapshot(cx))
15587            .into();
15588        if old_selections.is_empty() {
15589            return;
15590        }
15591
15592        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15593
15594        let buffer = self.buffer.read(cx).snapshot(cx);
15595        let mut selected_sibling = false;
15596
15597        let new_selections = old_selections
15598            .iter()
15599            .map(|selection| {
15600                let old_range = selection.start..selection.end;
15601
15602                if let Some(node) = buffer.syntax_prev_sibling(old_range) {
15603                    let new_range = node.byte_range();
15604                    selected_sibling = true;
15605                    Selection {
15606                        id: selection.id,
15607                        start: new_range.start,
15608                        end: new_range.end,
15609                        goal: SelectionGoal::None,
15610                        reversed: selection.reversed,
15611                    }
15612                } else {
15613                    selection.clone()
15614                }
15615            })
15616            .collect::<Vec<_>>();
15617
15618        if selected_sibling {
15619            self.change_selections(
15620                SelectionEffects::scroll(Autoscroll::fit()),
15621                window,
15622                cx,
15623                |s| {
15624                    s.select(new_selections);
15625                },
15626            );
15627        }
15628    }
15629
15630    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
15631        if !EditorSettings::get_global(cx).gutter.runnables {
15632            self.clear_tasks();
15633            return Task::ready(());
15634        }
15635        let project = self.project().map(Entity::downgrade);
15636        let task_sources = self.lsp_task_sources(cx);
15637        let multi_buffer = self.buffer.downgrade();
15638        cx.spawn_in(window, async move |editor, cx| {
15639            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
15640            let Some(project) = project.and_then(|p| p.upgrade()) else {
15641                return;
15642            };
15643            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
15644                this.display_map.update(cx, |map, cx| map.snapshot(cx))
15645            }) else {
15646                return;
15647            };
15648
15649            let hide_runnables = project
15650                .update(cx, |project, _| project.is_via_collab())
15651                .unwrap_or(true);
15652            if hide_runnables {
15653                return;
15654            }
15655            let new_rows =
15656                cx.background_spawn({
15657                    let snapshot = display_snapshot.clone();
15658                    async move {
15659                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
15660                    }
15661                })
15662                    .await;
15663            let Ok(lsp_tasks) =
15664                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
15665            else {
15666                return;
15667            };
15668            let lsp_tasks = lsp_tasks.await;
15669
15670            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
15671                lsp_tasks
15672                    .into_iter()
15673                    .flat_map(|(kind, tasks)| {
15674                        tasks.into_iter().filter_map(move |(location, task)| {
15675                            Some((kind.clone(), location?, task))
15676                        })
15677                    })
15678                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
15679                        let buffer = location.target.buffer;
15680                        let buffer_snapshot = buffer.read(cx).snapshot();
15681                        let offset = display_snapshot.buffer_snapshot().excerpts().find_map(
15682                            |(excerpt_id, snapshot, _)| {
15683                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
15684                                    display_snapshot
15685                                        .buffer_snapshot()
15686                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
15687                                } else {
15688                                    None
15689                                }
15690                            },
15691                        );
15692                        if let Some(offset) = offset {
15693                            let task_buffer_range =
15694                                location.target.range.to_point(&buffer_snapshot);
15695                            let context_buffer_range =
15696                                task_buffer_range.to_offset(&buffer_snapshot);
15697                            let context_range = BufferOffset(context_buffer_range.start)
15698                                ..BufferOffset(context_buffer_range.end);
15699
15700                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
15701                                .or_insert_with(|| RunnableTasks {
15702                                    templates: Vec::new(),
15703                                    offset,
15704                                    column: task_buffer_range.start.column,
15705                                    extra_variables: HashMap::default(),
15706                                    context_range,
15707                                })
15708                                .templates
15709                                .push((kind, task.original_task().clone()));
15710                        }
15711
15712                        acc
15713                    })
15714            }) else {
15715                return;
15716            };
15717
15718            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
15719                buffer.language_settings(cx).tasks.prefer_lsp
15720            }) else {
15721                return;
15722            };
15723
15724            let rows = Self::runnable_rows(
15725                project,
15726                display_snapshot,
15727                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
15728                new_rows,
15729                cx.clone(),
15730            )
15731            .await;
15732            editor
15733                .update(cx, |editor, _| {
15734                    editor.clear_tasks();
15735                    for (key, mut value) in rows {
15736                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
15737                            value.templates.extend(lsp_tasks.templates);
15738                        }
15739
15740                        editor.insert_tasks(key, value);
15741                    }
15742                    for (key, value) in lsp_tasks_by_rows {
15743                        editor.insert_tasks(key, value);
15744                    }
15745                })
15746                .ok();
15747        })
15748    }
15749    fn fetch_runnable_ranges(
15750        snapshot: &DisplaySnapshot,
15751        range: Range<Anchor>,
15752    ) -> Vec<language::RunnableRange> {
15753        snapshot.buffer_snapshot().runnable_ranges(range).collect()
15754    }
15755
15756    fn runnable_rows(
15757        project: Entity<Project>,
15758        snapshot: DisplaySnapshot,
15759        prefer_lsp: bool,
15760        runnable_ranges: Vec<RunnableRange>,
15761        cx: AsyncWindowContext,
15762    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
15763        cx.spawn(async move |cx| {
15764            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
15765            for mut runnable in runnable_ranges {
15766                let Some(tasks) = cx
15767                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
15768                    .ok()
15769                else {
15770                    continue;
15771                };
15772                let mut tasks = tasks.await;
15773
15774                if prefer_lsp {
15775                    tasks.retain(|(task_kind, _)| {
15776                        !matches!(task_kind, TaskSourceKind::Language { .. })
15777                    });
15778                }
15779                if tasks.is_empty() {
15780                    continue;
15781                }
15782
15783                let point = runnable
15784                    .run_range
15785                    .start
15786                    .to_point(&snapshot.buffer_snapshot());
15787                let Some(row) = snapshot
15788                    .buffer_snapshot()
15789                    .buffer_line_for_row(MultiBufferRow(point.row))
15790                    .map(|(_, range)| range.start.row)
15791                else {
15792                    continue;
15793                };
15794
15795                let context_range =
15796                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
15797                runnable_rows.push((
15798                    (runnable.buffer_id, row),
15799                    RunnableTasks {
15800                        templates: tasks,
15801                        offset: snapshot
15802                            .buffer_snapshot()
15803                            .anchor_before(runnable.run_range.start),
15804                        context_range,
15805                        column: point.column,
15806                        extra_variables: runnable.extra_captures,
15807                    },
15808                ));
15809            }
15810            runnable_rows
15811        })
15812    }
15813
15814    fn templates_with_tags(
15815        project: &Entity<Project>,
15816        runnable: &mut Runnable,
15817        cx: &mut App,
15818    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
15819        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
15820            let (worktree_id, file) = project
15821                .buffer_for_id(runnable.buffer, cx)
15822                .and_then(|buffer| buffer.read(cx).file())
15823                .map(|file| (file.worktree_id(cx), file.clone()))
15824                .unzip();
15825
15826            (
15827                project.task_store().read(cx).task_inventory().cloned(),
15828                worktree_id,
15829                file,
15830            )
15831        });
15832
15833        let tags = mem::take(&mut runnable.tags);
15834        let language = runnable.language.clone();
15835        cx.spawn(async move |cx| {
15836            let mut templates_with_tags = Vec::new();
15837            if let Some(inventory) = inventory {
15838                for RunnableTag(tag) in tags {
15839                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
15840                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
15841                    }) else {
15842                        return templates_with_tags;
15843                    };
15844                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
15845                        move |(_, template)| {
15846                            template.tags.iter().any(|source_tag| source_tag == &tag)
15847                        },
15848                    ));
15849                }
15850            }
15851            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
15852
15853            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
15854                // Strongest source wins; if we have worktree tag binding, prefer that to
15855                // global and language bindings;
15856                // if we have a global binding, prefer that to language binding.
15857                let first_mismatch = templates_with_tags
15858                    .iter()
15859                    .position(|(tag_source, _)| tag_source != leading_tag_source);
15860                if let Some(index) = first_mismatch {
15861                    templates_with_tags.truncate(index);
15862                }
15863            }
15864
15865            templates_with_tags
15866        })
15867    }
15868
15869    pub fn move_to_enclosing_bracket(
15870        &mut self,
15871        _: &MoveToEnclosingBracket,
15872        window: &mut Window,
15873        cx: &mut Context<Self>,
15874    ) {
15875        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15876        self.change_selections(Default::default(), window, cx, |s| {
15877            s.move_offsets_with(|snapshot, selection| {
15878                let Some(enclosing_bracket_ranges) =
15879                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
15880                else {
15881                    return;
15882                };
15883
15884                let mut best_length = usize::MAX;
15885                let mut best_inside = false;
15886                let mut best_in_bracket_range = false;
15887                let mut best_destination = None;
15888                for (open, close) in enclosing_bracket_ranges {
15889                    let close = close.to_inclusive();
15890                    let length = close.end() - open.start;
15891                    let inside = selection.start >= open.end && selection.end <= *close.start();
15892                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
15893                        || close.contains(&selection.head());
15894
15895                    // If best is next to a bracket and current isn't, skip
15896                    if !in_bracket_range && best_in_bracket_range {
15897                        continue;
15898                    }
15899
15900                    // Prefer smaller lengths unless best is inside and current isn't
15901                    if length > best_length && (best_inside || !inside) {
15902                        continue;
15903                    }
15904
15905                    best_length = length;
15906                    best_inside = inside;
15907                    best_in_bracket_range = in_bracket_range;
15908                    best_destination = Some(
15909                        if close.contains(&selection.start) && close.contains(&selection.end) {
15910                            if inside { open.end } else { open.start }
15911                        } else if inside {
15912                            *close.start()
15913                        } else {
15914                            *close.end()
15915                        },
15916                    );
15917                }
15918
15919                if let Some(destination) = best_destination {
15920                    selection.collapse_to(destination, SelectionGoal::None);
15921                }
15922            })
15923        });
15924    }
15925
15926    pub fn undo_selection(
15927        &mut self,
15928        _: &UndoSelection,
15929        window: &mut Window,
15930        cx: &mut Context<Self>,
15931    ) {
15932        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15933        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
15934            self.selection_history.mode = SelectionHistoryMode::Undoing;
15935            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15936                this.end_selection(window, cx);
15937                this.change_selections(
15938                    SelectionEffects::scroll(Autoscroll::newest()),
15939                    window,
15940                    cx,
15941                    |s| s.select_anchors(entry.selections.to_vec()),
15942                );
15943            });
15944            self.selection_history.mode = SelectionHistoryMode::Normal;
15945
15946            self.select_next_state = entry.select_next_state;
15947            self.select_prev_state = entry.select_prev_state;
15948            self.add_selections_state = entry.add_selections_state;
15949        }
15950    }
15951
15952    pub fn redo_selection(
15953        &mut self,
15954        _: &RedoSelection,
15955        window: &mut Window,
15956        cx: &mut Context<Self>,
15957    ) {
15958        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15959        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
15960            self.selection_history.mode = SelectionHistoryMode::Redoing;
15961            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15962                this.end_selection(window, cx);
15963                this.change_selections(
15964                    SelectionEffects::scroll(Autoscroll::newest()),
15965                    window,
15966                    cx,
15967                    |s| s.select_anchors(entry.selections.to_vec()),
15968                );
15969            });
15970            self.selection_history.mode = SelectionHistoryMode::Normal;
15971
15972            self.select_next_state = entry.select_next_state;
15973            self.select_prev_state = entry.select_prev_state;
15974            self.add_selections_state = entry.add_selections_state;
15975        }
15976    }
15977
15978    pub fn expand_excerpts(
15979        &mut self,
15980        action: &ExpandExcerpts,
15981        _: &mut Window,
15982        cx: &mut Context<Self>,
15983    ) {
15984        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
15985    }
15986
15987    pub fn expand_excerpts_down(
15988        &mut self,
15989        action: &ExpandExcerptsDown,
15990        _: &mut Window,
15991        cx: &mut Context<Self>,
15992    ) {
15993        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
15994    }
15995
15996    pub fn expand_excerpts_up(
15997        &mut self,
15998        action: &ExpandExcerptsUp,
15999        _: &mut Window,
16000        cx: &mut Context<Self>,
16001    ) {
16002        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
16003    }
16004
16005    pub fn expand_excerpts_for_direction(
16006        &mut self,
16007        lines: u32,
16008        direction: ExpandExcerptDirection,
16009
16010        cx: &mut Context<Self>,
16011    ) {
16012        let selections = self.selections.disjoint_anchors_arc();
16013
16014        let lines = if lines == 0 {
16015            EditorSettings::get_global(cx).expand_excerpt_lines
16016        } else {
16017            lines
16018        };
16019
16020        self.buffer.update(cx, |buffer, cx| {
16021            let snapshot = buffer.snapshot(cx);
16022            let mut excerpt_ids = selections
16023                .iter()
16024                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
16025                .collect::<Vec<_>>();
16026            excerpt_ids.sort();
16027            excerpt_ids.dedup();
16028            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
16029        })
16030    }
16031
16032    pub fn expand_excerpt(
16033        &mut self,
16034        excerpt: ExcerptId,
16035        direction: ExpandExcerptDirection,
16036        window: &mut Window,
16037        cx: &mut Context<Self>,
16038    ) {
16039        let current_scroll_position = self.scroll_position(cx);
16040        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
16041        let mut should_scroll_up = false;
16042
16043        if direction == ExpandExcerptDirection::Down {
16044            let multi_buffer = self.buffer.read(cx);
16045            let snapshot = multi_buffer.snapshot(cx);
16046            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
16047                && let Some(buffer) = multi_buffer.buffer(buffer_id)
16048                && let Some(excerpt_range) = snapshot.context_range_for_excerpt(excerpt)
16049            {
16050                let buffer_snapshot = buffer.read(cx).snapshot();
16051                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
16052                let last_row = buffer_snapshot.max_point().row;
16053                let lines_below = last_row.saturating_sub(excerpt_end_row);
16054                should_scroll_up = lines_below >= lines_to_expand;
16055            }
16056        }
16057
16058        self.buffer.update(cx, |buffer, cx| {
16059            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
16060        });
16061
16062        if should_scroll_up {
16063            let new_scroll_position =
16064                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as ScrollOffset);
16065            self.set_scroll_position(new_scroll_position, window, cx);
16066        }
16067    }
16068
16069    pub fn go_to_singleton_buffer_point(
16070        &mut self,
16071        point: Point,
16072        window: &mut Window,
16073        cx: &mut Context<Self>,
16074    ) {
16075        self.go_to_singleton_buffer_range(point..point, window, cx);
16076    }
16077
16078    pub fn go_to_singleton_buffer_range(
16079        &mut self,
16080        range: Range<Point>,
16081        window: &mut Window,
16082        cx: &mut Context<Self>,
16083    ) {
16084        let multibuffer = self.buffer().read(cx);
16085        let Some(buffer) = multibuffer.as_singleton() else {
16086            return;
16087        };
16088        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
16089            return;
16090        };
16091        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
16092            return;
16093        };
16094        self.change_selections(
16095            SelectionEffects::default().nav_history(true),
16096            window,
16097            cx,
16098            |s| s.select_anchor_ranges([start..end]),
16099        );
16100    }
16101
16102    pub fn go_to_diagnostic(
16103        &mut self,
16104        action: &GoToDiagnostic,
16105        window: &mut Window,
16106        cx: &mut Context<Self>,
16107    ) {
16108        if !self.diagnostics_enabled() {
16109            return;
16110        }
16111        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16112        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
16113    }
16114
16115    pub fn go_to_prev_diagnostic(
16116        &mut self,
16117        action: &GoToPreviousDiagnostic,
16118        window: &mut Window,
16119        cx: &mut Context<Self>,
16120    ) {
16121        if !self.diagnostics_enabled() {
16122            return;
16123        }
16124        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16125        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
16126    }
16127
16128    pub fn go_to_diagnostic_impl(
16129        &mut self,
16130        direction: Direction,
16131        severity: GoToDiagnosticSeverityFilter,
16132        window: &mut Window,
16133        cx: &mut Context<Self>,
16134    ) {
16135        let buffer = self.buffer.read(cx).snapshot(cx);
16136        let selection = self.selections.newest::<usize>(&self.display_snapshot(cx));
16137
16138        let mut active_group_id = None;
16139        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
16140            && active_group.active_range.start.to_offset(&buffer) == selection.start
16141        {
16142            active_group_id = Some(active_group.group_id);
16143        }
16144
16145        fn filtered<'a>(
16146            snapshot: EditorSnapshot,
16147            severity: GoToDiagnosticSeverityFilter,
16148            diagnostics: impl Iterator<Item = DiagnosticEntryRef<'a, usize>>,
16149        ) -> impl Iterator<Item = DiagnosticEntryRef<'a, usize>> {
16150            diagnostics
16151                .filter(move |entry| severity.matches(entry.diagnostic.severity))
16152                .filter(|entry| entry.range.start != entry.range.end)
16153                .filter(|entry| !entry.diagnostic.is_unnecessary)
16154                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
16155        }
16156
16157        let snapshot = self.snapshot(window, cx);
16158        let before = filtered(
16159            snapshot.clone(),
16160            severity,
16161            buffer
16162                .diagnostics_in_range(0..selection.start)
16163                .filter(|entry| entry.range.start <= selection.start),
16164        );
16165        let after = filtered(
16166            snapshot,
16167            severity,
16168            buffer
16169                .diagnostics_in_range(selection.start..buffer.len())
16170                .filter(|entry| entry.range.start >= selection.start),
16171        );
16172
16173        let mut found: Option<DiagnosticEntryRef<usize>> = None;
16174        if direction == Direction::Prev {
16175            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
16176            {
16177                for diagnostic in prev_diagnostics.into_iter().rev() {
16178                    if diagnostic.range.start != selection.start
16179                        || active_group_id
16180                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
16181                    {
16182                        found = Some(diagnostic);
16183                        break 'outer;
16184                    }
16185                }
16186            }
16187        } else {
16188            for diagnostic in after.chain(before) {
16189                if diagnostic.range.start != selection.start
16190                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
16191                {
16192                    found = Some(diagnostic);
16193                    break;
16194                }
16195            }
16196        }
16197        let Some(next_diagnostic) = found else {
16198            return;
16199        };
16200
16201        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
16202        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
16203            return;
16204        };
16205        self.change_selections(Default::default(), window, cx, |s| {
16206            s.select_ranges(vec![
16207                next_diagnostic.range.start..next_diagnostic.range.start,
16208            ])
16209        });
16210        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
16211        self.refresh_edit_prediction(false, true, window, cx);
16212    }
16213
16214    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
16215        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16216        let snapshot = self.snapshot(window, cx);
16217        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
16218        self.go_to_hunk_before_or_after_position(
16219            &snapshot,
16220            selection.head(),
16221            Direction::Next,
16222            window,
16223            cx,
16224        );
16225    }
16226
16227    pub fn go_to_hunk_before_or_after_position(
16228        &mut self,
16229        snapshot: &EditorSnapshot,
16230        position: Point,
16231        direction: Direction,
16232        window: &mut Window,
16233        cx: &mut Context<Editor>,
16234    ) {
16235        let row = if direction == Direction::Next {
16236            self.hunk_after_position(snapshot, position)
16237                .map(|hunk| hunk.row_range.start)
16238        } else {
16239            self.hunk_before_position(snapshot, position)
16240        };
16241
16242        if let Some(row) = row {
16243            let destination = Point::new(row.0, 0);
16244            let autoscroll = Autoscroll::center();
16245
16246            self.unfold_ranges(&[destination..destination], false, false, cx);
16247            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16248                s.select_ranges([destination..destination]);
16249            });
16250        }
16251    }
16252
16253    fn hunk_after_position(
16254        &mut self,
16255        snapshot: &EditorSnapshot,
16256        position: Point,
16257    ) -> Option<MultiBufferDiffHunk> {
16258        snapshot
16259            .buffer_snapshot()
16260            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
16261            .find(|hunk| hunk.row_range.start.0 > position.row)
16262            .or_else(|| {
16263                snapshot
16264                    .buffer_snapshot()
16265                    .diff_hunks_in_range(Point::zero()..position)
16266                    .find(|hunk| hunk.row_range.end.0 < position.row)
16267            })
16268    }
16269
16270    fn go_to_prev_hunk(
16271        &mut self,
16272        _: &GoToPreviousHunk,
16273        window: &mut Window,
16274        cx: &mut Context<Self>,
16275    ) {
16276        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16277        let snapshot = self.snapshot(window, cx);
16278        let selection = self.selections.newest::<Point>(&snapshot.display_snapshot);
16279        self.go_to_hunk_before_or_after_position(
16280            &snapshot,
16281            selection.head(),
16282            Direction::Prev,
16283            window,
16284            cx,
16285        );
16286    }
16287
16288    fn hunk_before_position(
16289        &mut self,
16290        snapshot: &EditorSnapshot,
16291        position: Point,
16292    ) -> Option<MultiBufferRow> {
16293        snapshot
16294            .buffer_snapshot()
16295            .diff_hunk_before(position)
16296            .or_else(|| snapshot.buffer_snapshot().diff_hunk_before(Point::MAX))
16297    }
16298
16299    fn go_to_next_change(
16300        &mut self,
16301        _: &GoToNextChange,
16302        window: &mut Window,
16303        cx: &mut Context<Self>,
16304    ) {
16305        if let Some(selections) = self
16306            .change_list
16307            .next_change(1, Direction::Next)
16308            .map(|s| s.to_vec())
16309        {
16310            self.change_selections(Default::default(), window, cx, |s| {
16311                let map = s.display_map();
16312                s.select_display_ranges(selections.iter().map(|a| {
16313                    let point = a.to_display_point(&map);
16314                    point..point
16315                }))
16316            })
16317        }
16318    }
16319
16320    fn go_to_previous_change(
16321        &mut self,
16322        _: &GoToPreviousChange,
16323        window: &mut Window,
16324        cx: &mut Context<Self>,
16325    ) {
16326        if let Some(selections) = self
16327            .change_list
16328            .next_change(1, Direction::Prev)
16329            .map(|s| s.to_vec())
16330        {
16331            self.change_selections(Default::default(), window, cx, |s| {
16332                let map = s.display_map();
16333                s.select_display_ranges(selections.iter().map(|a| {
16334                    let point = a.to_display_point(&map);
16335                    point..point
16336                }))
16337            })
16338        }
16339    }
16340
16341    pub fn go_to_next_document_highlight(
16342        &mut self,
16343        _: &GoToNextDocumentHighlight,
16344        window: &mut Window,
16345        cx: &mut Context<Self>,
16346    ) {
16347        self.go_to_document_highlight_before_or_after_position(Direction::Next, window, cx);
16348    }
16349
16350    pub fn go_to_prev_document_highlight(
16351        &mut self,
16352        _: &GoToPreviousDocumentHighlight,
16353        window: &mut Window,
16354        cx: &mut Context<Self>,
16355    ) {
16356        self.go_to_document_highlight_before_or_after_position(Direction::Prev, window, cx);
16357    }
16358
16359    pub fn go_to_document_highlight_before_or_after_position(
16360        &mut self,
16361        direction: Direction,
16362        window: &mut Window,
16363        cx: &mut Context<Editor>,
16364    ) {
16365        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16366        let snapshot = self.snapshot(window, cx);
16367        let buffer = &snapshot.buffer_snapshot();
16368        let position = self
16369            .selections
16370            .newest::<Point>(&snapshot.display_snapshot)
16371            .head();
16372        let anchor_position = buffer.anchor_after(position);
16373
16374        // Get all document highlights (both read and write)
16375        let mut all_highlights = Vec::new();
16376
16377        if let Some((_, read_highlights)) = self
16378            .background_highlights
16379            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
16380        {
16381            all_highlights.extend(read_highlights.iter());
16382        }
16383
16384        if let Some((_, write_highlights)) = self
16385            .background_highlights
16386            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
16387        {
16388            all_highlights.extend(write_highlights.iter());
16389        }
16390
16391        if all_highlights.is_empty() {
16392            return;
16393        }
16394
16395        // Sort highlights by position
16396        all_highlights.sort_by(|a, b| a.start.cmp(&b.start, buffer));
16397
16398        let target_highlight = match direction {
16399            Direction::Next => {
16400                // Find the first highlight after the current position
16401                all_highlights
16402                    .iter()
16403                    .find(|highlight| highlight.start.cmp(&anchor_position, buffer).is_gt())
16404            }
16405            Direction::Prev => {
16406                // Find the last highlight before the current position
16407                all_highlights
16408                    .iter()
16409                    .rev()
16410                    .find(|highlight| highlight.end.cmp(&anchor_position, buffer).is_lt())
16411            }
16412        };
16413
16414        if let Some(highlight) = target_highlight {
16415            let destination = highlight.start.to_point(buffer);
16416            let autoscroll = Autoscroll::center();
16417
16418            self.unfold_ranges(&[destination..destination], false, false, cx);
16419            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16420                s.select_ranges([destination..destination]);
16421            });
16422        }
16423    }
16424
16425    fn go_to_line<T: 'static>(
16426        &mut self,
16427        position: Anchor,
16428        highlight_color: Option<Hsla>,
16429        window: &mut Window,
16430        cx: &mut Context<Self>,
16431    ) {
16432        let snapshot = self.snapshot(window, cx).display_snapshot;
16433        let position = position.to_point(&snapshot.buffer_snapshot());
16434        let start = snapshot
16435            .buffer_snapshot()
16436            .clip_point(Point::new(position.row, 0), Bias::Left);
16437        let end = start + Point::new(1, 0);
16438        let start = snapshot.buffer_snapshot().anchor_before(start);
16439        let end = snapshot.buffer_snapshot().anchor_before(end);
16440
16441        self.highlight_rows::<T>(
16442            start..end,
16443            highlight_color
16444                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
16445            Default::default(),
16446            cx,
16447        );
16448
16449        if self.buffer.read(cx).is_singleton() {
16450            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
16451        }
16452    }
16453
16454    pub fn go_to_definition(
16455        &mut self,
16456        _: &GoToDefinition,
16457        window: &mut Window,
16458        cx: &mut Context<Self>,
16459    ) -> Task<Result<Navigated>> {
16460        let definition =
16461            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
16462        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
16463        cx.spawn_in(window, async move |editor, cx| {
16464            if definition.await? == Navigated::Yes {
16465                return Ok(Navigated::Yes);
16466            }
16467            match fallback_strategy {
16468                GoToDefinitionFallback::None => Ok(Navigated::No),
16469                GoToDefinitionFallback::FindAllReferences => {
16470                    match editor.update_in(cx, |editor, window, cx| {
16471                        editor.find_all_references(&FindAllReferences, window, cx)
16472                    })? {
16473                        Some(references) => references.await,
16474                        None => Ok(Navigated::No),
16475                    }
16476                }
16477            }
16478        })
16479    }
16480
16481    pub fn go_to_declaration(
16482        &mut self,
16483        _: &GoToDeclaration,
16484        window: &mut Window,
16485        cx: &mut Context<Self>,
16486    ) -> Task<Result<Navigated>> {
16487        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
16488    }
16489
16490    pub fn go_to_declaration_split(
16491        &mut self,
16492        _: &GoToDeclaration,
16493        window: &mut Window,
16494        cx: &mut Context<Self>,
16495    ) -> Task<Result<Navigated>> {
16496        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
16497    }
16498
16499    pub fn go_to_implementation(
16500        &mut self,
16501        _: &GoToImplementation,
16502        window: &mut Window,
16503        cx: &mut Context<Self>,
16504    ) -> Task<Result<Navigated>> {
16505        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
16506    }
16507
16508    pub fn go_to_implementation_split(
16509        &mut self,
16510        _: &GoToImplementationSplit,
16511        window: &mut Window,
16512        cx: &mut Context<Self>,
16513    ) -> Task<Result<Navigated>> {
16514        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
16515    }
16516
16517    pub fn go_to_type_definition(
16518        &mut self,
16519        _: &GoToTypeDefinition,
16520        window: &mut Window,
16521        cx: &mut Context<Self>,
16522    ) -> Task<Result<Navigated>> {
16523        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
16524    }
16525
16526    pub fn go_to_definition_split(
16527        &mut self,
16528        _: &GoToDefinitionSplit,
16529        window: &mut Window,
16530        cx: &mut Context<Self>,
16531    ) -> Task<Result<Navigated>> {
16532        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
16533    }
16534
16535    pub fn go_to_type_definition_split(
16536        &mut self,
16537        _: &GoToTypeDefinitionSplit,
16538        window: &mut Window,
16539        cx: &mut Context<Self>,
16540    ) -> Task<Result<Navigated>> {
16541        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
16542    }
16543
16544    fn go_to_definition_of_kind(
16545        &mut self,
16546        kind: GotoDefinitionKind,
16547        split: bool,
16548        window: &mut Window,
16549        cx: &mut Context<Self>,
16550    ) -> Task<Result<Navigated>> {
16551        let Some(provider) = self.semantics_provider.clone() else {
16552            return Task::ready(Ok(Navigated::No));
16553        };
16554        let head = self
16555            .selections
16556            .newest::<usize>(&self.display_snapshot(cx))
16557            .head();
16558        let buffer = self.buffer.read(cx);
16559        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
16560            return Task::ready(Ok(Navigated::No));
16561        };
16562        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
16563            return Task::ready(Ok(Navigated::No));
16564        };
16565
16566        cx.spawn_in(window, async move |editor, cx| {
16567            let Some(definitions) = definitions.await? else {
16568                return Ok(Navigated::No);
16569            };
16570            let navigated = editor
16571                .update_in(cx, |editor, window, cx| {
16572                    editor.navigate_to_hover_links(
16573                        Some(kind),
16574                        definitions
16575                            .into_iter()
16576                            .filter(|location| {
16577                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
16578                            })
16579                            .map(HoverLink::Text)
16580                            .collect::<Vec<_>>(),
16581                        split,
16582                        window,
16583                        cx,
16584                    )
16585                })?
16586                .await?;
16587            anyhow::Ok(navigated)
16588        })
16589    }
16590
16591    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
16592        let selection = self.selections.newest_anchor();
16593        let head = selection.head();
16594        let tail = selection.tail();
16595
16596        let Some((buffer, start_position)) =
16597            self.buffer.read(cx).text_anchor_for_position(head, cx)
16598        else {
16599            return;
16600        };
16601
16602        let end_position = if head != tail {
16603            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
16604                return;
16605            };
16606            Some(pos)
16607        } else {
16608            None
16609        };
16610
16611        let url_finder = cx.spawn_in(window, async move |_editor, cx| {
16612            let url = if let Some(end_pos) = end_position {
16613                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
16614            } else {
16615                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
16616            };
16617
16618            if let Some(url) = url {
16619                cx.update(|window, cx| {
16620                    if parse_zed_link(&url, cx).is_some() {
16621                        window.dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
16622                    } else {
16623                        cx.open_url(&url);
16624                    }
16625                })?;
16626            }
16627
16628            anyhow::Ok(())
16629        });
16630
16631        url_finder.detach();
16632    }
16633
16634    pub fn open_selected_filename(
16635        &mut self,
16636        _: &OpenSelectedFilename,
16637        window: &mut Window,
16638        cx: &mut Context<Self>,
16639    ) {
16640        let Some(workspace) = self.workspace() else {
16641            return;
16642        };
16643
16644        let position = self.selections.newest_anchor().head();
16645
16646        let Some((buffer, buffer_position)) =
16647            self.buffer.read(cx).text_anchor_for_position(position, cx)
16648        else {
16649            return;
16650        };
16651
16652        let project = self.project.clone();
16653
16654        cx.spawn_in(window, async move |_, cx| {
16655            let result = find_file(&buffer, project, buffer_position, cx).await;
16656
16657            if let Some((_, path)) = result {
16658                workspace
16659                    .update_in(cx, |workspace, window, cx| {
16660                        workspace.open_resolved_path(path, window, cx)
16661                    })?
16662                    .await?;
16663            }
16664            anyhow::Ok(())
16665        })
16666        .detach();
16667    }
16668
16669    pub(crate) fn navigate_to_hover_links(
16670        &mut self,
16671        kind: Option<GotoDefinitionKind>,
16672        definitions: Vec<HoverLink>,
16673        split: bool,
16674        window: &mut Window,
16675        cx: &mut Context<Editor>,
16676    ) -> Task<Result<Navigated>> {
16677        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
16678        let mut first_url_or_file = None;
16679        let definitions: Vec<_> = definitions
16680            .into_iter()
16681            .filter_map(|def| match def {
16682                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
16683                HoverLink::InlayHint(lsp_location, server_id) => {
16684                    let computation =
16685                        self.compute_target_location(lsp_location, server_id, window, cx);
16686                    Some(cx.background_spawn(computation))
16687                }
16688                HoverLink::Url(url) => {
16689                    first_url_or_file = Some(Either::Left(url));
16690                    None
16691                }
16692                HoverLink::File(path) => {
16693                    first_url_or_file = Some(Either::Right(path));
16694                    None
16695                }
16696            })
16697            .collect();
16698
16699        let workspace = self.workspace();
16700
16701        cx.spawn_in(window, async move |editor, cx| {
16702            let locations: Vec<Location> = future::join_all(definitions)
16703                .await
16704                .into_iter()
16705                .filter_map(|location| location.transpose())
16706                .collect::<Result<_>>()
16707                .context("location tasks")?;
16708            let mut locations = cx.update(|_, cx| {
16709                locations
16710                    .into_iter()
16711                    .map(|location| {
16712                        let buffer = location.buffer.read(cx);
16713                        (location.buffer, location.range.to_point(buffer))
16714                    })
16715                    .into_group_map()
16716            })?;
16717            let mut num_locations = 0;
16718            for ranges in locations.values_mut() {
16719                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
16720                ranges.dedup();
16721                num_locations += ranges.len();
16722            }
16723
16724            if num_locations > 1 {
16725                let Some(workspace) = workspace else {
16726                    return Ok(Navigated::No);
16727                };
16728
16729                let tab_kind = match kind {
16730                    Some(GotoDefinitionKind::Implementation) => "Implementations",
16731                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
16732                    Some(GotoDefinitionKind::Declaration) => "Declarations",
16733                    Some(GotoDefinitionKind::Type) => "Types",
16734                };
16735                let title = editor
16736                    .update_in(cx, |_, _, cx| {
16737                        let target = locations
16738                            .iter()
16739                            .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
16740                            .map(|(buffer, location)| {
16741                                buffer
16742                                    .read(cx)
16743                                    .text_for_range(location.clone())
16744                                    .collect::<String>()
16745                            })
16746                            .filter(|text| !text.contains('\n'))
16747                            .unique()
16748                            .take(3)
16749                            .join(", ");
16750                        if target.is_empty() {
16751                            tab_kind.to_owned()
16752                        } else {
16753                            format!("{tab_kind} for {target}")
16754                        }
16755                    })
16756                    .context("buffer title")?;
16757
16758                let opened = workspace
16759                    .update_in(cx, |workspace, window, cx| {
16760                        Self::open_locations_in_multibuffer(
16761                            workspace,
16762                            locations,
16763                            title,
16764                            split,
16765                            MultibufferSelectionMode::First,
16766                            window,
16767                            cx,
16768                        )
16769                    })
16770                    .is_ok();
16771
16772                anyhow::Ok(Navigated::from_bool(opened))
16773            } else if num_locations == 0 {
16774                // If there is one url or file, open it directly
16775                match first_url_or_file {
16776                    Some(Either::Left(url)) => {
16777                        cx.update(|_, cx| cx.open_url(&url))?;
16778                        Ok(Navigated::Yes)
16779                    }
16780                    Some(Either::Right(path)) => {
16781                        let Some(workspace) = workspace else {
16782                            return Ok(Navigated::No);
16783                        };
16784
16785                        workspace
16786                            .update_in(cx, |workspace, window, cx| {
16787                                workspace.open_resolved_path(path, window, cx)
16788                            })?
16789                            .await?;
16790                        Ok(Navigated::Yes)
16791                    }
16792                    None => Ok(Navigated::No),
16793                }
16794            } else {
16795                let Some(workspace) = workspace else {
16796                    return Ok(Navigated::No);
16797                };
16798
16799                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
16800                let target_range = target_ranges.first().unwrap().clone();
16801
16802                editor.update_in(cx, |editor, window, cx| {
16803                    let range = target_range.to_point(target_buffer.read(cx));
16804                    let range = editor.range_for_match(&range);
16805                    let range = collapse_multiline_range(range);
16806
16807                    if !split
16808                        && Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref()
16809                    {
16810                        editor.go_to_singleton_buffer_range(range, window, cx);
16811                    } else {
16812                        let pane = workspace.read(cx).active_pane().clone();
16813                        window.defer(cx, move |window, cx| {
16814                            let target_editor: Entity<Self> =
16815                                workspace.update(cx, |workspace, cx| {
16816                                    let pane = if split {
16817                                        workspace.adjacent_pane(window, cx)
16818                                    } else {
16819                                        workspace.active_pane().clone()
16820                                    };
16821
16822                                    workspace.open_project_item(
16823                                        pane,
16824                                        target_buffer.clone(),
16825                                        true,
16826                                        true,
16827                                        window,
16828                                        cx,
16829                                    )
16830                                });
16831                            target_editor.update(cx, |target_editor, cx| {
16832                                // When selecting a definition in a different buffer, disable the nav history
16833                                // to avoid creating a history entry at the previous cursor location.
16834                                pane.update(cx, |pane, _| pane.disable_history());
16835                                target_editor.go_to_singleton_buffer_range(range, window, cx);
16836                                pane.update(cx, |pane, _| pane.enable_history());
16837                            });
16838                        });
16839                    }
16840                    Navigated::Yes
16841                })
16842            }
16843        })
16844    }
16845
16846    fn compute_target_location(
16847        &self,
16848        lsp_location: lsp::Location,
16849        server_id: LanguageServerId,
16850        window: &mut Window,
16851        cx: &mut Context<Self>,
16852    ) -> Task<anyhow::Result<Option<Location>>> {
16853        let Some(project) = self.project.clone() else {
16854            return Task::ready(Ok(None));
16855        };
16856
16857        cx.spawn_in(window, async move |editor, cx| {
16858            let location_task = editor.update(cx, |_, cx| {
16859                project.update(cx, |project, cx| {
16860                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
16861                })
16862            })?;
16863            let location = Some({
16864                let target_buffer_handle = location_task.await.context("open local buffer")?;
16865                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
16866                    let target_start = target_buffer
16867                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
16868                    let target_end = target_buffer
16869                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
16870                    target_buffer.anchor_after(target_start)
16871                        ..target_buffer.anchor_before(target_end)
16872                })?;
16873                Location {
16874                    buffer: target_buffer_handle,
16875                    range,
16876                }
16877            });
16878            Ok(location)
16879        })
16880    }
16881
16882    pub fn find_all_references(
16883        &mut self,
16884        _: &FindAllReferences,
16885        window: &mut Window,
16886        cx: &mut Context<Self>,
16887    ) -> Option<Task<Result<Navigated>>> {
16888        let selection = self.selections.newest::<usize>(&self.display_snapshot(cx));
16889        let multi_buffer = self.buffer.read(cx);
16890        let head = selection.head();
16891
16892        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
16893        let head_anchor = multi_buffer_snapshot.anchor_at(
16894            head,
16895            if head < selection.tail() {
16896                Bias::Right
16897            } else {
16898                Bias::Left
16899            },
16900        );
16901
16902        match self
16903            .find_all_references_task_sources
16904            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16905        {
16906            Ok(_) => {
16907                log::info!(
16908                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
16909                );
16910                return None;
16911            }
16912            Err(i) => {
16913                self.find_all_references_task_sources.insert(i, head_anchor);
16914            }
16915        }
16916
16917        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
16918        let workspace = self.workspace()?;
16919        let project = workspace.read(cx).project().clone();
16920        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
16921        Some(cx.spawn_in(window, async move |editor, cx| {
16922            let _cleanup = cx.on_drop(&editor, move |editor, _| {
16923                if let Ok(i) = editor
16924                    .find_all_references_task_sources
16925                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16926                {
16927                    editor.find_all_references_task_sources.remove(i);
16928                }
16929            });
16930
16931            let Some(locations) = references.await? else {
16932                return anyhow::Ok(Navigated::No);
16933            };
16934            let mut locations = cx.update(|_, cx| {
16935                locations
16936                    .into_iter()
16937                    .map(|location| {
16938                        let buffer = location.buffer.read(cx);
16939                        (location.buffer, location.range.to_point(buffer))
16940                    })
16941                    .into_group_map()
16942            })?;
16943            if locations.is_empty() {
16944                return anyhow::Ok(Navigated::No);
16945            }
16946            for ranges in locations.values_mut() {
16947                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
16948                ranges.dedup();
16949            }
16950
16951            workspace.update_in(cx, |workspace, window, cx| {
16952                let target = locations
16953                    .iter()
16954                    .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
16955                    .map(|(buffer, location)| {
16956                        buffer
16957                            .read(cx)
16958                            .text_for_range(location.clone())
16959                            .collect::<String>()
16960                    })
16961                    .filter(|text| !text.contains('\n'))
16962                    .unique()
16963                    .take(3)
16964                    .join(", ");
16965                let title = if target.is_empty() {
16966                    "References".to_owned()
16967                } else {
16968                    format!("References to {target}")
16969                };
16970                Self::open_locations_in_multibuffer(
16971                    workspace,
16972                    locations,
16973                    title,
16974                    false,
16975                    MultibufferSelectionMode::First,
16976                    window,
16977                    cx,
16978                );
16979                Navigated::Yes
16980            })
16981        }))
16982    }
16983
16984    /// Opens a multibuffer with the given project locations in it
16985    pub fn open_locations_in_multibuffer(
16986        workspace: &mut Workspace,
16987        locations: std::collections::HashMap<Entity<Buffer>, Vec<Range<Point>>>,
16988        title: String,
16989        split: bool,
16990        multibuffer_selection_mode: MultibufferSelectionMode,
16991        window: &mut Window,
16992        cx: &mut Context<Workspace>,
16993    ) {
16994        if locations.is_empty() {
16995            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
16996            return;
16997        }
16998
16999        let capability = workspace.project().read(cx).capability();
17000        let mut ranges = <Vec<Range<Anchor>>>::new();
17001
17002        // a key to find existing multibuffer editors with the same set of locations
17003        // to prevent us from opening more and more multibuffer tabs for searches and the like
17004        let mut key = (title.clone(), vec![]);
17005        let excerpt_buffer = cx.new(|cx| {
17006            let key = &mut key.1;
17007            let mut multibuffer = MultiBuffer::new(capability);
17008            for (buffer, mut ranges_for_buffer) in locations {
17009                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
17010                key.push((buffer.read(cx).remote_id(), ranges_for_buffer.clone()));
17011                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
17012                    PathKey::for_buffer(&buffer, cx),
17013                    buffer.clone(),
17014                    ranges_for_buffer,
17015                    multibuffer_context_lines(cx),
17016                    cx,
17017                );
17018                ranges.extend(new_ranges)
17019            }
17020
17021            multibuffer.with_title(title)
17022        });
17023        let existing = workspace.active_pane().update(cx, |pane, cx| {
17024            pane.items()
17025                .filter_map(|item| item.downcast::<Editor>())
17026                .find(|editor| {
17027                    editor
17028                        .read(cx)
17029                        .lookup_key
17030                        .as_ref()
17031                        .and_then(|it| {
17032                            it.downcast_ref::<(String, Vec<(BufferId, Vec<Range<Point>>)>)>()
17033                        })
17034                        .is_some_and(|it| *it == key)
17035                })
17036        });
17037        let editor = existing.unwrap_or_else(|| {
17038            cx.new(|cx| {
17039                let mut editor = Editor::for_multibuffer(
17040                    excerpt_buffer,
17041                    Some(workspace.project().clone()),
17042                    window,
17043                    cx,
17044                );
17045                editor.lookup_key = Some(Box::new(key));
17046                editor
17047            })
17048        });
17049        editor.update(cx, |editor, cx| match multibuffer_selection_mode {
17050            MultibufferSelectionMode::First => {
17051                if let Some(first_range) = ranges.first() {
17052                    editor.change_selections(
17053                        SelectionEffects::no_scroll(),
17054                        window,
17055                        cx,
17056                        |selections| {
17057                            selections.clear_disjoint();
17058                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
17059                        },
17060                    );
17061                }
17062                editor.highlight_background::<Self>(
17063                    &ranges,
17064                    |theme| theme.colors().editor_highlighted_line_background,
17065                    cx,
17066                );
17067            }
17068            MultibufferSelectionMode::All => {
17069                editor.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
17070                    selections.clear_disjoint();
17071                    selections.select_anchor_ranges(ranges);
17072                });
17073            }
17074        });
17075
17076        let item = Box::new(editor);
17077        let item_id = item.item_id();
17078
17079        if split {
17080            let pane = workspace.adjacent_pane(window, cx);
17081            workspace.add_item(pane, item, None, true, true, window, cx);
17082        } else if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
17083            let (preview_item_id, preview_item_idx) =
17084                workspace.active_pane().read_with(cx, |pane, _| {
17085                    (pane.preview_item_id(), pane.preview_item_idx())
17086                });
17087
17088            workspace.add_item_to_active_pane(item, preview_item_idx, true, window, cx);
17089
17090            if let Some(preview_item_id) = preview_item_id {
17091                workspace.active_pane().update(cx, |pane, cx| {
17092                    pane.remove_item(preview_item_id, false, false, window, cx);
17093                });
17094            }
17095        } else {
17096            workspace.add_item_to_active_pane(item, None, true, window, cx);
17097        }
17098        workspace.active_pane().update(cx, |pane, cx| {
17099            pane.set_preview_item_id(Some(item_id), cx);
17100        });
17101    }
17102
17103    pub fn rename(
17104        &mut self,
17105        _: &Rename,
17106        window: &mut Window,
17107        cx: &mut Context<Self>,
17108    ) -> Option<Task<Result<()>>> {
17109        use language::ToOffset as _;
17110
17111        let provider = self.semantics_provider.clone()?;
17112        let selection = self.selections.newest_anchor().clone();
17113        let (cursor_buffer, cursor_buffer_position) = self
17114            .buffer
17115            .read(cx)
17116            .text_anchor_for_position(selection.head(), cx)?;
17117        let (tail_buffer, cursor_buffer_position_end) = self
17118            .buffer
17119            .read(cx)
17120            .text_anchor_for_position(selection.tail(), cx)?;
17121        if tail_buffer != cursor_buffer {
17122            return None;
17123        }
17124
17125        let snapshot = cursor_buffer.read(cx).snapshot();
17126        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
17127        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
17128        let prepare_rename = provider
17129            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
17130            .unwrap_or_else(|| Task::ready(Ok(None)));
17131        drop(snapshot);
17132
17133        Some(cx.spawn_in(window, async move |this, cx| {
17134            let rename_range = if let Some(range) = prepare_rename.await? {
17135                Some(range)
17136            } else {
17137                this.update(cx, |this, cx| {
17138                    let buffer = this.buffer.read(cx).snapshot(cx);
17139                    let mut buffer_highlights = this
17140                        .document_highlights_for_position(selection.head(), &buffer)
17141                        .filter(|highlight| {
17142                            highlight.start.excerpt_id == selection.head().excerpt_id
17143                                && highlight.end.excerpt_id == selection.head().excerpt_id
17144                        });
17145                    buffer_highlights
17146                        .next()
17147                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
17148                })?
17149            };
17150            if let Some(rename_range) = rename_range {
17151                this.update_in(cx, |this, window, cx| {
17152                    let snapshot = cursor_buffer.read(cx).snapshot();
17153                    let rename_buffer_range = rename_range.to_offset(&snapshot);
17154                    let cursor_offset_in_rename_range =
17155                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
17156                    let cursor_offset_in_rename_range_end =
17157                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
17158
17159                    this.take_rename(false, window, cx);
17160                    let buffer = this.buffer.read(cx).read(cx);
17161                    let cursor_offset = selection.head().to_offset(&buffer);
17162                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
17163                    let rename_end = rename_start + rename_buffer_range.len();
17164                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
17165                    let mut old_highlight_id = None;
17166                    let old_name: Arc<str> = buffer
17167                        .chunks(rename_start..rename_end, true)
17168                        .map(|chunk| {
17169                            if old_highlight_id.is_none() {
17170                                old_highlight_id = chunk.syntax_highlight_id;
17171                            }
17172                            chunk.text
17173                        })
17174                        .collect::<String>()
17175                        .into();
17176
17177                    drop(buffer);
17178
17179                    // Position the selection in the rename editor so that it matches the current selection.
17180                    this.show_local_selections = false;
17181                    let rename_editor = cx.new(|cx| {
17182                        let mut editor = Editor::single_line(window, cx);
17183                        editor.buffer.update(cx, |buffer, cx| {
17184                            buffer.edit([(0..0, old_name.clone())], None, cx)
17185                        });
17186                        let rename_selection_range = match cursor_offset_in_rename_range
17187                            .cmp(&cursor_offset_in_rename_range_end)
17188                        {
17189                            Ordering::Equal => {
17190                                editor.select_all(&SelectAll, window, cx);
17191                                return editor;
17192                            }
17193                            Ordering::Less => {
17194                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
17195                            }
17196                            Ordering::Greater => {
17197                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
17198                            }
17199                        };
17200                        if rename_selection_range.end > old_name.len() {
17201                            editor.select_all(&SelectAll, window, cx);
17202                        } else {
17203                            editor.change_selections(Default::default(), window, cx, |s| {
17204                                s.select_ranges([rename_selection_range]);
17205                            });
17206                        }
17207                        editor
17208                    });
17209                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
17210                        if e == &EditorEvent::Focused {
17211                            cx.emit(EditorEvent::FocusedIn)
17212                        }
17213                    })
17214                    .detach();
17215
17216                    let write_highlights =
17217                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
17218                    let read_highlights =
17219                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
17220                    let ranges = write_highlights
17221                        .iter()
17222                        .flat_map(|(_, ranges)| ranges.iter())
17223                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
17224                        .cloned()
17225                        .collect();
17226
17227                    this.highlight_text::<Rename>(
17228                        ranges,
17229                        HighlightStyle {
17230                            fade_out: Some(0.6),
17231                            ..Default::default()
17232                        },
17233                        cx,
17234                    );
17235                    let rename_focus_handle = rename_editor.focus_handle(cx);
17236                    window.focus(&rename_focus_handle);
17237                    let block_id = this.insert_blocks(
17238                        [BlockProperties {
17239                            style: BlockStyle::Flex,
17240                            placement: BlockPlacement::Below(range.start),
17241                            height: Some(1),
17242                            render: Arc::new({
17243                                let rename_editor = rename_editor.clone();
17244                                move |cx: &mut BlockContext| {
17245                                    let mut text_style = cx.editor_style.text.clone();
17246                                    if let Some(highlight_style) = old_highlight_id
17247                                        .and_then(|h| h.style(&cx.editor_style.syntax))
17248                                    {
17249                                        text_style = text_style.highlight(highlight_style);
17250                                    }
17251                                    div()
17252                                        .block_mouse_except_scroll()
17253                                        .pl(cx.anchor_x)
17254                                        .child(EditorElement::new(
17255                                            &rename_editor,
17256                                            EditorStyle {
17257                                                background: cx.theme().system().transparent,
17258                                                local_player: cx.editor_style.local_player,
17259                                                text: text_style,
17260                                                scrollbar_width: cx.editor_style.scrollbar_width,
17261                                                syntax: cx.editor_style.syntax.clone(),
17262                                                status: cx.editor_style.status.clone(),
17263                                                inlay_hints_style: HighlightStyle {
17264                                                    font_weight: Some(FontWeight::BOLD),
17265                                                    ..make_inlay_hints_style(cx.app)
17266                                                },
17267                                                edit_prediction_styles: make_suggestion_styles(
17268                                                    cx.app,
17269                                                ),
17270                                                ..EditorStyle::default()
17271                                            },
17272                                        ))
17273                                        .into_any_element()
17274                                }
17275                            }),
17276                            priority: 0,
17277                        }],
17278                        Some(Autoscroll::fit()),
17279                        cx,
17280                    )[0];
17281                    this.pending_rename = Some(RenameState {
17282                        range,
17283                        old_name,
17284                        editor: rename_editor,
17285                        block_id,
17286                    });
17287                })?;
17288            }
17289
17290            Ok(())
17291        }))
17292    }
17293
17294    pub fn confirm_rename(
17295        &mut self,
17296        _: &ConfirmRename,
17297        window: &mut Window,
17298        cx: &mut Context<Self>,
17299    ) -> Option<Task<Result<()>>> {
17300        let rename = self.take_rename(false, window, cx)?;
17301        let workspace = self.workspace()?.downgrade();
17302        let (buffer, start) = self
17303            .buffer
17304            .read(cx)
17305            .text_anchor_for_position(rename.range.start, cx)?;
17306        let (end_buffer, _) = self
17307            .buffer
17308            .read(cx)
17309            .text_anchor_for_position(rename.range.end, cx)?;
17310        if buffer != end_buffer {
17311            return None;
17312        }
17313
17314        let old_name = rename.old_name;
17315        let new_name = rename.editor.read(cx).text(cx);
17316
17317        let rename = self.semantics_provider.as_ref()?.perform_rename(
17318            &buffer,
17319            start,
17320            new_name.clone(),
17321            cx,
17322        )?;
17323
17324        Some(cx.spawn_in(window, async move |editor, cx| {
17325            let project_transaction = rename.await?;
17326            Self::open_project_transaction(
17327                &editor,
17328                workspace,
17329                project_transaction,
17330                format!("Rename: {}{}", old_name, new_name),
17331                cx,
17332            )
17333            .await?;
17334
17335            editor.update(cx, |editor, cx| {
17336                editor.refresh_document_highlights(cx);
17337            })?;
17338            Ok(())
17339        }))
17340    }
17341
17342    fn take_rename(
17343        &mut self,
17344        moving_cursor: bool,
17345        window: &mut Window,
17346        cx: &mut Context<Self>,
17347    ) -> Option<RenameState> {
17348        let rename = self.pending_rename.take()?;
17349        if rename.editor.focus_handle(cx).is_focused(window) {
17350            window.focus(&self.focus_handle);
17351        }
17352
17353        self.remove_blocks(
17354            [rename.block_id].into_iter().collect(),
17355            Some(Autoscroll::fit()),
17356            cx,
17357        );
17358        self.clear_highlights::<Rename>(cx);
17359        self.show_local_selections = true;
17360
17361        if moving_cursor {
17362            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
17363                editor
17364                    .selections
17365                    .newest::<usize>(&editor.display_snapshot(cx))
17366                    .head()
17367            });
17368
17369            // Update the selection to match the position of the selection inside
17370            // the rename editor.
17371            let snapshot = self.buffer.read(cx).read(cx);
17372            let rename_range = rename.range.to_offset(&snapshot);
17373            let cursor_in_editor = snapshot
17374                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
17375                .min(rename_range.end);
17376            drop(snapshot);
17377
17378            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17379                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
17380            });
17381        } else {
17382            self.refresh_document_highlights(cx);
17383        }
17384
17385        Some(rename)
17386    }
17387
17388    pub fn pending_rename(&self) -> Option<&RenameState> {
17389        self.pending_rename.as_ref()
17390    }
17391
17392    fn format(
17393        &mut self,
17394        _: &Format,
17395        window: &mut Window,
17396        cx: &mut Context<Self>,
17397    ) -> Option<Task<Result<()>>> {
17398        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17399
17400        let project = match &self.project {
17401            Some(project) => project.clone(),
17402            None => return None,
17403        };
17404
17405        Some(self.perform_format(
17406            project,
17407            FormatTrigger::Manual,
17408            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
17409            window,
17410            cx,
17411        ))
17412    }
17413
17414    fn format_selections(
17415        &mut self,
17416        _: &FormatSelections,
17417        window: &mut Window,
17418        cx: &mut Context<Self>,
17419    ) -> Option<Task<Result<()>>> {
17420        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17421
17422        let project = match &self.project {
17423            Some(project) => project.clone(),
17424            None => return None,
17425        };
17426
17427        let ranges = self
17428            .selections
17429            .all_adjusted(&self.display_snapshot(cx))
17430            .into_iter()
17431            .map(|selection| selection.range())
17432            .collect_vec();
17433
17434        Some(self.perform_format(
17435            project,
17436            FormatTrigger::Manual,
17437            FormatTarget::Ranges(ranges),
17438            window,
17439            cx,
17440        ))
17441    }
17442
17443    fn perform_format(
17444        &mut self,
17445        project: Entity<Project>,
17446        trigger: FormatTrigger,
17447        target: FormatTarget,
17448        window: &mut Window,
17449        cx: &mut Context<Self>,
17450    ) -> Task<Result<()>> {
17451        let buffer = self.buffer.clone();
17452        let (buffers, target) = match target {
17453            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
17454            FormatTarget::Ranges(selection_ranges) => {
17455                let multi_buffer = buffer.read(cx);
17456                let snapshot = multi_buffer.read(cx);
17457                let mut buffers = HashSet::default();
17458                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
17459                    BTreeMap::new();
17460                for selection_range in selection_ranges {
17461                    for (buffer, buffer_range, _) in
17462                        snapshot.range_to_buffer_ranges(selection_range)
17463                    {
17464                        let buffer_id = buffer.remote_id();
17465                        let start = buffer.anchor_before(buffer_range.start);
17466                        let end = buffer.anchor_after(buffer_range.end);
17467                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
17468                        buffer_id_to_ranges
17469                            .entry(buffer_id)
17470                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
17471                            .or_insert_with(|| vec![start..end]);
17472                    }
17473                }
17474                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
17475            }
17476        };
17477
17478        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
17479        let selections_prev = transaction_id_prev
17480            .and_then(|transaction_id_prev| {
17481                // default to selections as they were after the last edit, if we have them,
17482                // instead of how they are now.
17483                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
17484                // will take you back to where you made the last edit, instead of staying where you scrolled
17485                self.selection_history
17486                    .transaction(transaction_id_prev)
17487                    .map(|t| t.0.clone())
17488            })
17489            .unwrap_or_else(|| self.selections.disjoint_anchors_arc());
17490
17491        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
17492        let format = project.update(cx, |project, cx| {
17493            project.format(buffers, target, true, trigger, cx)
17494        });
17495
17496        cx.spawn_in(window, async move |editor, cx| {
17497            let transaction = futures::select_biased! {
17498                transaction = format.log_err().fuse() => transaction,
17499                () = timeout => {
17500                    log::warn!("timed out waiting for formatting");
17501                    None
17502                }
17503            };
17504
17505            buffer
17506                .update(cx, |buffer, cx| {
17507                    if let Some(transaction) = transaction
17508                        && !buffer.is_singleton()
17509                    {
17510                        buffer.push_transaction(&transaction.0, cx);
17511                    }
17512                    cx.notify();
17513                })
17514                .ok();
17515
17516            if let Some(transaction_id_now) =
17517                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
17518            {
17519                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
17520                if has_new_transaction {
17521                    _ = editor.update(cx, |editor, _| {
17522                        editor
17523                            .selection_history
17524                            .insert_transaction(transaction_id_now, selections_prev);
17525                    });
17526                }
17527            }
17528
17529            Ok(())
17530        })
17531    }
17532
17533    fn organize_imports(
17534        &mut self,
17535        _: &OrganizeImports,
17536        window: &mut Window,
17537        cx: &mut Context<Self>,
17538    ) -> Option<Task<Result<()>>> {
17539        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17540        let project = match &self.project {
17541            Some(project) => project.clone(),
17542            None => return None,
17543        };
17544        Some(self.perform_code_action_kind(
17545            project,
17546            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
17547            window,
17548            cx,
17549        ))
17550    }
17551
17552    fn perform_code_action_kind(
17553        &mut self,
17554        project: Entity<Project>,
17555        kind: CodeActionKind,
17556        window: &mut Window,
17557        cx: &mut Context<Self>,
17558    ) -> Task<Result<()>> {
17559        let buffer = self.buffer.clone();
17560        let buffers = buffer.read(cx).all_buffers();
17561        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
17562        let apply_action = project.update(cx, |project, cx| {
17563            project.apply_code_action_kind(buffers, kind, true, cx)
17564        });
17565        cx.spawn_in(window, async move |_, cx| {
17566            let transaction = futures::select_biased! {
17567                () = timeout => {
17568                    log::warn!("timed out waiting for executing code action");
17569                    None
17570                }
17571                transaction = apply_action.log_err().fuse() => transaction,
17572            };
17573            buffer
17574                .update(cx, |buffer, cx| {
17575                    // check if we need this
17576                    if let Some(transaction) = transaction
17577                        && !buffer.is_singleton()
17578                    {
17579                        buffer.push_transaction(&transaction.0, cx);
17580                    }
17581                    cx.notify();
17582                })
17583                .ok();
17584            Ok(())
17585        })
17586    }
17587
17588    pub fn restart_language_server(
17589        &mut self,
17590        _: &RestartLanguageServer,
17591        _: &mut Window,
17592        cx: &mut Context<Self>,
17593    ) {
17594        if let Some(project) = self.project.clone() {
17595            self.buffer.update(cx, |multi_buffer, cx| {
17596                project.update(cx, |project, cx| {
17597                    project.restart_language_servers_for_buffers(
17598                        multi_buffer.all_buffers().into_iter().collect(),
17599                        HashSet::default(),
17600                        cx,
17601                    );
17602                });
17603            })
17604        }
17605    }
17606
17607    pub fn stop_language_server(
17608        &mut self,
17609        _: &StopLanguageServer,
17610        _: &mut Window,
17611        cx: &mut Context<Self>,
17612    ) {
17613        if let Some(project) = self.project.clone() {
17614            self.buffer.update(cx, |multi_buffer, cx| {
17615                project.update(cx, |project, cx| {
17616                    project.stop_language_servers_for_buffers(
17617                        multi_buffer.all_buffers().into_iter().collect(),
17618                        HashSet::default(),
17619                        cx,
17620                    );
17621                    cx.emit(project::Event::RefreshInlayHints);
17622                });
17623            });
17624        }
17625    }
17626
17627    fn cancel_language_server_work(
17628        workspace: &mut Workspace,
17629        _: &actions::CancelLanguageServerWork,
17630        _: &mut Window,
17631        cx: &mut Context<Workspace>,
17632    ) {
17633        let project = workspace.project();
17634        let buffers = workspace
17635            .active_item(cx)
17636            .and_then(|item| item.act_as::<Editor>(cx))
17637            .map_or(HashSet::default(), |editor| {
17638                editor.read(cx).buffer.read(cx).all_buffers()
17639            });
17640        project.update(cx, |project, cx| {
17641            project.cancel_language_server_work_for_buffers(buffers, cx);
17642        });
17643    }
17644
17645    fn show_character_palette(
17646        &mut self,
17647        _: &ShowCharacterPalette,
17648        window: &mut Window,
17649        _: &mut Context<Self>,
17650    ) {
17651        window.show_character_palette();
17652    }
17653
17654    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
17655        if !self.diagnostics_enabled() {
17656            return;
17657        }
17658
17659        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
17660            let buffer = self.buffer.read(cx).snapshot(cx);
17661            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
17662            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
17663            let is_valid = buffer
17664                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
17665                .any(|entry| {
17666                    entry.diagnostic.is_primary
17667                        && !entry.range.is_empty()
17668                        && entry.range.start == primary_range_start
17669                        && entry.diagnostic.message == active_diagnostics.active_message
17670                });
17671
17672            if !is_valid {
17673                self.dismiss_diagnostics(cx);
17674            }
17675        }
17676    }
17677
17678    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
17679        match &self.active_diagnostics {
17680            ActiveDiagnostic::Group(group) => Some(group),
17681            _ => None,
17682        }
17683    }
17684
17685    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
17686        if !self.diagnostics_enabled() {
17687            return;
17688        }
17689        self.dismiss_diagnostics(cx);
17690        self.active_diagnostics = ActiveDiagnostic::All;
17691    }
17692
17693    fn activate_diagnostics(
17694        &mut self,
17695        buffer_id: BufferId,
17696        diagnostic: DiagnosticEntryRef<'_, usize>,
17697        window: &mut Window,
17698        cx: &mut Context<Self>,
17699    ) {
17700        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17701            return;
17702        }
17703        self.dismiss_diagnostics(cx);
17704        let snapshot = self.snapshot(window, cx);
17705        let buffer = self.buffer.read(cx).snapshot(cx);
17706        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
17707            return;
17708        };
17709
17710        let diagnostic_group = buffer
17711            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
17712            .collect::<Vec<_>>();
17713
17714        let blocks =
17715            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
17716
17717        let blocks = self.display_map.update(cx, |display_map, cx| {
17718            display_map.insert_blocks(blocks, cx).into_iter().collect()
17719        });
17720        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
17721            active_range: buffer.anchor_before(diagnostic.range.start)
17722                ..buffer.anchor_after(diagnostic.range.end),
17723            active_message: diagnostic.diagnostic.message.clone(),
17724            group_id: diagnostic.diagnostic.group_id,
17725            blocks,
17726        });
17727        cx.notify();
17728    }
17729
17730    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
17731        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17732            return;
17733        };
17734
17735        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
17736        if let ActiveDiagnostic::Group(group) = prev {
17737            self.display_map.update(cx, |display_map, cx| {
17738                display_map.remove_blocks(group.blocks, cx);
17739            });
17740            cx.notify();
17741        }
17742    }
17743
17744    /// Disable inline diagnostics rendering for this editor.
17745    pub fn disable_inline_diagnostics(&mut self) {
17746        self.inline_diagnostics_enabled = false;
17747        self.inline_diagnostics_update = Task::ready(());
17748        self.inline_diagnostics.clear();
17749    }
17750
17751    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
17752        self.diagnostics_enabled = false;
17753        self.dismiss_diagnostics(cx);
17754        self.inline_diagnostics_update = Task::ready(());
17755        self.inline_diagnostics.clear();
17756    }
17757
17758    pub fn disable_word_completions(&mut self) {
17759        self.word_completions_enabled = false;
17760    }
17761
17762    pub fn diagnostics_enabled(&self) -> bool {
17763        self.diagnostics_enabled && self.mode.is_full()
17764    }
17765
17766    pub fn inline_diagnostics_enabled(&self) -> bool {
17767        self.inline_diagnostics_enabled && self.diagnostics_enabled()
17768    }
17769
17770    pub fn show_inline_diagnostics(&self) -> bool {
17771        self.show_inline_diagnostics
17772    }
17773
17774    pub fn toggle_inline_diagnostics(
17775        &mut self,
17776        _: &ToggleInlineDiagnostics,
17777        window: &mut Window,
17778        cx: &mut Context<Editor>,
17779    ) {
17780        self.show_inline_diagnostics = !self.show_inline_diagnostics;
17781        self.refresh_inline_diagnostics(false, window, cx);
17782    }
17783
17784    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
17785        self.diagnostics_max_severity = severity;
17786        self.display_map.update(cx, |display_map, _| {
17787            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
17788        });
17789    }
17790
17791    pub fn toggle_diagnostics(
17792        &mut self,
17793        _: &ToggleDiagnostics,
17794        window: &mut Window,
17795        cx: &mut Context<Editor>,
17796    ) {
17797        if !self.diagnostics_enabled() {
17798            return;
17799        }
17800
17801        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17802            EditorSettings::get_global(cx)
17803                .diagnostics_max_severity
17804                .filter(|severity| severity != &DiagnosticSeverity::Off)
17805                .unwrap_or(DiagnosticSeverity::Hint)
17806        } else {
17807            DiagnosticSeverity::Off
17808        };
17809        self.set_max_diagnostics_severity(new_severity, cx);
17810        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17811            self.active_diagnostics = ActiveDiagnostic::None;
17812            self.inline_diagnostics_update = Task::ready(());
17813            self.inline_diagnostics.clear();
17814        } else {
17815            self.refresh_inline_diagnostics(false, window, cx);
17816        }
17817
17818        cx.notify();
17819    }
17820
17821    pub fn toggle_minimap(
17822        &mut self,
17823        _: &ToggleMinimap,
17824        window: &mut Window,
17825        cx: &mut Context<Editor>,
17826    ) {
17827        if self.supports_minimap(cx) {
17828            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
17829        }
17830    }
17831
17832    fn refresh_inline_diagnostics(
17833        &mut self,
17834        debounce: bool,
17835        window: &mut Window,
17836        cx: &mut Context<Self>,
17837    ) {
17838        let max_severity = ProjectSettings::get_global(cx)
17839            .diagnostics
17840            .inline
17841            .max_severity
17842            .unwrap_or(self.diagnostics_max_severity);
17843
17844        if !self.inline_diagnostics_enabled()
17845            || !self.show_inline_diagnostics
17846            || max_severity == DiagnosticSeverity::Off
17847        {
17848            self.inline_diagnostics_update = Task::ready(());
17849            self.inline_diagnostics.clear();
17850            return;
17851        }
17852
17853        let debounce_ms = ProjectSettings::get_global(cx)
17854            .diagnostics
17855            .inline
17856            .update_debounce_ms;
17857        let debounce = if debounce && debounce_ms > 0 {
17858            Some(Duration::from_millis(debounce_ms))
17859        } else {
17860            None
17861        };
17862        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
17863            if let Some(debounce) = debounce {
17864                cx.background_executor().timer(debounce).await;
17865            }
17866            let Some(snapshot) = editor.upgrade().and_then(|editor| {
17867                editor
17868                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
17869                    .ok()
17870            }) else {
17871                return;
17872            };
17873
17874            let new_inline_diagnostics = cx
17875                .background_spawn(async move {
17876                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
17877                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
17878                        let message = diagnostic_entry
17879                            .diagnostic
17880                            .message
17881                            .split_once('\n')
17882                            .map(|(line, _)| line)
17883                            .map(SharedString::new)
17884                            .unwrap_or_else(|| {
17885                                SharedString::new(&*diagnostic_entry.diagnostic.message)
17886                            });
17887                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
17888                        let (Ok(i) | Err(i)) = inline_diagnostics
17889                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
17890                        inline_diagnostics.insert(
17891                            i,
17892                            (
17893                                start_anchor,
17894                                InlineDiagnostic {
17895                                    message,
17896                                    group_id: diagnostic_entry.diagnostic.group_id,
17897                                    start: diagnostic_entry.range.start.to_point(&snapshot),
17898                                    is_primary: diagnostic_entry.diagnostic.is_primary,
17899                                    severity: diagnostic_entry.diagnostic.severity,
17900                                },
17901                            ),
17902                        );
17903                    }
17904                    inline_diagnostics
17905                })
17906                .await;
17907
17908            editor
17909                .update(cx, |editor, cx| {
17910                    editor.inline_diagnostics = new_inline_diagnostics;
17911                    cx.notify();
17912                })
17913                .ok();
17914        });
17915    }
17916
17917    fn pull_diagnostics(
17918        &mut self,
17919        buffer_id: Option<BufferId>,
17920        window: &Window,
17921        cx: &mut Context<Self>,
17922    ) -> Option<()> {
17923        if self.ignore_lsp_data() {
17924            return None;
17925        }
17926        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
17927            .diagnostics
17928            .lsp_pull_diagnostics;
17929        if !pull_diagnostics_settings.enabled {
17930            return None;
17931        }
17932        let project = self.project()?.downgrade();
17933        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
17934        let mut buffers = self.buffer.read(cx).all_buffers();
17935        buffers.retain(|buffer| {
17936            let buffer_id_to_retain = buffer.read(cx).remote_id();
17937            buffer_id.is_none_or(|buffer_id| buffer_id == buffer_id_to_retain)
17938                && self.registered_buffers.contains_key(&buffer_id_to_retain)
17939        });
17940        if buffers.is_empty() {
17941            self.pull_diagnostics_task = Task::ready(());
17942            return None;
17943        }
17944
17945        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
17946            cx.background_executor().timer(debounce).await;
17947
17948            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
17949                buffers
17950                    .into_iter()
17951                    .filter_map(|buffer| {
17952                        project
17953                            .update(cx, |project, cx| {
17954                                project.lsp_store().update(cx, |lsp_store, cx| {
17955                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
17956                                })
17957                            })
17958                            .ok()
17959                    })
17960                    .collect::<FuturesUnordered<_>>()
17961            }) else {
17962                return;
17963            };
17964
17965            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
17966                match pull_task {
17967                    Ok(()) => {
17968                        if editor
17969                            .update_in(cx, |editor, window, cx| {
17970                                editor.update_diagnostics_state(window, cx);
17971                            })
17972                            .is_err()
17973                        {
17974                            return;
17975                        }
17976                    }
17977                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
17978                }
17979            }
17980        });
17981
17982        Some(())
17983    }
17984
17985    pub fn set_selections_from_remote(
17986        &mut self,
17987        selections: Vec<Selection<Anchor>>,
17988        pending_selection: Option<Selection<Anchor>>,
17989        window: &mut Window,
17990        cx: &mut Context<Self>,
17991    ) {
17992        let old_cursor_position = self.selections.newest_anchor().head();
17993        self.selections.change_with(cx, |s| {
17994            s.select_anchors(selections);
17995            if let Some(pending_selection) = pending_selection {
17996                s.set_pending(pending_selection, SelectMode::Character);
17997            } else {
17998                s.clear_pending();
17999            }
18000        });
18001        self.selections_did_change(
18002            false,
18003            &old_cursor_position,
18004            SelectionEffects::default(),
18005            window,
18006            cx,
18007        );
18008    }
18009
18010    pub fn transact(
18011        &mut self,
18012        window: &mut Window,
18013        cx: &mut Context<Self>,
18014        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
18015    ) -> Option<TransactionId> {
18016        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
18017            this.start_transaction_at(Instant::now(), window, cx);
18018            update(this, window, cx);
18019            this.end_transaction_at(Instant::now(), cx)
18020        })
18021    }
18022
18023    pub fn start_transaction_at(
18024        &mut self,
18025        now: Instant,
18026        window: &mut Window,
18027        cx: &mut Context<Self>,
18028    ) -> Option<TransactionId> {
18029        self.end_selection(window, cx);
18030        if let Some(tx_id) = self
18031            .buffer
18032            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
18033        {
18034            self.selection_history
18035                .insert_transaction(tx_id, self.selections.disjoint_anchors_arc());
18036            cx.emit(EditorEvent::TransactionBegun {
18037                transaction_id: tx_id,
18038            });
18039            Some(tx_id)
18040        } else {
18041            None
18042        }
18043    }
18044
18045    pub fn end_transaction_at(
18046        &mut self,
18047        now: Instant,
18048        cx: &mut Context<Self>,
18049    ) -> Option<TransactionId> {
18050        if let Some(transaction_id) = self
18051            .buffer
18052            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
18053        {
18054            if let Some((_, end_selections)) =
18055                self.selection_history.transaction_mut(transaction_id)
18056            {
18057                *end_selections = Some(self.selections.disjoint_anchors_arc());
18058            } else {
18059                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
18060            }
18061
18062            cx.emit(EditorEvent::Edited { transaction_id });
18063            Some(transaction_id)
18064        } else {
18065            None
18066        }
18067    }
18068
18069    pub fn modify_transaction_selection_history(
18070        &mut self,
18071        transaction_id: TransactionId,
18072        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
18073    ) -> bool {
18074        self.selection_history
18075            .transaction_mut(transaction_id)
18076            .map(modify)
18077            .is_some()
18078    }
18079
18080    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
18081        if self.selection_mark_mode {
18082            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18083                s.move_with(|_, sel| {
18084                    sel.collapse_to(sel.head(), SelectionGoal::None);
18085                });
18086            })
18087        }
18088        self.selection_mark_mode = true;
18089        cx.notify();
18090    }
18091
18092    pub fn swap_selection_ends(
18093        &mut self,
18094        _: &actions::SwapSelectionEnds,
18095        window: &mut Window,
18096        cx: &mut Context<Self>,
18097    ) {
18098        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18099            s.move_with(|_, sel| {
18100                if sel.start != sel.end {
18101                    sel.reversed = !sel.reversed
18102                }
18103            });
18104        });
18105        self.request_autoscroll(Autoscroll::newest(), cx);
18106        cx.notify();
18107    }
18108
18109    pub fn toggle_focus(
18110        workspace: &mut Workspace,
18111        _: &actions::ToggleFocus,
18112        window: &mut Window,
18113        cx: &mut Context<Workspace>,
18114    ) {
18115        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
18116            return;
18117        };
18118        workspace.activate_item(&item, true, true, window, cx);
18119    }
18120
18121    pub fn toggle_fold(
18122        &mut self,
18123        _: &actions::ToggleFold,
18124        window: &mut Window,
18125        cx: &mut Context<Self>,
18126    ) {
18127        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18128            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18129            let selection = self.selections.newest::<Point>(&display_map);
18130
18131            let range = if selection.is_empty() {
18132                let point = selection.head().to_display_point(&display_map);
18133                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
18134                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
18135                    .to_point(&display_map);
18136                start..end
18137            } else {
18138                selection.range()
18139            };
18140            if display_map.folds_in_range(range).next().is_some() {
18141                self.unfold_lines(&Default::default(), window, cx)
18142            } else {
18143                self.fold(&Default::default(), window, cx)
18144            }
18145        } else {
18146            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18147            let buffer_ids: HashSet<_> = self
18148                .selections
18149                .disjoint_anchor_ranges()
18150                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18151                .collect();
18152
18153            let should_unfold = buffer_ids
18154                .iter()
18155                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18156
18157            for buffer_id in buffer_ids {
18158                if should_unfold {
18159                    self.unfold_buffer(buffer_id, cx);
18160                } else {
18161                    self.fold_buffer(buffer_id, cx);
18162                }
18163            }
18164        }
18165    }
18166
18167    pub fn toggle_fold_recursive(
18168        &mut self,
18169        _: &actions::ToggleFoldRecursive,
18170        window: &mut Window,
18171        cx: &mut Context<Self>,
18172    ) {
18173        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
18174
18175        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18176        let range = if selection.is_empty() {
18177            let point = selection.head().to_display_point(&display_map);
18178            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
18179            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
18180                .to_point(&display_map);
18181            start..end
18182        } else {
18183            selection.range()
18184        };
18185        if display_map.folds_in_range(range).next().is_some() {
18186            self.unfold_recursive(&Default::default(), window, cx)
18187        } else {
18188            self.fold_recursive(&Default::default(), window, cx)
18189        }
18190    }
18191
18192    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
18193        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18194            let mut to_fold = Vec::new();
18195            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18196            let selections = self.selections.all_adjusted(&display_map);
18197
18198            for selection in selections {
18199                let range = selection.range().sorted();
18200                let buffer_start_row = range.start.row;
18201
18202                if range.start.row != range.end.row {
18203                    let mut found = false;
18204                    let mut row = range.start.row;
18205                    while row <= range.end.row {
18206                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18207                        {
18208                            found = true;
18209                            row = crease.range().end.row + 1;
18210                            to_fold.push(crease);
18211                        } else {
18212                            row += 1
18213                        }
18214                    }
18215                    if found {
18216                        continue;
18217                    }
18218                }
18219
18220                for row in (0..=range.start.row).rev() {
18221                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18222                        && crease.range().end.row >= buffer_start_row
18223                    {
18224                        to_fold.push(crease);
18225                        if row <= range.start.row {
18226                            break;
18227                        }
18228                    }
18229                }
18230            }
18231
18232            self.fold_creases(to_fold, true, window, cx);
18233        } else {
18234            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18235            let buffer_ids = self
18236                .selections
18237                .disjoint_anchor_ranges()
18238                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18239                .collect::<HashSet<_>>();
18240            for buffer_id in buffer_ids {
18241                self.fold_buffer(buffer_id, cx);
18242            }
18243        }
18244    }
18245
18246    pub fn toggle_fold_all(
18247        &mut self,
18248        _: &actions::ToggleFoldAll,
18249        window: &mut Window,
18250        cx: &mut Context<Self>,
18251    ) {
18252        if self.buffer.read(cx).is_singleton() {
18253            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18254            let has_folds = display_map
18255                .folds_in_range(0..display_map.buffer_snapshot().len())
18256                .next()
18257                .is_some();
18258
18259            if has_folds {
18260                self.unfold_all(&actions::UnfoldAll, window, cx);
18261            } else {
18262                self.fold_all(&actions::FoldAll, window, cx);
18263            }
18264        } else {
18265            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
18266            let should_unfold = buffer_ids
18267                .iter()
18268                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18269
18270            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18271                editor
18272                    .update_in(cx, |editor, _, cx| {
18273                        for buffer_id in buffer_ids {
18274                            if should_unfold {
18275                                editor.unfold_buffer(buffer_id, cx);
18276                            } else {
18277                                editor.fold_buffer(buffer_id, cx);
18278                            }
18279                        }
18280                    })
18281                    .ok();
18282            });
18283        }
18284    }
18285
18286    fn fold_at_level(
18287        &mut self,
18288        fold_at: &FoldAtLevel,
18289        window: &mut Window,
18290        cx: &mut Context<Self>,
18291    ) {
18292        if !self.buffer.read(cx).is_singleton() {
18293            return;
18294        }
18295
18296        let fold_at_level = fold_at.0;
18297        let snapshot = self.buffer.read(cx).snapshot(cx);
18298        let mut to_fold = Vec::new();
18299        let mut stack = vec![(0, snapshot.max_row().0, 1)];
18300
18301        let row_ranges_to_keep: Vec<Range<u32>> = self
18302            .selections
18303            .all::<Point>(&self.display_snapshot(cx))
18304            .into_iter()
18305            .map(|sel| sel.start.row..sel.end.row)
18306            .collect();
18307
18308        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
18309            while start_row < end_row {
18310                match self
18311                    .snapshot(window, cx)
18312                    .crease_for_buffer_row(MultiBufferRow(start_row))
18313                {
18314                    Some(crease) => {
18315                        let nested_start_row = crease.range().start.row + 1;
18316                        let nested_end_row = crease.range().end.row;
18317
18318                        if current_level < fold_at_level {
18319                            stack.push((nested_start_row, nested_end_row, current_level + 1));
18320                        } else if current_level == fold_at_level {
18321                            // Fold iff there is no selection completely contained within the fold region
18322                            if !row_ranges_to_keep.iter().any(|selection| {
18323                                selection.end >= nested_start_row
18324                                    && selection.start <= nested_end_row
18325                            }) {
18326                                to_fold.push(crease);
18327                            }
18328                        }
18329
18330                        start_row = nested_end_row + 1;
18331                    }
18332                    None => start_row += 1,
18333                }
18334            }
18335        }
18336
18337        self.fold_creases(to_fold, true, window, cx);
18338    }
18339
18340    pub fn fold_at_level_1(
18341        &mut self,
18342        _: &actions::FoldAtLevel1,
18343        window: &mut Window,
18344        cx: &mut Context<Self>,
18345    ) {
18346        self.fold_at_level(&actions::FoldAtLevel(1), window, cx);
18347    }
18348
18349    pub fn fold_at_level_2(
18350        &mut self,
18351        _: &actions::FoldAtLevel2,
18352        window: &mut Window,
18353        cx: &mut Context<Self>,
18354    ) {
18355        self.fold_at_level(&actions::FoldAtLevel(2), window, cx);
18356    }
18357
18358    pub fn fold_at_level_3(
18359        &mut self,
18360        _: &actions::FoldAtLevel3,
18361        window: &mut Window,
18362        cx: &mut Context<Self>,
18363    ) {
18364        self.fold_at_level(&actions::FoldAtLevel(3), window, cx);
18365    }
18366
18367    pub fn fold_at_level_4(
18368        &mut self,
18369        _: &actions::FoldAtLevel4,
18370        window: &mut Window,
18371        cx: &mut Context<Self>,
18372    ) {
18373        self.fold_at_level(&actions::FoldAtLevel(4), window, cx);
18374    }
18375
18376    pub fn fold_at_level_5(
18377        &mut self,
18378        _: &actions::FoldAtLevel5,
18379        window: &mut Window,
18380        cx: &mut Context<Self>,
18381    ) {
18382        self.fold_at_level(&actions::FoldAtLevel(5), window, cx);
18383    }
18384
18385    pub fn fold_at_level_6(
18386        &mut self,
18387        _: &actions::FoldAtLevel6,
18388        window: &mut Window,
18389        cx: &mut Context<Self>,
18390    ) {
18391        self.fold_at_level(&actions::FoldAtLevel(6), window, cx);
18392    }
18393
18394    pub fn fold_at_level_7(
18395        &mut self,
18396        _: &actions::FoldAtLevel7,
18397        window: &mut Window,
18398        cx: &mut Context<Self>,
18399    ) {
18400        self.fold_at_level(&actions::FoldAtLevel(7), window, cx);
18401    }
18402
18403    pub fn fold_at_level_8(
18404        &mut self,
18405        _: &actions::FoldAtLevel8,
18406        window: &mut Window,
18407        cx: &mut Context<Self>,
18408    ) {
18409        self.fold_at_level(&actions::FoldAtLevel(8), window, cx);
18410    }
18411
18412    pub fn fold_at_level_9(
18413        &mut self,
18414        _: &actions::FoldAtLevel9,
18415        window: &mut Window,
18416        cx: &mut Context<Self>,
18417    ) {
18418        self.fold_at_level(&actions::FoldAtLevel(9), window, cx);
18419    }
18420
18421    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
18422        if self.buffer.read(cx).is_singleton() {
18423            let mut fold_ranges = Vec::new();
18424            let snapshot = self.buffer.read(cx).snapshot(cx);
18425
18426            for row in 0..snapshot.max_row().0 {
18427                if let Some(foldable_range) = self
18428                    .snapshot(window, cx)
18429                    .crease_for_buffer_row(MultiBufferRow(row))
18430                {
18431                    fold_ranges.push(foldable_range);
18432                }
18433            }
18434
18435            self.fold_creases(fold_ranges, true, window, cx);
18436        } else {
18437            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18438                editor
18439                    .update_in(cx, |editor, _, cx| {
18440                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18441                            editor.fold_buffer(buffer_id, cx);
18442                        }
18443                    })
18444                    .ok();
18445            });
18446        }
18447    }
18448
18449    pub fn fold_function_bodies(
18450        &mut self,
18451        _: &actions::FoldFunctionBodies,
18452        window: &mut Window,
18453        cx: &mut Context<Self>,
18454    ) {
18455        let snapshot = self.buffer.read(cx).snapshot(cx);
18456
18457        let ranges = snapshot
18458            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
18459            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
18460            .collect::<Vec<_>>();
18461
18462        let creases = ranges
18463            .into_iter()
18464            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
18465            .collect();
18466
18467        self.fold_creases(creases, true, window, cx);
18468    }
18469
18470    pub fn fold_recursive(
18471        &mut self,
18472        _: &actions::FoldRecursive,
18473        window: &mut Window,
18474        cx: &mut Context<Self>,
18475    ) {
18476        let mut to_fold = Vec::new();
18477        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18478        let selections = self.selections.all_adjusted(&display_map);
18479
18480        for selection in selections {
18481            let range = selection.range().sorted();
18482            let buffer_start_row = range.start.row;
18483
18484            if range.start.row != range.end.row {
18485                let mut found = false;
18486                for row in range.start.row..=range.end.row {
18487                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18488                        found = true;
18489                        to_fold.push(crease);
18490                    }
18491                }
18492                if found {
18493                    continue;
18494                }
18495            }
18496
18497            for row in (0..=range.start.row).rev() {
18498                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18499                    if crease.range().end.row >= buffer_start_row {
18500                        to_fold.push(crease);
18501                    } else {
18502                        break;
18503                    }
18504                }
18505            }
18506        }
18507
18508        self.fold_creases(to_fold, true, window, cx);
18509    }
18510
18511    pub fn fold_at(
18512        &mut self,
18513        buffer_row: MultiBufferRow,
18514        window: &mut Window,
18515        cx: &mut Context<Self>,
18516    ) {
18517        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18518
18519        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
18520            let autoscroll = self
18521                .selections
18522                .all::<Point>(&display_map)
18523                .iter()
18524                .any(|selection| crease.range().overlaps(&selection.range()));
18525
18526            self.fold_creases(vec![crease], autoscroll, window, cx);
18527        }
18528    }
18529
18530    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
18531        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18532            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18533            let buffer = display_map.buffer_snapshot();
18534            let selections = self.selections.all::<Point>(&display_map);
18535            let ranges = selections
18536                .iter()
18537                .map(|s| {
18538                    let range = s.display_range(&display_map).sorted();
18539                    let mut start = range.start.to_point(&display_map);
18540                    let mut end = range.end.to_point(&display_map);
18541                    start.column = 0;
18542                    end.column = buffer.line_len(MultiBufferRow(end.row));
18543                    start..end
18544                })
18545                .collect::<Vec<_>>();
18546
18547            self.unfold_ranges(&ranges, true, true, cx);
18548        } else {
18549            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18550            let buffer_ids = self
18551                .selections
18552                .disjoint_anchor_ranges()
18553                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18554                .collect::<HashSet<_>>();
18555            for buffer_id in buffer_ids {
18556                self.unfold_buffer(buffer_id, cx);
18557            }
18558        }
18559    }
18560
18561    pub fn unfold_recursive(
18562        &mut self,
18563        _: &UnfoldRecursive,
18564        _window: &mut Window,
18565        cx: &mut Context<Self>,
18566    ) {
18567        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18568        let selections = self.selections.all::<Point>(&display_map);
18569        let ranges = selections
18570            .iter()
18571            .map(|s| {
18572                let mut range = s.display_range(&display_map).sorted();
18573                *range.start.column_mut() = 0;
18574                *range.end.column_mut() = display_map.line_len(range.end.row());
18575                let start = range.start.to_point(&display_map);
18576                let end = range.end.to_point(&display_map);
18577                start..end
18578            })
18579            .collect::<Vec<_>>();
18580
18581        self.unfold_ranges(&ranges, true, true, cx);
18582    }
18583
18584    pub fn unfold_at(
18585        &mut self,
18586        buffer_row: MultiBufferRow,
18587        _window: &mut Window,
18588        cx: &mut Context<Self>,
18589    ) {
18590        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18591
18592        let intersection_range = Point::new(buffer_row.0, 0)
18593            ..Point::new(
18594                buffer_row.0,
18595                display_map.buffer_snapshot().line_len(buffer_row),
18596            );
18597
18598        let autoscroll = self
18599            .selections
18600            .all::<Point>(&display_map)
18601            .iter()
18602            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
18603
18604        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
18605    }
18606
18607    pub fn unfold_all(
18608        &mut self,
18609        _: &actions::UnfoldAll,
18610        _window: &mut Window,
18611        cx: &mut Context<Self>,
18612    ) {
18613        if self.buffer.read(cx).is_singleton() {
18614            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18615            self.unfold_ranges(&[0..display_map.buffer_snapshot().len()], true, true, cx);
18616        } else {
18617            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
18618                editor
18619                    .update(cx, |editor, cx| {
18620                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18621                            editor.unfold_buffer(buffer_id, cx);
18622                        }
18623                    })
18624                    .ok();
18625            });
18626        }
18627    }
18628
18629    pub fn fold_selected_ranges(
18630        &mut self,
18631        _: &FoldSelectedRanges,
18632        window: &mut Window,
18633        cx: &mut Context<Self>,
18634    ) {
18635        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18636        let selections = self.selections.all_adjusted(&display_map);
18637        let ranges = selections
18638            .into_iter()
18639            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
18640            .collect::<Vec<_>>();
18641        self.fold_creases(ranges, true, window, cx);
18642    }
18643
18644    pub fn fold_ranges<T: ToOffset + Clone>(
18645        &mut self,
18646        ranges: Vec<Range<T>>,
18647        auto_scroll: bool,
18648        window: &mut Window,
18649        cx: &mut Context<Self>,
18650    ) {
18651        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18652        let ranges = ranges
18653            .into_iter()
18654            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
18655            .collect::<Vec<_>>();
18656        self.fold_creases(ranges, auto_scroll, window, cx);
18657    }
18658
18659    pub fn fold_creases<T: ToOffset + Clone>(
18660        &mut self,
18661        creases: Vec<Crease<T>>,
18662        auto_scroll: bool,
18663        _window: &mut Window,
18664        cx: &mut Context<Self>,
18665    ) {
18666        if creases.is_empty() {
18667            return;
18668        }
18669
18670        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
18671
18672        if auto_scroll {
18673            self.request_autoscroll(Autoscroll::fit(), cx);
18674        }
18675
18676        cx.notify();
18677
18678        self.scrollbar_marker_state.dirty = true;
18679        self.folds_did_change(cx);
18680    }
18681
18682    /// Removes any folds whose ranges intersect any of the given ranges.
18683    pub fn unfold_ranges<T: ToOffset + Clone>(
18684        &mut self,
18685        ranges: &[Range<T>],
18686        inclusive: bool,
18687        auto_scroll: bool,
18688        cx: &mut Context<Self>,
18689    ) {
18690        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18691            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
18692        });
18693        self.folds_did_change(cx);
18694    }
18695
18696    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18697        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
18698            return;
18699        }
18700        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18701        self.display_map.update(cx, |display_map, cx| {
18702            display_map.fold_buffers([buffer_id], cx)
18703        });
18704        cx.emit(EditorEvent::BufferFoldToggled {
18705            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
18706            folded: true,
18707        });
18708        cx.notify();
18709    }
18710
18711    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18712        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
18713            return;
18714        }
18715        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18716        self.display_map.update(cx, |display_map, cx| {
18717            display_map.unfold_buffers([buffer_id], cx);
18718        });
18719        cx.emit(EditorEvent::BufferFoldToggled {
18720            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
18721            folded: false,
18722        });
18723        cx.notify();
18724    }
18725
18726    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
18727        self.display_map.read(cx).is_buffer_folded(buffer)
18728    }
18729
18730    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
18731        self.display_map.read(cx).folded_buffers()
18732    }
18733
18734    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18735        self.display_map.update(cx, |display_map, cx| {
18736            display_map.disable_header_for_buffer(buffer_id, cx);
18737        });
18738        cx.notify();
18739    }
18740
18741    /// Removes any folds with the given ranges.
18742    pub fn remove_folds_with_type<T: ToOffset + Clone>(
18743        &mut self,
18744        ranges: &[Range<T>],
18745        type_id: TypeId,
18746        auto_scroll: bool,
18747        cx: &mut Context<Self>,
18748    ) {
18749        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18750            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
18751        });
18752        self.folds_did_change(cx);
18753    }
18754
18755    fn remove_folds_with<T: ToOffset + Clone>(
18756        &mut self,
18757        ranges: &[Range<T>],
18758        auto_scroll: bool,
18759        cx: &mut Context<Self>,
18760        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
18761    ) {
18762        if ranges.is_empty() {
18763            return;
18764        }
18765
18766        let mut buffers_affected = HashSet::default();
18767        let multi_buffer = self.buffer().read(cx);
18768        for range in ranges {
18769            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
18770                buffers_affected.insert(buffer.read(cx).remote_id());
18771            };
18772        }
18773
18774        self.display_map.update(cx, update);
18775
18776        if auto_scroll {
18777            self.request_autoscroll(Autoscroll::fit(), cx);
18778        }
18779
18780        cx.notify();
18781        self.scrollbar_marker_state.dirty = true;
18782        self.active_indent_guides_state.dirty = true;
18783    }
18784
18785    pub fn update_renderer_widths(
18786        &mut self,
18787        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
18788        cx: &mut Context<Self>,
18789    ) -> bool {
18790        self.display_map
18791            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
18792    }
18793
18794    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
18795        self.display_map.read(cx).fold_placeholder.clone()
18796    }
18797
18798    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
18799        self.buffer.update(cx, |buffer, cx| {
18800            buffer.set_all_diff_hunks_expanded(cx);
18801        });
18802    }
18803
18804    pub fn expand_all_diff_hunks(
18805        &mut self,
18806        _: &ExpandAllDiffHunks,
18807        _window: &mut Window,
18808        cx: &mut Context<Self>,
18809    ) {
18810        self.buffer.update(cx, |buffer, cx| {
18811            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
18812        });
18813    }
18814
18815    pub fn collapse_all_diff_hunks(
18816        &mut self,
18817        _: &CollapseAllDiffHunks,
18818        _window: &mut Window,
18819        cx: &mut Context<Self>,
18820    ) {
18821        self.buffer.update(cx, |buffer, cx| {
18822            buffer.collapse_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
18823        });
18824    }
18825
18826    pub fn toggle_selected_diff_hunks(
18827        &mut self,
18828        _: &ToggleSelectedDiffHunks,
18829        _window: &mut Window,
18830        cx: &mut Context<Self>,
18831    ) {
18832        let ranges: Vec<_> = self
18833            .selections
18834            .disjoint_anchors()
18835            .iter()
18836            .map(|s| s.range())
18837            .collect();
18838        self.toggle_diff_hunks_in_ranges(ranges, cx);
18839    }
18840
18841    pub fn diff_hunks_in_ranges<'a>(
18842        &'a self,
18843        ranges: &'a [Range<Anchor>],
18844        buffer: &'a MultiBufferSnapshot,
18845    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
18846        ranges.iter().flat_map(move |range| {
18847            let end_excerpt_id = range.end.excerpt_id;
18848            let range = range.to_point(buffer);
18849            let mut peek_end = range.end;
18850            if range.end.row < buffer.max_row().0 {
18851                peek_end = Point::new(range.end.row + 1, 0);
18852            }
18853            buffer
18854                .diff_hunks_in_range(range.start..peek_end)
18855                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
18856        })
18857    }
18858
18859    pub fn has_stageable_diff_hunks_in_ranges(
18860        &self,
18861        ranges: &[Range<Anchor>],
18862        snapshot: &MultiBufferSnapshot,
18863    ) -> bool {
18864        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
18865        hunks.any(|hunk| hunk.status().has_secondary_hunk())
18866    }
18867
18868    pub fn toggle_staged_selected_diff_hunks(
18869        &mut self,
18870        _: &::git::ToggleStaged,
18871        _: &mut Window,
18872        cx: &mut Context<Self>,
18873    ) {
18874        let snapshot = self.buffer.read(cx).snapshot(cx);
18875        let ranges: Vec<_> = self
18876            .selections
18877            .disjoint_anchors()
18878            .iter()
18879            .map(|s| s.range())
18880            .collect();
18881        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
18882        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18883    }
18884
18885    pub fn set_render_diff_hunk_controls(
18886        &mut self,
18887        render_diff_hunk_controls: RenderDiffHunkControlsFn,
18888        cx: &mut Context<Self>,
18889    ) {
18890        self.render_diff_hunk_controls = render_diff_hunk_controls;
18891        cx.notify();
18892    }
18893
18894    pub fn stage_and_next(
18895        &mut self,
18896        _: &::git::StageAndNext,
18897        window: &mut Window,
18898        cx: &mut Context<Self>,
18899    ) {
18900        self.do_stage_or_unstage_and_next(true, window, cx);
18901    }
18902
18903    pub fn unstage_and_next(
18904        &mut self,
18905        _: &::git::UnstageAndNext,
18906        window: &mut Window,
18907        cx: &mut Context<Self>,
18908    ) {
18909        self.do_stage_or_unstage_and_next(false, window, cx);
18910    }
18911
18912    pub fn stage_or_unstage_diff_hunks(
18913        &mut self,
18914        stage: bool,
18915        ranges: Vec<Range<Anchor>>,
18916        cx: &mut Context<Self>,
18917    ) {
18918        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
18919        cx.spawn(async move |this, cx| {
18920            task.await?;
18921            this.update(cx, |this, cx| {
18922                let snapshot = this.buffer.read(cx).snapshot(cx);
18923                let chunk_by = this
18924                    .diff_hunks_in_ranges(&ranges, &snapshot)
18925                    .chunk_by(|hunk| hunk.buffer_id);
18926                for (buffer_id, hunks) in &chunk_by {
18927                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
18928                }
18929            })
18930        })
18931        .detach_and_log_err(cx);
18932    }
18933
18934    fn save_buffers_for_ranges_if_needed(
18935        &mut self,
18936        ranges: &[Range<Anchor>],
18937        cx: &mut Context<Editor>,
18938    ) -> Task<Result<()>> {
18939        let multibuffer = self.buffer.read(cx);
18940        let snapshot = multibuffer.read(cx);
18941        let buffer_ids: HashSet<_> = ranges
18942            .iter()
18943            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
18944            .collect();
18945        drop(snapshot);
18946
18947        let mut buffers = HashSet::default();
18948        for buffer_id in buffer_ids {
18949            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
18950                let buffer = buffer_entity.read(cx);
18951                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
18952                {
18953                    buffers.insert(buffer_entity);
18954                }
18955            }
18956        }
18957
18958        if let Some(project) = &self.project {
18959            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
18960        } else {
18961            Task::ready(Ok(()))
18962        }
18963    }
18964
18965    fn do_stage_or_unstage_and_next(
18966        &mut self,
18967        stage: bool,
18968        window: &mut Window,
18969        cx: &mut Context<Self>,
18970    ) {
18971        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
18972
18973        if ranges.iter().any(|range| range.start != range.end) {
18974            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18975            return;
18976        }
18977
18978        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18979        let snapshot = self.snapshot(window, cx);
18980        let position = self
18981            .selections
18982            .newest::<Point>(&snapshot.display_snapshot)
18983            .head();
18984        let mut row = snapshot
18985            .buffer_snapshot()
18986            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
18987            .find(|hunk| hunk.row_range.start.0 > position.row)
18988            .map(|hunk| hunk.row_range.start);
18989
18990        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
18991        // Outside of the project diff editor, wrap around to the beginning.
18992        if !all_diff_hunks_expanded {
18993            row = row.or_else(|| {
18994                snapshot
18995                    .buffer_snapshot()
18996                    .diff_hunks_in_range(Point::zero()..position)
18997                    .find(|hunk| hunk.row_range.end.0 < position.row)
18998                    .map(|hunk| hunk.row_range.start)
18999            });
19000        }
19001
19002        if let Some(row) = row {
19003            let destination = Point::new(row.0, 0);
19004            let autoscroll = Autoscroll::center();
19005
19006            self.unfold_ranges(&[destination..destination], false, false, cx);
19007            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
19008                s.select_ranges([destination..destination]);
19009            });
19010        }
19011    }
19012
19013    fn do_stage_or_unstage(
19014        &self,
19015        stage: bool,
19016        buffer_id: BufferId,
19017        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
19018        cx: &mut App,
19019    ) -> Option<()> {
19020        let project = self.project()?;
19021        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
19022        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
19023        let buffer_snapshot = buffer.read(cx).snapshot();
19024        let file_exists = buffer_snapshot
19025            .file()
19026            .is_some_and(|file| file.disk_state().exists());
19027        diff.update(cx, |diff, cx| {
19028            diff.stage_or_unstage_hunks(
19029                stage,
19030                &hunks
19031                    .map(|hunk| buffer_diff::DiffHunk {
19032                        buffer_range: hunk.buffer_range,
19033                        diff_base_byte_range: hunk.diff_base_byte_range,
19034                        secondary_status: hunk.secondary_status,
19035                        range: Point::zero()..Point::zero(), // unused
19036                    })
19037                    .collect::<Vec<_>>(),
19038                &buffer_snapshot,
19039                file_exists,
19040                cx,
19041            )
19042        });
19043        None
19044    }
19045
19046    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
19047        let ranges: Vec<_> = self
19048            .selections
19049            .disjoint_anchors()
19050            .iter()
19051            .map(|s| s.range())
19052            .collect();
19053        self.buffer
19054            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
19055    }
19056
19057    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
19058        self.buffer.update(cx, |buffer, cx| {
19059            let ranges = vec![Anchor::min()..Anchor::max()];
19060            if !buffer.all_diff_hunks_expanded()
19061                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
19062            {
19063                buffer.collapse_diff_hunks(ranges, cx);
19064                true
19065            } else {
19066                false
19067            }
19068        })
19069    }
19070
19071    fn toggle_diff_hunks_in_ranges(
19072        &mut self,
19073        ranges: Vec<Range<Anchor>>,
19074        cx: &mut Context<Editor>,
19075    ) {
19076        self.buffer.update(cx, |buffer, cx| {
19077            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
19078            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
19079        })
19080    }
19081
19082    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
19083        self.buffer.update(cx, |buffer, cx| {
19084            let snapshot = buffer.snapshot(cx);
19085            let excerpt_id = range.end.excerpt_id;
19086            let point_range = range.to_point(&snapshot);
19087            let expand = !buffer.single_hunk_is_expanded(range, cx);
19088            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
19089        })
19090    }
19091
19092    pub(crate) fn apply_all_diff_hunks(
19093        &mut self,
19094        _: &ApplyAllDiffHunks,
19095        window: &mut Window,
19096        cx: &mut Context<Self>,
19097    ) {
19098        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19099
19100        let buffers = self.buffer.read(cx).all_buffers();
19101        for branch_buffer in buffers {
19102            branch_buffer.update(cx, |branch_buffer, cx| {
19103                branch_buffer.merge_into_base(Vec::new(), cx);
19104            });
19105        }
19106
19107        if let Some(project) = self.project.clone() {
19108            self.save(
19109                SaveOptions {
19110                    format: true,
19111                    autosave: false,
19112                },
19113                project,
19114                window,
19115                cx,
19116            )
19117            .detach_and_log_err(cx);
19118        }
19119    }
19120
19121    pub(crate) fn apply_selected_diff_hunks(
19122        &mut self,
19123        _: &ApplyDiffHunk,
19124        window: &mut Window,
19125        cx: &mut Context<Self>,
19126    ) {
19127        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19128        let snapshot = self.snapshot(window, cx);
19129        let hunks = snapshot.hunks_for_ranges(
19130            self.selections
19131                .all(&snapshot.display_snapshot)
19132                .into_iter()
19133                .map(|selection| selection.range()),
19134        );
19135        let mut ranges_by_buffer = HashMap::default();
19136        self.transact(window, cx, |editor, _window, cx| {
19137            for hunk in hunks {
19138                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
19139                    ranges_by_buffer
19140                        .entry(buffer.clone())
19141                        .or_insert_with(Vec::new)
19142                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
19143                }
19144            }
19145
19146            for (buffer, ranges) in ranges_by_buffer {
19147                buffer.update(cx, |buffer, cx| {
19148                    buffer.merge_into_base(ranges, cx);
19149                });
19150            }
19151        });
19152
19153        if let Some(project) = self.project.clone() {
19154            self.save(
19155                SaveOptions {
19156                    format: true,
19157                    autosave: false,
19158                },
19159                project,
19160                window,
19161                cx,
19162            )
19163            .detach_and_log_err(cx);
19164        }
19165    }
19166
19167    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
19168        if hovered != self.gutter_hovered {
19169            self.gutter_hovered = hovered;
19170            cx.notify();
19171        }
19172    }
19173
19174    pub fn insert_blocks(
19175        &mut self,
19176        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
19177        autoscroll: Option<Autoscroll>,
19178        cx: &mut Context<Self>,
19179    ) -> Vec<CustomBlockId> {
19180        let blocks = self
19181            .display_map
19182            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
19183        if let Some(autoscroll) = autoscroll {
19184            self.request_autoscroll(autoscroll, cx);
19185        }
19186        cx.notify();
19187        blocks
19188    }
19189
19190    pub fn resize_blocks(
19191        &mut self,
19192        heights: HashMap<CustomBlockId, u32>,
19193        autoscroll: Option<Autoscroll>,
19194        cx: &mut Context<Self>,
19195    ) {
19196        self.display_map
19197            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
19198        if let Some(autoscroll) = autoscroll {
19199            self.request_autoscroll(autoscroll, cx);
19200        }
19201        cx.notify();
19202    }
19203
19204    pub fn replace_blocks(
19205        &mut self,
19206        renderers: HashMap<CustomBlockId, RenderBlock>,
19207        autoscroll: Option<Autoscroll>,
19208        cx: &mut Context<Self>,
19209    ) {
19210        self.display_map
19211            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
19212        if let Some(autoscroll) = autoscroll {
19213            self.request_autoscroll(autoscroll, cx);
19214        }
19215        cx.notify();
19216    }
19217
19218    pub fn remove_blocks(
19219        &mut self,
19220        block_ids: HashSet<CustomBlockId>,
19221        autoscroll: Option<Autoscroll>,
19222        cx: &mut Context<Self>,
19223    ) {
19224        self.display_map.update(cx, |display_map, cx| {
19225            display_map.remove_blocks(block_ids, cx)
19226        });
19227        if let Some(autoscroll) = autoscroll {
19228            self.request_autoscroll(autoscroll, cx);
19229        }
19230        cx.notify();
19231    }
19232
19233    pub fn row_for_block(
19234        &self,
19235        block_id: CustomBlockId,
19236        cx: &mut Context<Self>,
19237    ) -> Option<DisplayRow> {
19238        self.display_map
19239            .update(cx, |map, cx| map.row_for_block(block_id, cx))
19240    }
19241
19242    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
19243        self.focused_block = Some(focused_block);
19244    }
19245
19246    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
19247        self.focused_block.take()
19248    }
19249
19250    pub fn insert_creases(
19251        &mut self,
19252        creases: impl IntoIterator<Item = Crease<Anchor>>,
19253        cx: &mut Context<Self>,
19254    ) -> Vec<CreaseId> {
19255        self.display_map
19256            .update(cx, |map, cx| map.insert_creases(creases, cx))
19257    }
19258
19259    pub fn remove_creases(
19260        &mut self,
19261        ids: impl IntoIterator<Item = CreaseId>,
19262        cx: &mut Context<Self>,
19263    ) -> Vec<(CreaseId, Range<Anchor>)> {
19264        self.display_map
19265            .update(cx, |map, cx| map.remove_creases(ids, cx))
19266    }
19267
19268    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
19269        self.display_map
19270            .update(cx, |map, cx| map.snapshot(cx))
19271            .longest_row()
19272    }
19273
19274    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
19275        self.display_map
19276            .update(cx, |map, cx| map.snapshot(cx))
19277            .max_point()
19278    }
19279
19280    pub fn text(&self, cx: &App) -> String {
19281        self.buffer.read(cx).read(cx).text()
19282    }
19283
19284    pub fn is_empty(&self, cx: &App) -> bool {
19285        self.buffer.read(cx).read(cx).is_empty()
19286    }
19287
19288    pub fn text_option(&self, cx: &App) -> Option<String> {
19289        let text = self.text(cx);
19290        let text = text.trim();
19291
19292        if text.is_empty() {
19293            return None;
19294        }
19295
19296        Some(text.to_string())
19297    }
19298
19299    pub fn set_text(
19300        &mut self,
19301        text: impl Into<Arc<str>>,
19302        window: &mut Window,
19303        cx: &mut Context<Self>,
19304    ) {
19305        self.transact(window, cx, |this, _, cx| {
19306            this.buffer
19307                .read(cx)
19308                .as_singleton()
19309                .expect("you can only call set_text on editors for singleton buffers")
19310                .update(cx, |buffer, cx| buffer.set_text(text, cx));
19311        });
19312    }
19313
19314    pub fn display_text(&self, cx: &mut App) -> String {
19315        self.display_map
19316            .update(cx, |map, cx| map.snapshot(cx))
19317            .text()
19318    }
19319
19320    fn create_minimap(
19321        &self,
19322        minimap_settings: MinimapSettings,
19323        window: &mut Window,
19324        cx: &mut Context<Self>,
19325    ) -> Option<Entity<Self>> {
19326        (minimap_settings.minimap_enabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton)
19327            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
19328    }
19329
19330    fn initialize_new_minimap(
19331        &self,
19332        minimap_settings: MinimapSettings,
19333        window: &mut Window,
19334        cx: &mut Context<Self>,
19335    ) -> Entity<Self> {
19336        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
19337
19338        let mut minimap = Editor::new_internal(
19339            EditorMode::Minimap {
19340                parent: cx.weak_entity(),
19341            },
19342            self.buffer.clone(),
19343            None,
19344            Some(self.display_map.clone()),
19345            window,
19346            cx,
19347        );
19348        minimap.scroll_manager.clone_state(&self.scroll_manager);
19349        minimap.set_text_style_refinement(TextStyleRefinement {
19350            font_size: Some(MINIMAP_FONT_SIZE),
19351            font_weight: Some(MINIMAP_FONT_WEIGHT),
19352            ..Default::default()
19353        });
19354        minimap.update_minimap_configuration(minimap_settings, cx);
19355        cx.new(|_| minimap)
19356    }
19357
19358    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
19359        let current_line_highlight = minimap_settings
19360            .current_line_highlight
19361            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
19362        self.set_current_line_highlight(Some(current_line_highlight));
19363    }
19364
19365    pub fn minimap(&self) -> Option<&Entity<Self>> {
19366        self.minimap
19367            .as_ref()
19368            .filter(|_| self.minimap_visibility.visible())
19369    }
19370
19371    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
19372        let mut wrap_guides = smallvec![];
19373
19374        if self.show_wrap_guides == Some(false) {
19375            return wrap_guides;
19376        }
19377
19378        let settings = self.buffer.read(cx).language_settings(cx);
19379        if settings.show_wrap_guides {
19380            match self.soft_wrap_mode(cx) {
19381                SoftWrap::Column(soft_wrap) => {
19382                    wrap_guides.push((soft_wrap as usize, true));
19383                }
19384                SoftWrap::Bounded(soft_wrap) => {
19385                    wrap_guides.push((soft_wrap as usize, true));
19386                }
19387                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
19388            }
19389            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
19390        }
19391
19392        wrap_guides
19393    }
19394
19395    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
19396        let settings = self.buffer.read(cx).language_settings(cx);
19397        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
19398        match mode {
19399            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
19400                SoftWrap::None
19401            }
19402            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
19403            language_settings::SoftWrap::PreferredLineLength => {
19404                SoftWrap::Column(settings.preferred_line_length)
19405            }
19406            language_settings::SoftWrap::Bounded => {
19407                SoftWrap::Bounded(settings.preferred_line_length)
19408            }
19409        }
19410    }
19411
19412    pub fn set_soft_wrap_mode(
19413        &mut self,
19414        mode: language_settings::SoftWrap,
19415
19416        cx: &mut Context<Self>,
19417    ) {
19418        self.soft_wrap_mode_override = Some(mode);
19419        cx.notify();
19420    }
19421
19422    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
19423        self.hard_wrap = hard_wrap;
19424        cx.notify();
19425    }
19426
19427    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
19428        self.text_style_refinement = Some(style);
19429    }
19430
19431    /// called by the Element so we know what style we were most recently rendered with.
19432    pub fn set_style(&mut self, style: EditorStyle, window: &mut Window, cx: &mut Context<Self>) {
19433        // We intentionally do not inform the display map about the minimap style
19434        // so that wrapping is not recalculated and stays consistent for the editor
19435        // and its linked minimap.
19436        if !self.mode.is_minimap() {
19437            let font = style.text.font();
19438            let font_size = style.text.font_size.to_pixels(window.rem_size());
19439            let display_map = self
19440                .placeholder_display_map
19441                .as_ref()
19442                .filter(|_| self.is_empty(cx))
19443                .unwrap_or(&self.display_map);
19444
19445            display_map.update(cx, |map, cx| map.set_font(font, font_size, cx));
19446        }
19447        self.style = Some(style);
19448    }
19449
19450    pub fn style(&self) -> Option<&EditorStyle> {
19451        self.style.as_ref()
19452    }
19453
19454    // Called by the element. This method is not designed to be called outside of the editor
19455    // element's layout code because it does not notify when rewrapping is computed synchronously.
19456    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
19457        if self.is_empty(cx) {
19458            self.placeholder_display_map
19459                .as_ref()
19460                .map_or(false, |display_map| {
19461                    display_map.update(cx, |map, cx| map.set_wrap_width(width, cx))
19462                })
19463        } else {
19464            self.display_map
19465                .update(cx, |map, cx| map.set_wrap_width(width, cx))
19466        }
19467    }
19468
19469    pub fn set_soft_wrap(&mut self) {
19470        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
19471    }
19472
19473    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
19474        if self.soft_wrap_mode_override.is_some() {
19475            self.soft_wrap_mode_override.take();
19476        } else {
19477            let soft_wrap = match self.soft_wrap_mode(cx) {
19478                SoftWrap::GitDiff => return,
19479                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
19480                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
19481                    language_settings::SoftWrap::None
19482                }
19483            };
19484            self.soft_wrap_mode_override = Some(soft_wrap);
19485        }
19486        cx.notify();
19487    }
19488
19489    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
19490        let Some(workspace) = self.workspace() else {
19491            return;
19492        };
19493        let fs = workspace.read(cx).app_state().fs.clone();
19494        let current_show = TabBarSettings::get_global(cx).show;
19495        update_settings_file(fs, cx, move |setting, _| {
19496            setting.tab_bar.get_or_insert_default().show = Some(!current_show);
19497        });
19498    }
19499
19500    pub fn toggle_indent_guides(
19501        &mut self,
19502        _: &ToggleIndentGuides,
19503        _: &mut Window,
19504        cx: &mut Context<Self>,
19505    ) {
19506        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
19507            self.buffer
19508                .read(cx)
19509                .language_settings(cx)
19510                .indent_guides
19511                .enabled
19512        });
19513        self.show_indent_guides = Some(!currently_enabled);
19514        cx.notify();
19515    }
19516
19517    fn should_show_indent_guides(&self) -> Option<bool> {
19518        self.show_indent_guides
19519    }
19520
19521    pub fn toggle_line_numbers(
19522        &mut self,
19523        _: &ToggleLineNumbers,
19524        _: &mut Window,
19525        cx: &mut Context<Self>,
19526    ) {
19527        let mut editor_settings = EditorSettings::get_global(cx).clone();
19528        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
19529        EditorSettings::override_global(editor_settings, cx);
19530    }
19531
19532    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
19533        if let Some(show_line_numbers) = self.show_line_numbers {
19534            return show_line_numbers;
19535        }
19536        EditorSettings::get_global(cx).gutter.line_numbers
19537    }
19538
19539    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
19540        self.use_relative_line_numbers
19541            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
19542    }
19543
19544    pub fn toggle_relative_line_numbers(
19545        &mut self,
19546        _: &ToggleRelativeLineNumbers,
19547        _: &mut Window,
19548        cx: &mut Context<Self>,
19549    ) {
19550        let is_relative = self.should_use_relative_line_numbers(cx);
19551        self.set_relative_line_number(Some(!is_relative), cx)
19552    }
19553
19554    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
19555        self.use_relative_line_numbers = is_relative;
19556        cx.notify();
19557    }
19558
19559    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
19560        self.show_gutter = show_gutter;
19561        cx.notify();
19562    }
19563
19564    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
19565        self.show_scrollbars = ScrollbarAxes {
19566            horizontal: show,
19567            vertical: show,
19568        };
19569        cx.notify();
19570    }
19571
19572    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19573        self.show_scrollbars.vertical = show;
19574        cx.notify();
19575    }
19576
19577    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19578        self.show_scrollbars.horizontal = show;
19579        cx.notify();
19580    }
19581
19582    pub fn set_minimap_visibility(
19583        &mut self,
19584        minimap_visibility: MinimapVisibility,
19585        window: &mut Window,
19586        cx: &mut Context<Self>,
19587    ) {
19588        if self.minimap_visibility != minimap_visibility {
19589            if minimap_visibility.visible() && self.minimap.is_none() {
19590                let minimap_settings = EditorSettings::get_global(cx).minimap;
19591                self.minimap =
19592                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
19593            }
19594            self.minimap_visibility = minimap_visibility;
19595            cx.notify();
19596        }
19597    }
19598
19599    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19600        self.set_show_scrollbars(false, cx);
19601        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
19602    }
19603
19604    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19605        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
19606    }
19607
19608    /// Normally the text in full mode and auto height editors is padded on the
19609    /// left side by roughly half a character width for improved hit testing.
19610    ///
19611    /// Use this method to disable this for cases where this is not wanted (e.g.
19612    /// if you want to align the editor text with some other text above or below)
19613    /// or if you want to add this padding to single-line editors.
19614    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
19615        self.offset_content = offset_content;
19616        cx.notify();
19617    }
19618
19619    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
19620        self.show_line_numbers = Some(show_line_numbers);
19621        cx.notify();
19622    }
19623
19624    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
19625        self.disable_expand_excerpt_buttons = true;
19626        cx.notify();
19627    }
19628
19629    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
19630        self.show_git_diff_gutter = Some(show_git_diff_gutter);
19631        cx.notify();
19632    }
19633
19634    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
19635        self.show_code_actions = Some(show_code_actions);
19636        cx.notify();
19637    }
19638
19639    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
19640        self.show_runnables = Some(show_runnables);
19641        cx.notify();
19642    }
19643
19644    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
19645        self.show_breakpoints = Some(show_breakpoints);
19646        cx.notify();
19647    }
19648
19649    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
19650        if self.display_map.read(cx).masked != masked {
19651            self.display_map.update(cx, |map, _| map.masked = masked);
19652        }
19653        cx.notify()
19654    }
19655
19656    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
19657        self.show_wrap_guides = Some(show_wrap_guides);
19658        cx.notify();
19659    }
19660
19661    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
19662        self.show_indent_guides = Some(show_indent_guides);
19663        cx.notify();
19664    }
19665
19666    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
19667        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
19668            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
19669                && let Some(dir) = file.abs_path(cx).parent()
19670            {
19671                return Some(dir.to_owned());
19672            }
19673        }
19674
19675        None
19676    }
19677
19678    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
19679        self.active_excerpt(cx)?
19680            .1
19681            .read(cx)
19682            .file()
19683            .and_then(|f| f.as_local())
19684    }
19685
19686    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
19687        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19688            let buffer = buffer.read(cx);
19689            if let Some(project_path) = buffer.project_path(cx) {
19690                let project = self.project()?.read(cx);
19691                project.absolute_path(&project_path, cx)
19692            } else {
19693                buffer
19694                    .file()
19695                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
19696            }
19697        })
19698    }
19699
19700    pub fn reveal_in_finder(
19701        &mut self,
19702        _: &RevealInFileManager,
19703        _window: &mut Window,
19704        cx: &mut Context<Self>,
19705    ) {
19706        if let Some(target) = self.target_file(cx) {
19707            cx.reveal_path(&target.abs_path(cx));
19708        }
19709    }
19710
19711    pub fn copy_path(
19712        &mut self,
19713        _: &zed_actions::workspace::CopyPath,
19714        _window: &mut Window,
19715        cx: &mut Context<Self>,
19716    ) {
19717        if let Some(path) = self.target_file_abs_path(cx)
19718            && let Some(path) = path.to_str()
19719        {
19720            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19721        } else {
19722            cx.propagate();
19723        }
19724    }
19725
19726    pub fn copy_relative_path(
19727        &mut self,
19728        _: &zed_actions::workspace::CopyRelativePath,
19729        _window: &mut Window,
19730        cx: &mut Context<Self>,
19731    ) {
19732        if let Some(path) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19733            let project = self.project()?.read(cx);
19734            let path = buffer.read(cx).file()?.path();
19735            let path = path.display(project.path_style(cx));
19736            Some(path)
19737        }) {
19738            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19739        } else {
19740            cx.propagate();
19741        }
19742    }
19743
19744    /// Returns the project path for the editor's buffer, if any buffer is
19745    /// opened in the editor.
19746    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
19747        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
19748            buffer.read(cx).project_path(cx)
19749        } else {
19750            None
19751        }
19752    }
19753
19754    // Returns true if the editor handled a go-to-line request
19755    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
19756        maybe!({
19757            let breakpoint_store = self.breakpoint_store.as_ref()?;
19758
19759            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
19760            else {
19761                self.clear_row_highlights::<ActiveDebugLine>();
19762                return None;
19763            };
19764
19765            let position = active_stack_frame.position;
19766            let buffer_id = position.buffer_id?;
19767            let snapshot = self
19768                .project
19769                .as_ref()?
19770                .read(cx)
19771                .buffer_for_id(buffer_id, cx)?
19772                .read(cx)
19773                .snapshot();
19774
19775            let mut handled = false;
19776            for (id, ExcerptRange { context, .. }) in
19777                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
19778            {
19779                if context.start.cmp(&position, &snapshot).is_ge()
19780                    || context.end.cmp(&position, &snapshot).is_lt()
19781                {
19782                    continue;
19783                }
19784                let snapshot = self.buffer.read(cx).snapshot(cx);
19785                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
19786
19787                handled = true;
19788                self.clear_row_highlights::<ActiveDebugLine>();
19789
19790                self.go_to_line::<ActiveDebugLine>(
19791                    multibuffer_anchor,
19792                    Some(cx.theme().colors().editor_debugger_active_line_background),
19793                    window,
19794                    cx,
19795                );
19796
19797                cx.notify();
19798            }
19799
19800            handled.then_some(())
19801        })
19802        .is_some()
19803    }
19804
19805    pub fn copy_file_name_without_extension(
19806        &mut self,
19807        _: &CopyFileNameWithoutExtension,
19808        _: &mut Window,
19809        cx: &mut Context<Self>,
19810    ) {
19811        if let Some(file) = self.target_file(cx)
19812            && let Some(file_stem) = file.path().file_stem()
19813        {
19814            cx.write_to_clipboard(ClipboardItem::new_string(file_stem.to_string()));
19815        }
19816    }
19817
19818    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
19819        if let Some(file) = self.target_file(cx)
19820            && let Some(name) = file.path().file_name()
19821        {
19822            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
19823        }
19824    }
19825
19826    pub fn toggle_git_blame(
19827        &mut self,
19828        _: &::git::Blame,
19829        window: &mut Window,
19830        cx: &mut Context<Self>,
19831    ) {
19832        self.show_git_blame_gutter = !self.show_git_blame_gutter;
19833
19834        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
19835            self.start_git_blame(true, window, cx);
19836        }
19837
19838        cx.notify();
19839    }
19840
19841    pub fn toggle_git_blame_inline(
19842        &mut self,
19843        _: &ToggleGitBlameInline,
19844        window: &mut Window,
19845        cx: &mut Context<Self>,
19846    ) {
19847        self.toggle_git_blame_inline_internal(true, window, cx);
19848        cx.notify();
19849    }
19850
19851    pub fn open_git_blame_commit(
19852        &mut self,
19853        _: &OpenGitBlameCommit,
19854        window: &mut Window,
19855        cx: &mut Context<Self>,
19856    ) {
19857        self.open_git_blame_commit_internal(window, cx);
19858    }
19859
19860    fn open_git_blame_commit_internal(
19861        &mut self,
19862        window: &mut Window,
19863        cx: &mut Context<Self>,
19864    ) -> Option<()> {
19865        let blame = self.blame.as_ref()?;
19866        let snapshot = self.snapshot(window, cx);
19867        let cursor = self
19868            .selections
19869            .newest::<Point>(&snapshot.display_snapshot)
19870            .head();
19871        let (buffer, point, _) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)?;
19872        let (_, blame_entry) = blame
19873            .update(cx, |blame, cx| {
19874                blame
19875                    .blame_for_rows(
19876                        &[RowInfo {
19877                            buffer_id: Some(buffer.remote_id()),
19878                            buffer_row: Some(point.row),
19879                            ..Default::default()
19880                        }],
19881                        cx,
19882                    )
19883                    .next()
19884            })
19885            .flatten()?;
19886        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
19887        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
19888        let workspace = self.workspace()?.downgrade();
19889        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
19890        None
19891    }
19892
19893    pub fn git_blame_inline_enabled(&self) -> bool {
19894        self.git_blame_inline_enabled
19895    }
19896
19897    pub fn toggle_selection_menu(
19898        &mut self,
19899        _: &ToggleSelectionMenu,
19900        _: &mut Window,
19901        cx: &mut Context<Self>,
19902    ) {
19903        self.show_selection_menu = self
19904            .show_selection_menu
19905            .map(|show_selections_menu| !show_selections_menu)
19906            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
19907
19908        cx.notify();
19909    }
19910
19911    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
19912        self.show_selection_menu
19913            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
19914    }
19915
19916    fn start_git_blame(
19917        &mut self,
19918        user_triggered: bool,
19919        window: &mut Window,
19920        cx: &mut Context<Self>,
19921    ) {
19922        if let Some(project) = self.project() {
19923            if let Some(buffer) = self.buffer().read(cx).as_singleton()
19924                && buffer.read(cx).file().is_none()
19925            {
19926                return;
19927            }
19928
19929            let focused = self.focus_handle(cx).contains_focused(window, cx);
19930
19931            let project = project.clone();
19932            let blame = cx
19933                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
19934            self.blame_subscription =
19935                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
19936            self.blame = Some(blame);
19937        }
19938    }
19939
19940    fn toggle_git_blame_inline_internal(
19941        &mut self,
19942        user_triggered: bool,
19943        window: &mut Window,
19944        cx: &mut Context<Self>,
19945    ) {
19946        if self.git_blame_inline_enabled {
19947            self.git_blame_inline_enabled = false;
19948            self.show_git_blame_inline = false;
19949            self.show_git_blame_inline_delay_task.take();
19950        } else {
19951            self.git_blame_inline_enabled = true;
19952            self.start_git_blame_inline(user_triggered, window, cx);
19953        }
19954
19955        cx.notify();
19956    }
19957
19958    fn start_git_blame_inline(
19959        &mut self,
19960        user_triggered: bool,
19961        window: &mut Window,
19962        cx: &mut Context<Self>,
19963    ) {
19964        self.start_git_blame(user_triggered, window, cx);
19965
19966        if ProjectSettings::get_global(cx)
19967            .git
19968            .inline_blame_delay()
19969            .is_some()
19970        {
19971            self.start_inline_blame_timer(window, cx);
19972        } else {
19973            self.show_git_blame_inline = true
19974        }
19975    }
19976
19977    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
19978        self.blame.as_ref()
19979    }
19980
19981    pub fn show_git_blame_gutter(&self) -> bool {
19982        self.show_git_blame_gutter
19983    }
19984
19985    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
19986        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
19987    }
19988
19989    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
19990        self.show_git_blame_inline
19991            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
19992            && !self.newest_selection_head_on_empty_line(cx)
19993            && self.has_blame_entries(cx)
19994    }
19995
19996    fn has_blame_entries(&self, cx: &App) -> bool {
19997        self.blame()
19998            .is_some_and(|blame| blame.read(cx).has_generated_entries())
19999    }
20000
20001    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
20002        let cursor_anchor = self.selections.newest_anchor().head();
20003
20004        let snapshot = self.buffer.read(cx).snapshot(cx);
20005        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
20006
20007        snapshot.line_len(buffer_row) == 0
20008    }
20009
20010    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
20011        let buffer_and_selection = maybe!({
20012            let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
20013            let selection_range = selection.range();
20014
20015            let multi_buffer = self.buffer().read(cx);
20016            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
20017            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
20018
20019            let (buffer, range, _) = if selection.reversed {
20020                buffer_ranges.first()
20021            } else {
20022                buffer_ranges.last()
20023            }?;
20024
20025            let selection = text::ToPoint::to_point(&range.start, buffer).row
20026                ..text::ToPoint::to_point(&range.end, buffer).row;
20027            Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection))
20028        });
20029
20030        let Some((buffer, selection)) = buffer_and_selection else {
20031            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
20032        };
20033
20034        let Some(project) = self.project() else {
20035            return Task::ready(Err(anyhow!("editor does not have project")));
20036        };
20037
20038        project.update(cx, |project, cx| {
20039            project.get_permalink_to_line(&buffer, selection, cx)
20040        })
20041    }
20042
20043    pub fn copy_permalink_to_line(
20044        &mut self,
20045        _: &CopyPermalinkToLine,
20046        window: &mut Window,
20047        cx: &mut Context<Self>,
20048    ) {
20049        let permalink_task = self.get_permalink_to_line(cx);
20050        let workspace = self.workspace();
20051
20052        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
20053            Ok(permalink) => {
20054                cx.update(|_, cx| {
20055                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
20056                })
20057                .ok();
20058            }
20059            Err(err) => {
20060                let message = format!("Failed to copy permalink: {err}");
20061
20062                anyhow::Result::<()>::Err(err).log_err();
20063
20064                if let Some(workspace) = workspace {
20065                    workspace
20066                        .update_in(cx, |workspace, _, cx| {
20067                            struct CopyPermalinkToLine;
20068
20069                            workspace.show_toast(
20070                                Toast::new(
20071                                    NotificationId::unique::<CopyPermalinkToLine>(),
20072                                    message,
20073                                ),
20074                                cx,
20075                            )
20076                        })
20077                        .ok();
20078                }
20079            }
20080        })
20081        .detach();
20082    }
20083
20084    pub fn copy_file_location(
20085        &mut self,
20086        _: &CopyFileLocation,
20087        _: &mut Window,
20088        cx: &mut Context<Self>,
20089    ) {
20090        let selection = self
20091            .selections
20092            .newest::<Point>(&self.display_snapshot(cx))
20093            .start
20094            .row
20095            + 1;
20096        if let Some(file) = self.target_file(cx) {
20097            let path = file.path().display(file.path_style(cx));
20098            cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
20099        }
20100    }
20101
20102    pub fn open_permalink_to_line(
20103        &mut self,
20104        _: &OpenPermalinkToLine,
20105        window: &mut Window,
20106        cx: &mut Context<Self>,
20107    ) {
20108        let permalink_task = self.get_permalink_to_line(cx);
20109        let workspace = self.workspace();
20110
20111        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
20112            Ok(permalink) => {
20113                cx.update(|_, cx| {
20114                    cx.open_url(permalink.as_ref());
20115                })
20116                .ok();
20117            }
20118            Err(err) => {
20119                let message = format!("Failed to open permalink: {err}");
20120
20121                anyhow::Result::<()>::Err(err).log_err();
20122
20123                if let Some(workspace) = workspace {
20124                    workspace
20125                        .update(cx, |workspace, cx| {
20126                            struct OpenPermalinkToLine;
20127
20128                            workspace.show_toast(
20129                                Toast::new(
20130                                    NotificationId::unique::<OpenPermalinkToLine>(),
20131                                    message,
20132                                ),
20133                                cx,
20134                            )
20135                        })
20136                        .ok();
20137                }
20138            }
20139        })
20140        .detach();
20141    }
20142
20143    pub fn insert_uuid_v4(
20144        &mut self,
20145        _: &InsertUuidV4,
20146        window: &mut Window,
20147        cx: &mut Context<Self>,
20148    ) {
20149        self.insert_uuid(UuidVersion::V4, window, cx);
20150    }
20151
20152    pub fn insert_uuid_v7(
20153        &mut self,
20154        _: &InsertUuidV7,
20155        window: &mut Window,
20156        cx: &mut Context<Self>,
20157    ) {
20158        self.insert_uuid(UuidVersion::V7, window, cx);
20159    }
20160
20161    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
20162        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
20163        self.transact(window, cx, |this, window, cx| {
20164            let edits = this
20165                .selections
20166                .all::<Point>(&this.display_snapshot(cx))
20167                .into_iter()
20168                .map(|selection| {
20169                    let uuid = match version {
20170                        UuidVersion::V4 => uuid::Uuid::new_v4(),
20171                        UuidVersion::V7 => uuid::Uuid::now_v7(),
20172                    };
20173
20174                    (selection.range(), uuid.to_string())
20175                });
20176            this.edit(edits, cx);
20177            this.refresh_edit_prediction(true, false, window, cx);
20178        });
20179    }
20180
20181    pub fn open_selections_in_multibuffer(
20182        &mut self,
20183        _: &OpenSelectionsInMultibuffer,
20184        window: &mut Window,
20185        cx: &mut Context<Self>,
20186    ) {
20187        let multibuffer = self.buffer.read(cx);
20188
20189        let Some(buffer) = multibuffer.as_singleton() else {
20190            return;
20191        };
20192
20193        let Some(workspace) = self.workspace() else {
20194            return;
20195        };
20196
20197        let title = multibuffer.title(cx).to_string();
20198
20199        let locations = self
20200            .selections
20201            .all_anchors(cx)
20202            .iter()
20203            .map(|selection| {
20204                (
20205                    buffer.clone(),
20206                    (selection.start.text_anchor..selection.end.text_anchor)
20207                        .to_point(buffer.read(cx)),
20208                )
20209            })
20210            .into_group_map();
20211
20212        cx.spawn_in(window, async move |_, cx| {
20213            workspace.update_in(cx, |workspace, window, cx| {
20214                Self::open_locations_in_multibuffer(
20215                    workspace,
20216                    locations,
20217                    format!("Selections for '{title}'"),
20218                    false,
20219                    MultibufferSelectionMode::All,
20220                    window,
20221                    cx,
20222                );
20223            })
20224        })
20225        .detach();
20226    }
20227
20228    /// Adds a row highlight for the given range. If a row has multiple highlights, the
20229    /// last highlight added will be used.
20230    ///
20231    /// If the range ends at the beginning of a line, then that line will not be highlighted.
20232    pub fn highlight_rows<T: 'static>(
20233        &mut self,
20234        range: Range<Anchor>,
20235        color: Hsla,
20236        options: RowHighlightOptions,
20237        cx: &mut Context<Self>,
20238    ) {
20239        let snapshot = self.buffer().read(cx).snapshot(cx);
20240        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20241        let ix = row_highlights.binary_search_by(|highlight| {
20242            Ordering::Equal
20243                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
20244                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
20245        });
20246
20247        if let Err(mut ix) = ix {
20248            let index = post_inc(&mut self.highlight_order);
20249
20250            // If this range intersects with the preceding highlight, then merge it with
20251            // the preceding highlight. Otherwise insert a new highlight.
20252            let mut merged = false;
20253            if ix > 0 {
20254                let prev_highlight = &mut row_highlights[ix - 1];
20255                if prev_highlight
20256                    .range
20257                    .end
20258                    .cmp(&range.start, &snapshot)
20259                    .is_ge()
20260                {
20261                    ix -= 1;
20262                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
20263                        prev_highlight.range.end = range.end;
20264                    }
20265                    merged = true;
20266                    prev_highlight.index = index;
20267                    prev_highlight.color = color;
20268                    prev_highlight.options = options;
20269                }
20270            }
20271
20272            if !merged {
20273                row_highlights.insert(
20274                    ix,
20275                    RowHighlight {
20276                        range,
20277                        index,
20278                        color,
20279                        options,
20280                        type_id: TypeId::of::<T>(),
20281                    },
20282                );
20283            }
20284
20285            // If any of the following highlights intersect with this one, merge them.
20286            while let Some(next_highlight) = row_highlights.get(ix + 1) {
20287                let highlight = &row_highlights[ix];
20288                if next_highlight
20289                    .range
20290                    .start
20291                    .cmp(&highlight.range.end, &snapshot)
20292                    .is_le()
20293                {
20294                    if next_highlight
20295                        .range
20296                        .end
20297                        .cmp(&highlight.range.end, &snapshot)
20298                        .is_gt()
20299                    {
20300                        row_highlights[ix].range.end = next_highlight.range.end;
20301                    }
20302                    row_highlights.remove(ix + 1);
20303                } else {
20304                    break;
20305                }
20306            }
20307        }
20308    }
20309
20310    /// Remove any highlighted row ranges of the given type that intersect the
20311    /// given ranges.
20312    pub fn remove_highlighted_rows<T: 'static>(
20313        &mut self,
20314        ranges_to_remove: Vec<Range<Anchor>>,
20315        cx: &mut Context<Self>,
20316    ) {
20317        let snapshot = self.buffer().read(cx).snapshot(cx);
20318        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20319        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20320        row_highlights.retain(|highlight| {
20321            while let Some(range_to_remove) = ranges_to_remove.peek() {
20322                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
20323                    Ordering::Less | Ordering::Equal => {
20324                        ranges_to_remove.next();
20325                    }
20326                    Ordering::Greater => {
20327                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
20328                            Ordering::Less | Ordering::Equal => {
20329                                return false;
20330                            }
20331                            Ordering::Greater => break,
20332                        }
20333                    }
20334                }
20335            }
20336
20337            true
20338        })
20339    }
20340
20341    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
20342    pub fn clear_row_highlights<T: 'static>(&mut self) {
20343        self.highlighted_rows.remove(&TypeId::of::<T>());
20344    }
20345
20346    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
20347    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
20348        self.highlighted_rows
20349            .get(&TypeId::of::<T>())
20350            .map_or(&[] as &[_], |vec| vec.as_slice())
20351            .iter()
20352            .map(|highlight| (highlight.range.clone(), highlight.color))
20353    }
20354
20355    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
20356    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
20357    /// Allows to ignore certain kinds of highlights.
20358    pub fn highlighted_display_rows(
20359        &self,
20360        window: &mut Window,
20361        cx: &mut App,
20362    ) -> BTreeMap<DisplayRow, LineHighlight> {
20363        let snapshot = self.snapshot(window, cx);
20364        let mut used_highlight_orders = HashMap::default();
20365        self.highlighted_rows
20366            .iter()
20367            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
20368            .fold(
20369                BTreeMap::<DisplayRow, LineHighlight>::new(),
20370                |mut unique_rows, highlight| {
20371                    let start = highlight.range.start.to_display_point(&snapshot);
20372                    let end = highlight.range.end.to_display_point(&snapshot);
20373                    let start_row = start.row().0;
20374                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
20375                        && end.column() == 0
20376                    {
20377                        end.row().0.saturating_sub(1)
20378                    } else {
20379                        end.row().0
20380                    };
20381                    for row in start_row..=end_row {
20382                        let used_index =
20383                            used_highlight_orders.entry(row).or_insert(highlight.index);
20384                        if highlight.index >= *used_index {
20385                            *used_index = highlight.index;
20386                            unique_rows.insert(
20387                                DisplayRow(row),
20388                                LineHighlight {
20389                                    include_gutter: highlight.options.include_gutter,
20390                                    border: None,
20391                                    background: highlight.color.into(),
20392                                    type_id: Some(highlight.type_id),
20393                                },
20394                            );
20395                        }
20396                    }
20397                    unique_rows
20398                },
20399            )
20400    }
20401
20402    pub fn highlighted_display_row_for_autoscroll(
20403        &self,
20404        snapshot: &DisplaySnapshot,
20405    ) -> Option<DisplayRow> {
20406        self.highlighted_rows
20407            .values()
20408            .flat_map(|highlighted_rows| highlighted_rows.iter())
20409            .filter_map(|highlight| {
20410                if highlight.options.autoscroll {
20411                    Some(highlight.range.start.to_display_point(snapshot).row())
20412                } else {
20413                    None
20414                }
20415            })
20416            .min()
20417    }
20418
20419    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
20420        self.highlight_background::<SearchWithinRange>(
20421            ranges,
20422            |colors| colors.colors().editor_document_highlight_read_background,
20423            cx,
20424        )
20425    }
20426
20427    pub fn set_breadcrumb_header(&mut self, new_header: String) {
20428        self.breadcrumb_header = Some(new_header);
20429    }
20430
20431    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
20432        self.clear_background_highlights::<SearchWithinRange>(cx);
20433    }
20434
20435    pub fn highlight_background<T: 'static>(
20436        &mut self,
20437        ranges: &[Range<Anchor>],
20438        color_fetcher: fn(&Theme) -> Hsla,
20439        cx: &mut Context<Self>,
20440    ) {
20441        self.background_highlights.insert(
20442            HighlightKey::Type(TypeId::of::<T>()),
20443            (color_fetcher, Arc::from(ranges)),
20444        );
20445        self.scrollbar_marker_state.dirty = true;
20446        cx.notify();
20447    }
20448
20449    pub fn highlight_background_key<T: 'static>(
20450        &mut self,
20451        key: usize,
20452        ranges: &[Range<Anchor>],
20453        color_fetcher: fn(&Theme) -> Hsla,
20454        cx: &mut Context<Self>,
20455    ) {
20456        self.background_highlights.insert(
20457            HighlightKey::TypePlus(TypeId::of::<T>(), key),
20458            (color_fetcher, Arc::from(ranges)),
20459        );
20460        self.scrollbar_marker_state.dirty = true;
20461        cx.notify();
20462    }
20463
20464    pub fn clear_background_highlights<T: 'static>(
20465        &mut self,
20466        cx: &mut Context<Self>,
20467    ) -> Option<BackgroundHighlight> {
20468        let text_highlights = self
20469            .background_highlights
20470            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
20471        if !text_highlights.1.is_empty() {
20472            self.scrollbar_marker_state.dirty = true;
20473            cx.notify();
20474        }
20475        Some(text_highlights)
20476    }
20477
20478    pub fn highlight_gutter<T: 'static>(
20479        &mut self,
20480        ranges: impl Into<Vec<Range<Anchor>>>,
20481        color_fetcher: fn(&App) -> Hsla,
20482        cx: &mut Context<Self>,
20483    ) {
20484        self.gutter_highlights
20485            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
20486        cx.notify();
20487    }
20488
20489    pub fn clear_gutter_highlights<T: 'static>(
20490        &mut self,
20491        cx: &mut Context<Self>,
20492    ) -> Option<GutterHighlight> {
20493        cx.notify();
20494        self.gutter_highlights.remove(&TypeId::of::<T>())
20495    }
20496
20497    pub fn insert_gutter_highlight<T: 'static>(
20498        &mut self,
20499        range: Range<Anchor>,
20500        color_fetcher: fn(&App) -> Hsla,
20501        cx: &mut Context<Self>,
20502    ) {
20503        let snapshot = self.buffer().read(cx).snapshot(cx);
20504        let mut highlights = self
20505            .gutter_highlights
20506            .remove(&TypeId::of::<T>())
20507            .map(|(_, highlights)| highlights)
20508            .unwrap_or_default();
20509        let ix = highlights.binary_search_by(|highlight| {
20510            Ordering::Equal
20511                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
20512                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
20513        });
20514        if let Err(ix) = ix {
20515            highlights.insert(ix, range);
20516        }
20517        self.gutter_highlights
20518            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
20519    }
20520
20521    pub fn remove_gutter_highlights<T: 'static>(
20522        &mut self,
20523        ranges_to_remove: Vec<Range<Anchor>>,
20524        cx: &mut Context<Self>,
20525    ) {
20526        let snapshot = self.buffer().read(cx).snapshot(cx);
20527        let Some((color_fetcher, mut gutter_highlights)) =
20528            self.gutter_highlights.remove(&TypeId::of::<T>())
20529        else {
20530            return;
20531        };
20532        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20533        gutter_highlights.retain(|highlight| {
20534            while let Some(range_to_remove) = ranges_to_remove.peek() {
20535                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
20536                    Ordering::Less | Ordering::Equal => {
20537                        ranges_to_remove.next();
20538                    }
20539                    Ordering::Greater => {
20540                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
20541                            Ordering::Less | Ordering::Equal => {
20542                                return false;
20543                            }
20544                            Ordering::Greater => break,
20545                        }
20546                    }
20547                }
20548            }
20549
20550            true
20551        });
20552        self.gutter_highlights
20553            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
20554    }
20555
20556    #[cfg(feature = "test-support")]
20557    pub fn all_text_highlights(
20558        &self,
20559        window: &mut Window,
20560        cx: &mut Context<Self>,
20561    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
20562        let snapshot = self.snapshot(window, cx);
20563        self.display_map.update(cx, |display_map, _| {
20564            display_map
20565                .all_text_highlights()
20566                .map(|highlight| {
20567                    let (style, ranges) = highlight.as_ref();
20568                    (
20569                        *style,
20570                        ranges
20571                            .iter()
20572                            .map(|range| range.clone().to_display_points(&snapshot))
20573                            .collect(),
20574                    )
20575                })
20576                .collect()
20577        })
20578    }
20579
20580    #[cfg(feature = "test-support")]
20581    pub fn all_text_background_highlights(
20582        &self,
20583        window: &mut Window,
20584        cx: &mut Context<Self>,
20585    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20586        let snapshot = self.snapshot(window, cx);
20587        let buffer = &snapshot.buffer_snapshot();
20588        let start = buffer.anchor_before(0);
20589        let end = buffer.anchor_after(buffer.len());
20590        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
20591    }
20592
20593    #[cfg(any(test, feature = "test-support"))]
20594    pub fn sorted_background_highlights_in_range(
20595        &self,
20596        search_range: Range<Anchor>,
20597        display_snapshot: &DisplaySnapshot,
20598        theme: &Theme,
20599    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20600        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
20601        res.sort_by(|a, b| {
20602            a.0.start
20603                .cmp(&b.0.start)
20604                .then_with(|| a.0.end.cmp(&b.0.end))
20605                .then_with(|| a.1.cmp(&b.1))
20606        });
20607        res
20608    }
20609
20610    #[cfg(feature = "test-support")]
20611    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
20612        let snapshot = self.buffer().read(cx).snapshot(cx);
20613
20614        let highlights = self
20615            .background_highlights
20616            .get(&HighlightKey::Type(TypeId::of::<
20617                items::BufferSearchHighlights,
20618            >()));
20619
20620        if let Some((_color, ranges)) = highlights {
20621            ranges
20622                .iter()
20623                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
20624                .collect_vec()
20625        } else {
20626            vec![]
20627        }
20628    }
20629
20630    fn document_highlights_for_position<'a>(
20631        &'a self,
20632        position: Anchor,
20633        buffer: &'a MultiBufferSnapshot,
20634    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
20635        let read_highlights = self
20636            .background_highlights
20637            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
20638            .map(|h| &h.1);
20639        let write_highlights = self
20640            .background_highlights
20641            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
20642            .map(|h| &h.1);
20643        let left_position = position.bias_left(buffer);
20644        let right_position = position.bias_right(buffer);
20645        read_highlights
20646            .into_iter()
20647            .chain(write_highlights)
20648            .flat_map(move |ranges| {
20649                let start_ix = match ranges.binary_search_by(|probe| {
20650                    let cmp = probe.end.cmp(&left_position, buffer);
20651                    if cmp.is_ge() {
20652                        Ordering::Greater
20653                    } else {
20654                        Ordering::Less
20655                    }
20656                }) {
20657                    Ok(i) | Err(i) => i,
20658                };
20659
20660                ranges[start_ix..]
20661                    .iter()
20662                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
20663            })
20664    }
20665
20666    pub fn has_background_highlights<T: 'static>(&self) -> bool {
20667        self.background_highlights
20668            .get(&HighlightKey::Type(TypeId::of::<T>()))
20669            .is_some_and(|(_, highlights)| !highlights.is_empty())
20670    }
20671
20672    /// Returns all background highlights for a given range.
20673    ///
20674    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
20675    pub fn background_highlights_in_range(
20676        &self,
20677        search_range: Range<Anchor>,
20678        display_snapshot: &DisplaySnapshot,
20679        theme: &Theme,
20680    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20681        let mut results = Vec::new();
20682        for (color_fetcher, ranges) in self.background_highlights.values() {
20683            let color = color_fetcher(theme);
20684            let start_ix = match ranges.binary_search_by(|probe| {
20685                let cmp = probe
20686                    .end
20687                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
20688                if cmp.is_gt() {
20689                    Ordering::Greater
20690                } else {
20691                    Ordering::Less
20692                }
20693            }) {
20694                Ok(i) | Err(i) => i,
20695            };
20696            for range in &ranges[start_ix..] {
20697                if range
20698                    .start
20699                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
20700                    .is_ge()
20701                {
20702                    break;
20703                }
20704
20705                let start = range.start.to_display_point(display_snapshot);
20706                let end = range.end.to_display_point(display_snapshot);
20707                results.push((start..end, color))
20708            }
20709        }
20710        results
20711    }
20712
20713    pub fn gutter_highlights_in_range(
20714        &self,
20715        search_range: Range<Anchor>,
20716        display_snapshot: &DisplaySnapshot,
20717        cx: &App,
20718    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20719        let mut results = Vec::new();
20720        for (color_fetcher, ranges) in self.gutter_highlights.values() {
20721            let color = color_fetcher(cx);
20722            let start_ix = match ranges.binary_search_by(|probe| {
20723                let cmp = probe
20724                    .end
20725                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
20726                if cmp.is_gt() {
20727                    Ordering::Greater
20728                } else {
20729                    Ordering::Less
20730                }
20731            }) {
20732                Ok(i) | Err(i) => i,
20733            };
20734            for range in &ranges[start_ix..] {
20735                if range
20736                    .start
20737                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
20738                    .is_ge()
20739                {
20740                    break;
20741                }
20742
20743                let start = range.start.to_display_point(display_snapshot);
20744                let end = range.end.to_display_point(display_snapshot);
20745                results.push((start..end, color))
20746            }
20747        }
20748        results
20749    }
20750
20751    /// Get the text ranges corresponding to the redaction query
20752    pub fn redacted_ranges(
20753        &self,
20754        search_range: Range<Anchor>,
20755        display_snapshot: &DisplaySnapshot,
20756        cx: &App,
20757    ) -> Vec<Range<DisplayPoint>> {
20758        display_snapshot
20759            .buffer_snapshot()
20760            .redacted_ranges(search_range, |file| {
20761                if let Some(file) = file {
20762                    file.is_private()
20763                        && EditorSettings::get(
20764                            Some(SettingsLocation {
20765                                worktree_id: file.worktree_id(cx),
20766                                path: file.path().as_ref(),
20767                            }),
20768                            cx,
20769                        )
20770                        .redact_private_values
20771                } else {
20772                    false
20773                }
20774            })
20775            .map(|range| {
20776                range.start.to_display_point(display_snapshot)
20777                    ..range.end.to_display_point(display_snapshot)
20778            })
20779            .collect()
20780    }
20781
20782    pub fn highlight_text_key<T: 'static>(
20783        &mut self,
20784        key: usize,
20785        ranges: Vec<Range<Anchor>>,
20786        style: HighlightStyle,
20787        cx: &mut Context<Self>,
20788    ) {
20789        self.display_map.update(cx, |map, _| {
20790            map.highlight_text(
20791                HighlightKey::TypePlus(TypeId::of::<T>(), key),
20792                ranges,
20793                style,
20794            );
20795        });
20796        cx.notify();
20797    }
20798
20799    pub fn highlight_text<T: 'static>(
20800        &mut self,
20801        ranges: Vec<Range<Anchor>>,
20802        style: HighlightStyle,
20803        cx: &mut Context<Self>,
20804    ) {
20805        self.display_map.update(cx, |map, _| {
20806            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
20807        });
20808        cx.notify();
20809    }
20810
20811    pub(crate) fn highlight_inlays<T: 'static>(
20812        &mut self,
20813        highlights: Vec<InlayHighlight>,
20814        style: HighlightStyle,
20815        cx: &mut Context<Self>,
20816    ) {
20817        self.display_map.update(cx, |map, _| {
20818            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
20819        });
20820        cx.notify();
20821    }
20822
20823    pub fn text_highlights<'a, T: 'static>(
20824        &'a self,
20825        cx: &'a App,
20826    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
20827        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
20828    }
20829
20830    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
20831        let cleared = self
20832            .display_map
20833            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
20834        if cleared {
20835            cx.notify();
20836        }
20837    }
20838
20839    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
20840        (self.read_only(cx) || self.blink_manager.read(cx).visible())
20841            && self.focus_handle.is_focused(window)
20842    }
20843
20844    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
20845        self.show_cursor_when_unfocused = is_enabled;
20846        cx.notify();
20847    }
20848
20849    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
20850        cx.notify();
20851    }
20852
20853    fn on_debug_session_event(
20854        &mut self,
20855        _session: Entity<Session>,
20856        event: &SessionEvent,
20857        cx: &mut Context<Self>,
20858    ) {
20859        if let SessionEvent::InvalidateInlineValue = event {
20860            self.refresh_inline_values(cx);
20861        }
20862    }
20863
20864    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
20865        let Some(project) = self.project.clone() else {
20866            return;
20867        };
20868
20869        if !self.inline_value_cache.enabled {
20870            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
20871            self.splice_inlays(&inlays, Vec::new(), cx);
20872            return;
20873        }
20874
20875        let current_execution_position = self
20876            .highlighted_rows
20877            .get(&TypeId::of::<ActiveDebugLine>())
20878            .and_then(|lines| lines.last().map(|line| line.range.end));
20879
20880        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
20881            let inline_values = editor
20882                .update(cx, |editor, cx| {
20883                    let Some(current_execution_position) = current_execution_position else {
20884                        return Some(Task::ready(Ok(Vec::new())));
20885                    };
20886
20887                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
20888                        let snapshot = buffer.snapshot(cx);
20889
20890                        let excerpt = snapshot.excerpt_containing(
20891                            current_execution_position..current_execution_position,
20892                        )?;
20893
20894                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
20895                    })?;
20896
20897                    let range =
20898                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
20899
20900                    project.inline_values(buffer, range, cx)
20901                })
20902                .ok()
20903                .flatten()?
20904                .await
20905                .context("refreshing debugger inlays")
20906                .log_err()?;
20907
20908            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
20909
20910            for (buffer_id, inline_value) in inline_values
20911                .into_iter()
20912                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
20913            {
20914                buffer_inline_values
20915                    .entry(buffer_id)
20916                    .or_default()
20917                    .push(inline_value);
20918            }
20919
20920            editor
20921                .update(cx, |editor, cx| {
20922                    let snapshot = editor.buffer.read(cx).snapshot(cx);
20923                    let mut new_inlays = Vec::default();
20924
20925                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
20926                        let buffer_id = buffer_snapshot.remote_id();
20927                        buffer_inline_values
20928                            .get(&buffer_id)
20929                            .into_iter()
20930                            .flatten()
20931                            .for_each(|hint| {
20932                                let inlay = Inlay::debugger(
20933                                    post_inc(&mut editor.next_inlay_id),
20934                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
20935                                    hint.text(),
20936                                );
20937                                if !inlay.text().chars().contains(&'\n') {
20938                                    new_inlays.push(inlay);
20939                                }
20940                            });
20941                    }
20942
20943                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
20944                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
20945
20946                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
20947                })
20948                .ok()?;
20949            Some(())
20950        });
20951    }
20952
20953    fn on_buffer_event(
20954        &mut self,
20955        multibuffer: &Entity<MultiBuffer>,
20956        event: &multi_buffer::Event,
20957        window: &mut Window,
20958        cx: &mut Context<Self>,
20959    ) {
20960        match event {
20961            multi_buffer::Event::Edited { edited_buffer } => {
20962                self.scrollbar_marker_state.dirty = true;
20963                self.active_indent_guides_state.dirty = true;
20964                self.refresh_active_diagnostics(cx);
20965                self.refresh_code_actions(window, cx);
20966                self.refresh_selected_text_highlights(true, window, cx);
20967                self.refresh_single_line_folds(window, cx);
20968                self.refresh_matching_bracket_highlights(window, cx);
20969                if self.has_active_edit_prediction() {
20970                    self.update_visible_edit_prediction(window, cx);
20971                }
20972
20973                if let Some(edited_buffer) = edited_buffer {
20974                    if edited_buffer.read(cx).file().is_none() {
20975                        cx.emit(EditorEvent::TitleChanged);
20976                    }
20977
20978                    let buffer_id = edited_buffer.read(cx).remote_id();
20979                    if let Some(project) = self.project.clone() {
20980                        self.register_buffer(buffer_id, cx);
20981                        self.update_lsp_data(Some(buffer_id), window, cx);
20982                        #[allow(clippy::mutable_key_type)]
20983                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
20984                            multibuffer
20985                                .all_buffers()
20986                                .into_iter()
20987                                .filter_map(|buffer| {
20988                                    buffer.update(cx, |buffer, cx| {
20989                                        let language = buffer.language()?;
20990                                        let should_discard = project.update(cx, |project, cx| {
20991                                            project.is_local()
20992                                                && !project.has_language_servers_for(buffer, cx)
20993                                        });
20994                                        should_discard.not().then_some(language.clone())
20995                                    })
20996                                })
20997                                .collect::<HashSet<_>>()
20998                        });
20999                        if !languages_affected.is_empty() {
21000                            self.refresh_inlay_hints(
21001                                InlayHintRefreshReason::BufferEdited(languages_affected),
21002                                cx,
21003                            );
21004                        }
21005                    }
21006                }
21007
21008                cx.emit(EditorEvent::BufferEdited);
21009                cx.emit(SearchEvent::MatchesInvalidated);
21010
21011                let Some(project) = &self.project else { return };
21012                let (telemetry, is_via_ssh) = {
21013                    let project = project.read(cx);
21014                    let telemetry = project.client().telemetry().clone();
21015                    let is_via_ssh = project.is_via_remote_server();
21016                    (telemetry, is_via_ssh)
21017                };
21018                telemetry.log_edit_event("editor", is_via_ssh);
21019            }
21020            multi_buffer::Event::ExcerptsAdded {
21021                buffer,
21022                predecessor,
21023                excerpts,
21024            } => {
21025                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21026                let buffer_id = buffer.read(cx).remote_id();
21027                if self.buffer.read(cx).diff_for(buffer_id).is_none()
21028                    && let Some(project) = &self.project
21029                {
21030                    update_uncommitted_diff_for_buffer(
21031                        cx.entity(),
21032                        project,
21033                        [buffer.clone()],
21034                        self.buffer.clone(),
21035                        cx,
21036                    )
21037                    .detach();
21038                }
21039                self.update_lsp_data(Some(buffer_id), window, cx);
21040                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
21041                cx.emit(EditorEvent::ExcerptsAdded {
21042                    buffer: buffer.clone(),
21043                    predecessor: *predecessor,
21044                    excerpts: excerpts.clone(),
21045                });
21046            }
21047            multi_buffer::Event::ExcerptsRemoved {
21048                ids,
21049                removed_buffer_ids,
21050            } => {
21051                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
21052                for buffer_id in removed_buffer_ids {
21053                    self.registered_buffers.remove(buffer_id);
21054                }
21055                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21056                cx.emit(EditorEvent::ExcerptsRemoved {
21057                    ids: ids.clone(),
21058                    removed_buffer_ids: removed_buffer_ids.clone(),
21059                });
21060            }
21061            multi_buffer::Event::ExcerptsEdited {
21062                excerpt_ids,
21063                buffer_ids,
21064            } => {
21065                self.display_map.update(cx, |map, cx| {
21066                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
21067                });
21068                cx.emit(EditorEvent::ExcerptsEdited {
21069                    ids: excerpt_ids.clone(),
21070                });
21071            }
21072            multi_buffer::Event::ExcerptsExpanded { ids } => {
21073                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
21074                self.refresh_document_highlights(cx);
21075                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
21076            }
21077            multi_buffer::Event::Reparsed(buffer_id) => {
21078                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21079                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21080
21081                cx.emit(EditorEvent::Reparsed(*buffer_id));
21082            }
21083            multi_buffer::Event::DiffHunksToggled => {
21084                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21085            }
21086            multi_buffer::Event::LanguageChanged(buffer_id) => {
21087                self.registered_buffers.remove(&buffer_id);
21088                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21089                cx.emit(EditorEvent::Reparsed(*buffer_id));
21090                cx.notify();
21091            }
21092            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
21093            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
21094            multi_buffer::Event::FileHandleChanged
21095            | multi_buffer::Event::Reloaded
21096            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
21097            multi_buffer::Event::DiagnosticsUpdated => {
21098                self.update_diagnostics_state(window, cx);
21099            }
21100            _ => {}
21101        };
21102    }
21103
21104    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
21105        if !self.diagnostics_enabled() {
21106            return;
21107        }
21108        self.refresh_active_diagnostics(cx);
21109        self.refresh_inline_diagnostics(true, window, cx);
21110        self.scrollbar_marker_state.dirty = true;
21111        cx.notify();
21112    }
21113
21114    pub fn start_temporary_diff_override(&mut self) {
21115        self.load_diff_task.take();
21116        self.temporary_diff_override = true;
21117    }
21118
21119    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
21120        self.temporary_diff_override = false;
21121        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
21122        self.buffer.update(cx, |buffer, cx| {
21123            buffer.set_all_diff_hunks_collapsed(cx);
21124        });
21125
21126        if let Some(project) = self.project.clone() {
21127            self.load_diff_task = Some(
21128                update_uncommitted_diff_for_buffer(
21129                    cx.entity(),
21130                    &project,
21131                    self.buffer.read(cx).all_buffers(),
21132                    self.buffer.clone(),
21133                    cx,
21134                )
21135                .shared(),
21136            );
21137        }
21138    }
21139
21140    fn on_display_map_changed(
21141        &mut self,
21142        _: Entity<DisplayMap>,
21143        _: &mut Window,
21144        cx: &mut Context<Self>,
21145    ) {
21146        cx.notify();
21147    }
21148
21149    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21150        if self.diagnostics_enabled() {
21151            let new_severity = EditorSettings::get_global(cx)
21152                .diagnostics_max_severity
21153                .unwrap_or(DiagnosticSeverity::Hint);
21154            self.set_max_diagnostics_severity(new_severity, cx);
21155        }
21156        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21157        self.update_edit_prediction_settings(cx);
21158        self.refresh_edit_prediction(true, false, window, cx);
21159        self.refresh_inline_values(cx);
21160        self.refresh_inlay_hints(
21161            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
21162                self.selections.newest_anchor().head(),
21163                &self.buffer.read(cx).snapshot(cx),
21164                cx,
21165            )),
21166            cx,
21167        );
21168
21169        let old_cursor_shape = self.cursor_shape;
21170        let old_show_breadcrumbs = self.show_breadcrumbs;
21171
21172        {
21173            let editor_settings = EditorSettings::get_global(cx);
21174            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
21175            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
21176            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
21177            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
21178        }
21179
21180        if old_cursor_shape != self.cursor_shape {
21181            cx.emit(EditorEvent::CursorShapeChanged);
21182        }
21183
21184        if old_show_breadcrumbs != self.show_breadcrumbs {
21185            cx.emit(EditorEvent::BreadcrumbsChanged);
21186        }
21187
21188        let project_settings = ProjectSettings::get_global(cx);
21189        self.serialize_dirty_buffers =
21190            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
21191
21192        if self.mode.is_full() {
21193            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
21194            let inline_blame_enabled = project_settings.git.inline_blame.enabled;
21195            if self.show_inline_diagnostics != show_inline_diagnostics {
21196                self.show_inline_diagnostics = show_inline_diagnostics;
21197                self.refresh_inline_diagnostics(false, window, cx);
21198            }
21199
21200            if self.git_blame_inline_enabled != inline_blame_enabled {
21201                self.toggle_git_blame_inline_internal(false, window, cx);
21202            }
21203
21204            let minimap_settings = EditorSettings::get_global(cx).minimap;
21205            if self.minimap_visibility != MinimapVisibility::Disabled {
21206                if self.minimap_visibility.settings_visibility()
21207                    != minimap_settings.minimap_enabled()
21208                {
21209                    self.set_minimap_visibility(
21210                        MinimapVisibility::for_mode(self.mode(), cx),
21211                        window,
21212                        cx,
21213                    );
21214                } else if let Some(minimap_entity) = self.minimap.as_ref() {
21215                    minimap_entity.update(cx, |minimap_editor, cx| {
21216                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
21217                    })
21218                }
21219            }
21220        }
21221
21222        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
21223            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
21224        }) {
21225            if !inlay_splice.to_insert.is_empty() || !inlay_splice.to_remove.is_empty() {
21226                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
21227            }
21228            self.refresh_colors_for_visible_range(None, window, cx);
21229        }
21230
21231        cx.notify();
21232    }
21233
21234    pub fn set_searchable(&mut self, searchable: bool) {
21235        self.searchable = searchable;
21236    }
21237
21238    pub fn searchable(&self) -> bool {
21239        self.searchable
21240    }
21241
21242    fn open_proposed_changes_editor(
21243        &mut self,
21244        _: &OpenProposedChangesEditor,
21245        window: &mut Window,
21246        cx: &mut Context<Self>,
21247    ) {
21248        let Some(workspace) = self.workspace() else {
21249            cx.propagate();
21250            return;
21251        };
21252
21253        let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
21254        let multi_buffer = self.buffer.read(cx);
21255        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
21256        let mut new_selections_by_buffer = HashMap::default();
21257        for selection in selections {
21258            for (buffer, range, _) in
21259                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
21260            {
21261                let mut range = range.to_point(buffer);
21262                range.start.column = 0;
21263                range.end.column = buffer.line_len(range.end.row);
21264                new_selections_by_buffer
21265                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
21266                    .or_insert(Vec::new())
21267                    .push(range)
21268            }
21269        }
21270
21271        let proposed_changes_buffers = new_selections_by_buffer
21272            .into_iter()
21273            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
21274            .collect::<Vec<_>>();
21275        let proposed_changes_editor = cx.new(|cx| {
21276            ProposedChangesEditor::new(
21277                "Proposed changes",
21278                proposed_changes_buffers,
21279                self.project.clone(),
21280                window,
21281                cx,
21282            )
21283        });
21284
21285        window.defer(cx, move |window, cx| {
21286            workspace.update(cx, |workspace, cx| {
21287                workspace.active_pane().update(cx, |pane, cx| {
21288                    pane.add_item(
21289                        Box::new(proposed_changes_editor),
21290                        true,
21291                        true,
21292                        None,
21293                        window,
21294                        cx,
21295                    );
21296                });
21297            });
21298        });
21299    }
21300
21301    pub fn open_excerpts_in_split(
21302        &mut self,
21303        _: &OpenExcerptsSplit,
21304        window: &mut Window,
21305        cx: &mut Context<Self>,
21306    ) {
21307        self.open_excerpts_common(None, true, window, cx)
21308    }
21309
21310    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
21311        self.open_excerpts_common(None, false, window, cx)
21312    }
21313
21314    fn open_excerpts_common(
21315        &mut self,
21316        jump_data: Option<JumpData>,
21317        split: bool,
21318        window: &mut Window,
21319        cx: &mut Context<Self>,
21320    ) {
21321        let Some(workspace) = self.workspace() else {
21322            cx.propagate();
21323            return;
21324        };
21325
21326        if self.buffer.read(cx).is_singleton() {
21327            cx.propagate();
21328            return;
21329        }
21330
21331        let mut new_selections_by_buffer = HashMap::default();
21332        match &jump_data {
21333            Some(JumpData::MultiBufferPoint {
21334                excerpt_id,
21335                position,
21336                anchor,
21337                line_offset_from_top,
21338            }) => {
21339                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
21340                if let Some(buffer) = multi_buffer_snapshot
21341                    .buffer_id_for_excerpt(*excerpt_id)
21342                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
21343                {
21344                    let buffer_snapshot = buffer.read(cx).snapshot();
21345                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
21346                        language::ToPoint::to_point(anchor, &buffer_snapshot)
21347                    } else {
21348                        buffer_snapshot.clip_point(*position, Bias::Left)
21349                    };
21350                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
21351                    new_selections_by_buffer.insert(
21352                        buffer,
21353                        (
21354                            vec![jump_to_offset..jump_to_offset],
21355                            Some(*line_offset_from_top),
21356                        ),
21357                    );
21358                }
21359            }
21360            Some(JumpData::MultiBufferRow {
21361                row,
21362                line_offset_from_top,
21363            }) => {
21364                let point = MultiBufferPoint::new(row.0, 0);
21365                if let Some((buffer, buffer_point, _)) =
21366                    self.buffer.read(cx).point_to_buffer_point(point, cx)
21367                {
21368                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
21369                    new_selections_by_buffer
21370                        .entry(buffer)
21371                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
21372                        .0
21373                        .push(buffer_offset..buffer_offset)
21374                }
21375            }
21376            None => {
21377                let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
21378                let multi_buffer = self.buffer.read(cx);
21379                for selection in selections {
21380                    for (snapshot, range, _, anchor) in multi_buffer
21381                        .snapshot(cx)
21382                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
21383                    {
21384                        if let Some(anchor) = anchor {
21385                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
21386                            else {
21387                                continue;
21388                            };
21389                            let offset = text::ToOffset::to_offset(
21390                                &anchor.text_anchor,
21391                                &buffer_handle.read(cx).snapshot(),
21392                            );
21393                            let range = offset..offset;
21394                            new_selections_by_buffer
21395                                .entry(buffer_handle)
21396                                .or_insert((Vec::new(), None))
21397                                .0
21398                                .push(range)
21399                        } else {
21400                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
21401                            else {
21402                                continue;
21403                            };
21404                            new_selections_by_buffer
21405                                .entry(buffer_handle)
21406                                .or_insert((Vec::new(), None))
21407                                .0
21408                                .push(range)
21409                        }
21410                    }
21411                }
21412            }
21413        }
21414
21415        new_selections_by_buffer
21416            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
21417
21418        if new_selections_by_buffer.is_empty() {
21419            return;
21420        }
21421
21422        // We defer the pane interaction because we ourselves are a workspace item
21423        // and activating a new item causes the pane to call a method on us reentrantly,
21424        // which panics if we're on the stack.
21425        window.defer(cx, move |window, cx| {
21426            workspace.update(cx, |workspace, cx| {
21427                let pane = if split {
21428                    workspace.adjacent_pane(window, cx)
21429                } else {
21430                    workspace.active_pane().clone()
21431                };
21432
21433                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
21434                    let editor = buffer
21435                        .read(cx)
21436                        .file()
21437                        .is_none()
21438                        .then(|| {
21439                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
21440                            // so `workspace.open_project_item` will never find them, always opening a new editor.
21441                            // Instead, we try to activate the existing editor in the pane first.
21442                            let (editor, pane_item_index) =
21443                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
21444                                    let editor = item.downcast::<Editor>()?;
21445                                    let singleton_buffer =
21446                                        editor.read(cx).buffer().read(cx).as_singleton()?;
21447                                    if singleton_buffer == buffer {
21448                                        Some((editor, i))
21449                                    } else {
21450                                        None
21451                                    }
21452                                })?;
21453                            pane.update(cx, |pane, cx| {
21454                                pane.activate_item(pane_item_index, true, true, window, cx)
21455                            });
21456                            Some(editor)
21457                        })
21458                        .flatten()
21459                        .unwrap_or_else(|| {
21460                            workspace.open_project_item::<Self>(
21461                                pane.clone(),
21462                                buffer,
21463                                true,
21464                                true,
21465                                window,
21466                                cx,
21467                            )
21468                        });
21469
21470                    editor.update(cx, |editor, cx| {
21471                        let autoscroll = match scroll_offset {
21472                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
21473                            None => Autoscroll::newest(),
21474                        };
21475                        let nav_history = editor.nav_history.take();
21476                        editor.change_selections(
21477                            SelectionEffects::scroll(autoscroll),
21478                            window,
21479                            cx,
21480                            |s| {
21481                                s.select_ranges(ranges);
21482                            },
21483                        );
21484                        editor.nav_history = nav_history;
21485                    });
21486                }
21487            })
21488        });
21489    }
21490
21491    // For now, don't allow opening excerpts in buffers that aren't backed by
21492    // regular project files.
21493    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
21494        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some())
21495    }
21496
21497    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
21498        let snapshot = self.buffer.read(cx).read(cx);
21499        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
21500        Some(
21501            ranges
21502                .iter()
21503                .map(move |range| {
21504                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
21505                })
21506                .collect(),
21507        )
21508    }
21509
21510    fn selection_replacement_ranges(
21511        &self,
21512        range: Range<OffsetUtf16>,
21513        cx: &mut App,
21514    ) -> Vec<Range<OffsetUtf16>> {
21515        let selections = self
21516            .selections
21517            .all::<OffsetUtf16>(&self.display_snapshot(cx));
21518        let newest_selection = selections
21519            .iter()
21520            .max_by_key(|selection| selection.id)
21521            .unwrap();
21522        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
21523        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
21524        let snapshot = self.buffer.read(cx).read(cx);
21525        selections
21526            .into_iter()
21527            .map(|mut selection| {
21528                selection.start.0 =
21529                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
21530                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
21531                snapshot.clip_offset_utf16(selection.start, Bias::Left)
21532                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
21533            })
21534            .collect()
21535    }
21536
21537    fn report_editor_event(
21538        &self,
21539        reported_event: ReportEditorEvent,
21540        file_extension: Option<String>,
21541        cx: &App,
21542    ) {
21543        if cfg!(any(test, feature = "test-support")) {
21544            return;
21545        }
21546
21547        let Some(project) = &self.project else { return };
21548
21549        // If None, we are in a file without an extension
21550        let file = self
21551            .buffer
21552            .read(cx)
21553            .as_singleton()
21554            .and_then(|b| b.read(cx).file());
21555        let file_extension = file_extension.or(file
21556            .as_ref()
21557            .and_then(|file| Path::new(file.file_name(cx)).extension())
21558            .and_then(|e| e.to_str())
21559            .map(|a| a.to_string()));
21560
21561        let vim_mode = vim_enabled(cx);
21562
21563        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
21564        let copilot_enabled = edit_predictions_provider
21565            == language::language_settings::EditPredictionProvider::Copilot;
21566        let copilot_enabled_for_language = self
21567            .buffer
21568            .read(cx)
21569            .language_settings(cx)
21570            .show_edit_predictions;
21571
21572        let project = project.read(cx);
21573        let event_type = reported_event.event_type();
21574
21575        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
21576            telemetry::event!(
21577                event_type,
21578                type = if auto_saved {"autosave"} else {"manual"},
21579                file_extension,
21580                vim_mode,
21581                copilot_enabled,
21582                copilot_enabled_for_language,
21583                edit_predictions_provider,
21584                is_via_ssh = project.is_via_remote_server(),
21585            );
21586        } else {
21587            telemetry::event!(
21588                event_type,
21589                file_extension,
21590                vim_mode,
21591                copilot_enabled,
21592                copilot_enabled_for_language,
21593                edit_predictions_provider,
21594                is_via_ssh = project.is_via_remote_server(),
21595            );
21596        };
21597    }
21598
21599    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
21600    /// with each line being an array of {text, highlight} objects.
21601    fn copy_highlight_json(
21602        &mut self,
21603        _: &CopyHighlightJson,
21604        window: &mut Window,
21605        cx: &mut Context<Self>,
21606    ) {
21607        #[derive(Serialize)]
21608        struct Chunk<'a> {
21609            text: String,
21610            highlight: Option<&'a str>,
21611        }
21612
21613        let snapshot = self.buffer.read(cx).snapshot(cx);
21614        let range = self
21615            .selected_text_range(false, window, cx)
21616            .and_then(|selection| {
21617                if selection.range.is_empty() {
21618                    None
21619                } else {
21620                    Some(selection.range)
21621                }
21622            })
21623            .unwrap_or_else(|| 0..snapshot.len());
21624
21625        let chunks = snapshot.chunks(range, true);
21626        let mut lines = Vec::new();
21627        let mut line: VecDeque<Chunk> = VecDeque::new();
21628
21629        let Some(style) = self.style.as_ref() else {
21630            return;
21631        };
21632
21633        for chunk in chunks {
21634            let highlight = chunk
21635                .syntax_highlight_id
21636                .and_then(|id| id.name(&style.syntax));
21637            let mut chunk_lines = chunk.text.split('\n').peekable();
21638            while let Some(text) = chunk_lines.next() {
21639                let mut merged_with_last_token = false;
21640                if let Some(last_token) = line.back_mut()
21641                    && last_token.highlight == highlight
21642                {
21643                    last_token.text.push_str(text);
21644                    merged_with_last_token = true;
21645                }
21646
21647                if !merged_with_last_token {
21648                    line.push_back(Chunk {
21649                        text: text.into(),
21650                        highlight,
21651                    });
21652                }
21653
21654                if chunk_lines.peek().is_some() {
21655                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
21656                        line.pop_front();
21657                    }
21658                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
21659                        line.pop_back();
21660                    }
21661
21662                    lines.push(mem::take(&mut line));
21663                }
21664            }
21665        }
21666
21667        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
21668            return;
21669        };
21670        cx.write_to_clipboard(ClipboardItem::new_string(lines));
21671    }
21672
21673    pub fn open_context_menu(
21674        &mut self,
21675        _: &OpenContextMenu,
21676        window: &mut Window,
21677        cx: &mut Context<Self>,
21678    ) {
21679        self.request_autoscroll(Autoscroll::newest(), cx);
21680        let position = self
21681            .selections
21682            .newest_display(&self.display_snapshot(cx))
21683            .start;
21684        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
21685    }
21686
21687    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
21688        &self.inlay_hint_cache
21689    }
21690
21691    pub fn replay_insert_event(
21692        &mut self,
21693        text: &str,
21694        relative_utf16_range: Option<Range<isize>>,
21695        window: &mut Window,
21696        cx: &mut Context<Self>,
21697    ) {
21698        if !self.input_enabled {
21699            cx.emit(EditorEvent::InputIgnored { text: text.into() });
21700            return;
21701        }
21702        if let Some(relative_utf16_range) = relative_utf16_range {
21703            let selections = self
21704                .selections
21705                .all::<OffsetUtf16>(&self.display_snapshot(cx));
21706            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21707                let new_ranges = selections.into_iter().map(|range| {
21708                    let start = OffsetUtf16(
21709                        range
21710                            .head()
21711                            .0
21712                            .saturating_add_signed(relative_utf16_range.start),
21713                    );
21714                    let end = OffsetUtf16(
21715                        range
21716                            .head()
21717                            .0
21718                            .saturating_add_signed(relative_utf16_range.end),
21719                    );
21720                    start..end
21721                });
21722                s.select_ranges(new_ranges);
21723            });
21724        }
21725
21726        self.handle_input(text, window, cx);
21727    }
21728
21729    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
21730        let Some(provider) = self.semantics_provider.as_ref() else {
21731            return false;
21732        };
21733
21734        let mut supports = false;
21735        self.buffer().update(cx, |this, cx| {
21736            this.for_each_buffer(|buffer| {
21737                supports |= provider.supports_inlay_hints(buffer, cx);
21738            });
21739        });
21740
21741        supports
21742    }
21743
21744    pub fn is_focused(&self, window: &Window) -> bool {
21745        self.focus_handle.is_focused(window)
21746    }
21747
21748    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21749        cx.emit(EditorEvent::Focused);
21750
21751        if let Some(descendant) = self
21752            .last_focused_descendant
21753            .take()
21754            .and_then(|descendant| descendant.upgrade())
21755        {
21756            window.focus(&descendant);
21757        } else {
21758            if let Some(blame) = self.blame.as_ref() {
21759                blame.update(cx, GitBlame::focus)
21760            }
21761
21762            self.blink_manager.update(cx, BlinkManager::enable);
21763            self.show_cursor_names(window, cx);
21764            self.buffer.update(cx, |buffer, cx| {
21765                buffer.finalize_last_transaction(cx);
21766                if self.leader_id.is_none() {
21767                    buffer.set_active_selections(
21768                        &self.selections.disjoint_anchors_arc(),
21769                        self.selections.line_mode(),
21770                        self.cursor_shape,
21771                        cx,
21772                    );
21773                }
21774            });
21775        }
21776    }
21777
21778    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
21779        cx.emit(EditorEvent::FocusedIn)
21780    }
21781
21782    fn handle_focus_out(
21783        &mut self,
21784        event: FocusOutEvent,
21785        _window: &mut Window,
21786        cx: &mut Context<Self>,
21787    ) {
21788        if event.blurred != self.focus_handle {
21789            self.last_focused_descendant = Some(event.blurred);
21790        }
21791        self.selection_drag_state = SelectionDragState::None;
21792        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
21793    }
21794
21795    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21796        self.blink_manager.update(cx, BlinkManager::disable);
21797        self.buffer
21798            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
21799
21800        if let Some(blame) = self.blame.as_ref() {
21801            blame.update(cx, GitBlame::blur)
21802        }
21803        if !self.hover_state.focused(window, cx) {
21804            hide_hover(self, cx);
21805        }
21806        if !self
21807            .context_menu
21808            .borrow()
21809            .as_ref()
21810            .is_some_and(|context_menu| context_menu.focused(window, cx))
21811        {
21812            self.hide_context_menu(window, cx);
21813        }
21814        self.take_active_edit_prediction(cx);
21815        cx.emit(EditorEvent::Blurred);
21816        cx.notify();
21817    }
21818
21819    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21820        let mut pending: String = window
21821            .pending_input_keystrokes()
21822            .into_iter()
21823            .flatten()
21824            .filter_map(|keystroke| {
21825                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
21826                    keystroke.key_char.clone()
21827                } else {
21828                    None
21829                }
21830            })
21831            .collect();
21832
21833        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
21834            pending = "".to_string();
21835        }
21836
21837        let existing_pending = self
21838            .text_highlights::<PendingInput>(cx)
21839            .map(|(_, ranges)| ranges.to_vec());
21840        if existing_pending.is_none() && pending.is_empty() {
21841            return;
21842        }
21843        let transaction =
21844            self.transact(window, cx, |this, window, cx| {
21845                let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
21846                let edits = selections
21847                    .iter()
21848                    .map(|selection| (selection.end..selection.end, pending.clone()));
21849                this.edit(edits, cx);
21850                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21851                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
21852                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
21853                    }));
21854                });
21855                if let Some(existing_ranges) = existing_pending {
21856                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
21857                    this.edit(edits, cx);
21858                }
21859            });
21860
21861        let snapshot = self.snapshot(window, cx);
21862        let ranges = self
21863            .selections
21864            .all::<usize>(&snapshot.display_snapshot)
21865            .into_iter()
21866            .map(|selection| {
21867                snapshot.buffer_snapshot().anchor_after(selection.end)
21868                    ..snapshot
21869                        .buffer_snapshot()
21870                        .anchor_before(selection.end + pending.len())
21871            })
21872            .collect();
21873
21874        if pending.is_empty() {
21875            self.clear_highlights::<PendingInput>(cx);
21876        } else {
21877            self.highlight_text::<PendingInput>(
21878                ranges,
21879                HighlightStyle {
21880                    underline: Some(UnderlineStyle {
21881                        thickness: px(1.),
21882                        color: None,
21883                        wavy: false,
21884                    }),
21885                    ..Default::default()
21886                },
21887                cx,
21888            );
21889        }
21890
21891        self.ime_transaction = self.ime_transaction.or(transaction);
21892        if let Some(transaction) = self.ime_transaction {
21893            self.buffer.update(cx, |buffer, cx| {
21894                buffer.group_until_transaction(transaction, cx);
21895            });
21896        }
21897
21898        if self.text_highlights::<PendingInput>(cx).is_none() {
21899            self.ime_transaction.take();
21900        }
21901    }
21902
21903    pub fn register_action_renderer(
21904        &mut self,
21905        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
21906    ) -> Subscription {
21907        let id = self.next_editor_action_id.post_inc();
21908        self.editor_actions
21909            .borrow_mut()
21910            .insert(id, Box::new(listener));
21911
21912        let editor_actions = self.editor_actions.clone();
21913        Subscription::new(move || {
21914            editor_actions.borrow_mut().remove(&id);
21915        })
21916    }
21917
21918    pub fn register_action<A: Action>(
21919        &mut self,
21920        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
21921    ) -> Subscription {
21922        let id = self.next_editor_action_id.post_inc();
21923        let listener = Arc::new(listener);
21924        self.editor_actions.borrow_mut().insert(
21925            id,
21926            Box::new(move |_, window, _| {
21927                let listener = listener.clone();
21928                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
21929                    let action = action.downcast_ref().unwrap();
21930                    if phase == DispatchPhase::Bubble {
21931                        listener(action, window, cx)
21932                    }
21933                })
21934            }),
21935        );
21936
21937        let editor_actions = self.editor_actions.clone();
21938        Subscription::new(move || {
21939            editor_actions.borrow_mut().remove(&id);
21940        })
21941    }
21942
21943    pub fn file_header_size(&self) -> u32 {
21944        FILE_HEADER_HEIGHT
21945    }
21946
21947    pub fn restore(
21948        &mut self,
21949        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
21950        window: &mut Window,
21951        cx: &mut Context<Self>,
21952    ) {
21953        let workspace = self.workspace();
21954        let project = self.project();
21955        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
21956            let mut tasks = Vec::new();
21957            for (buffer_id, changes) in revert_changes {
21958                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
21959                    buffer.update(cx, |buffer, cx| {
21960                        buffer.edit(
21961                            changes
21962                                .into_iter()
21963                                .map(|(range, text)| (range, text.to_string())),
21964                            None,
21965                            cx,
21966                        );
21967                    });
21968
21969                    if let Some(project) =
21970                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
21971                    {
21972                        project.update(cx, |project, cx| {
21973                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
21974                        })
21975                    }
21976                }
21977            }
21978            tasks
21979        });
21980        cx.spawn_in(window, async move |_, cx| {
21981            for (buffer, task) in save_tasks {
21982                let result = task.await;
21983                if result.is_err() {
21984                    let Some(path) = buffer
21985                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
21986                        .ok()
21987                    else {
21988                        continue;
21989                    };
21990                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
21991                        let Some(task) = cx
21992                            .update_window_entity(workspace, |workspace, window, cx| {
21993                                workspace
21994                                    .open_path_preview(path, None, false, false, false, window, cx)
21995                            })
21996                            .ok()
21997                        else {
21998                            continue;
21999                        };
22000                        task.await.log_err();
22001                    }
22002                }
22003            }
22004        })
22005        .detach();
22006        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
22007            selections.refresh()
22008        });
22009    }
22010
22011    pub fn to_pixel_point(
22012        &self,
22013        source: multi_buffer::Anchor,
22014        editor_snapshot: &EditorSnapshot,
22015        window: &mut Window,
22016    ) -> Option<gpui::Point<Pixels>> {
22017        let source_point = source.to_display_point(editor_snapshot);
22018        self.display_to_pixel_point(source_point, editor_snapshot, window)
22019    }
22020
22021    pub fn display_to_pixel_point(
22022        &self,
22023        source: DisplayPoint,
22024        editor_snapshot: &EditorSnapshot,
22025        window: &mut Window,
22026    ) -> Option<gpui::Point<Pixels>> {
22027        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
22028        let text_layout_details = self.text_layout_details(window);
22029        let scroll_top = text_layout_details
22030            .scroll_anchor
22031            .scroll_position(editor_snapshot)
22032            .y;
22033
22034        if source.row().as_f64() < scroll_top.floor() {
22035            return None;
22036        }
22037        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
22038        let source_y = line_height * (source.row().as_f64() - scroll_top) as f32;
22039        Some(gpui::Point::new(source_x, source_y))
22040    }
22041
22042    pub fn has_visible_completions_menu(&self) -> bool {
22043        !self.edit_prediction_preview_is_active()
22044            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
22045                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
22046            })
22047    }
22048
22049    pub fn register_addon<T: Addon>(&mut self, instance: T) {
22050        if self.mode.is_minimap() {
22051            return;
22052        }
22053        self.addons
22054            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
22055    }
22056
22057    pub fn unregister_addon<T: Addon>(&mut self) {
22058        self.addons.remove(&std::any::TypeId::of::<T>());
22059    }
22060
22061    pub fn addon<T: Addon>(&self) -> Option<&T> {
22062        let type_id = std::any::TypeId::of::<T>();
22063        self.addons
22064            .get(&type_id)
22065            .and_then(|item| item.to_any().downcast_ref::<T>())
22066    }
22067
22068    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
22069        let type_id = std::any::TypeId::of::<T>();
22070        self.addons
22071            .get_mut(&type_id)
22072            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
22073    }
22074
22075    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
22076        let text_layout_details = self.text_layout_details(window);
22077        let style = &text_layout_details.editor_style;
22078        let font_id = window.text_system().resolve_font(&style.text.font());
22079        let font_size = style.text.font_size.to_pixels(window.rem_size());
22080        let line_height = style.text.line_height_in_pixels(window.rem_size());
22081        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
22082        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
22083
22084        CharacterDimensions {
22085            em_width,
22086            em_advance,
22087            line_height,
22088        }
22089    }
22090
22091    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
22092        self.load_diff_task.clone()
22093    }
22094
22095    fn read_metadata_from_db(
22096        &mut self,
22097        item_id: u64,
22098        workspace_id: WorkspaceId,
22099        window: &mut Window,
22100        cx: &mut Context<Editor>,
22101    ) {
22102        if self.buffer_kind(cx) == ItemBufferKind::Singleton
22103            && !self.mode.is_minimap()
22104            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
22105        {
22106            let buffer_snapshot = OnceCell::new();
22107
22108            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
22109                && !folds.is_empty()
22110            {
22111                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
22112                self.fold_ranges(
22113                    folds
22114                        .into_iter()
22115                        .map(|(start, end)| {
22116                            snapshot.clip_offset(start, Bias::Left)
22117                                ..snapshot.clip_offset(end, Bias::Right)
22118                        })
22119                        .collect(),
22120                    false,
22121                    window,
22122                    cx,
22123                );
22124            }
22125
22126            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
22127                && !selections.is_empty()
22128            {
22129                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
22130                // skip adding the initial selection to selection history
22131                self.selection_history.mode = SelectionHistoryMode::Skipping;
22132                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22133                    s.select_ranges(selections.into_iter().map(|(start, end)| {
22134                        snapshot.clip_offset(start, Bias::Left)
22135                            ..snapshot.clip_offset(end, Bias::Right)
22136                    }));
22137                });
22138                self.selection_history.mode = SelectionHistoryMode::Normal;
22139            };
22140        }
22141
22142        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
22143    }
22144
22145    fn update_lsp_data(
22146        &mut self,
22147        for_buffer: Option<BufferId>,
22148        window: &mut Window,
22149        cx: &mut Context<'_, Self>,
22150    ) {
22151        self.pull_diagnostics(for_buffer, window, cx);
22152        self.refresh_colors_for_visible_range(for_buffer, window, cx);
22153    }
22154
22155    fn register_visible_buffers(&mut self, cx: &mut Context<Self>) {
22156        if self.ignore_lsp_data() {
22157            return;
22158        }
22159        for (_, (visible_buffer, _, _)) in self.visible_excerpts(None, cx) {
22160            self.register_buffer(visible_buffer.read(cx).remote_id(), cx);
22161        }
22162    }
22163
22164    fn register_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) -> bool {
22165        if !self.registered_buffers.contains_key(&buffer_id)
22166            && let Some(project) = self.project.as_ref()
22167        {
22168            if let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) {
22169                project.update(cx, |project, cx| {
22170                    self.registered_buffers.insert(
22171                        buffer_id,
22172                        project.register_buffer_with_language_servers(&buffer, cx),
22173                    );
22174                });
22175                return true;
22176            } else {
22177                self.registered_buffers.remove(&buffer_id);
22178            }
22179        }
22180
22181        false
22182    }
22183
22184    fn ignore_lsp_data(&self) -> bool {
22185        // `ActiveDiagnostic::All` is a special mode where editor's diagnostics are managed by the external view,
22186        // skip any LSP updates for it.
22187        self.active_diagnostics == ActiveDiagnostic::All || !self.mode().is_full()
22188    }
22189}
22190
22191fn edit_for_markdown_paste<'a>(
22192    buffer: &MultiBufferSnapshot,
22193    range: Range<usize>,
22194    to_insert: &'a str,
22195    url: Option<url::Url>,
22196) -> (Range<usize>, Cow<'a, str>) {
22197    if url.is_none() {
22198        return (range, Cow::Borrowed(to_insert));
22199    };
22200
22201    let old_text = buffer.text_for_range(range.clone()).collect::<String>();
22202
22203    let new_text = if range.is_empty() || url::Url::parse(&old_text).is_ok() {
22204        Cow::Borrowed(to_insert)
22205    } else {
22206        Cow::Owned(format!("[{old_text}]({to_insert})"))
22207    };
22208    (range, new_text)
22209}
22210
22211fn vim_enabled(cx: &App) -> bool {
22212    vim_mode_setting::VimModeSetting::try_get(cx)
22213        .map(|vim_mode| vim_mode.0)
22214        .unwrap_or(false)
22215}
22216
22217fn process_completion_for_edit(
22218    completion: &Completion,
22219    intent: CompletionIntent,
22220    buffer: &Entity<Buffer>,
22221    cursor_position: &text::Anchor,
22222    cx: &mut Context<Editor>,
22223) -> CompletionEdit {
22224    let buffer = buffer.read(cx);
22225    let buffer_snapshot = buffer.snapshot();
22226    let (snippet, new_text) = if completion.is_snippet() {
22227        let mut snippet_source = completion.new_text.clone();
22228        // Workaround for typescript language server issues so that methods don't expand within
22229        // strings and functions with type expressions. The previous point is used because the query
22230        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
22231        let previous_point = text::ToPoint::to_point(cursor_position, &buffer_snapshot);
22232        let previous_point = if previous_point.column > 0 {
22233            cursor_position.to_previous_offset(&buffer_snapshot)
22234        } else {
22235            cursor_position.to_offset(&buffer_snapshot)
22236        };
22237        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
22238            && scope.prefers_label_for_snippet_in_completion()
22239            && let Some(label) = completion.label()
22240            && matches!(
22241                completion.kind(),
22242                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
22243            )
22244        {
22245            snippet_source = label;
22246        }
22247        match Snippet::parse(&snippet_source).log_err() {
22248            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
22249            None => (None, completion.new_text.clone()),
22250        }
22251    } else {
22252        (None, completion.new_text.clone())
22253    };
22254
22255    let mut range_to_replace = {
22256        let replace_range = &completion.replace_range;
22257        if let CompletionSource::Lsp {
22258            insert_range: Some(insert_range),
22259            ..
22260        } = &completion.source
22261        {
22262            debug_assert_eq!(
22263                insert_range.start, replace_range.start,
22264                "insert_range and replace_range should start at the same position"
22265            );
22266            debug_assert!(
22267                insert_range
22268                    .start
22269                    .cmp(cursor_position, &buffer_snapshot)
22270                    .is_le(),
22271                "insert_range should start before or at cursor position"
22272            );
22273            debug_assert!(
22274                replace_range
22275                    .start
22276                    .cmp(cursor_position, &buffer_snapshot)
22277                    .is_le(),
22278                "replace_range should start before or at cursor position"
22279            );
22280
22281            let should_replace = match intent {
22282                CompletionIntent::CompleteWithInsert => false,
22283                CompletionIntent::CompleteWithReplace => true,
22284                CompletionIntent::Complete | CompletionIntent::Compose => {
22285                    let insert_mode =
22286                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
22287                            .completions
22288                            .lsp_insert_mode;
22289                    match insert_mode {
22290                        LspInsertMode::Insert => false,
22291                        LspInsertMode::Replace => true,
22292                        LspInsertMode::ReplaceSubsequence => {
22293                            let mut text_to_replace = buffer.chars_for_range(
22294                                buffer.anchor_before(replace_range.start)
22295                                    ..buffer.anchor_after(replace_range.end),
22296                            );
22297                            let mut current_needle = text_to_replace.next();
22298                            for haystack_ch in completion.label.text.chars() {
22299                                if let Some(needle_ch) = current_needle
22300                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
22301                                {
22302                                    current_needle = text_to_replace.next();
22303                                }
22304                            }
22305                            current_needle.is_none()
22306                        }
22307                        LspInsertMode::ReplaceSuffix => {
22308                            if replace_range
22309                                .end
22310                                .cmp(cursor_position, &buffer_snapshot)
22311                                .is_gt()
22312                            {
22313                                let range_after_cursor = *cursor_position..replace_range.end;
22314                                let text_after_cursor = buffer
22315                                    .text_for_range(
22316                                        buffer.anchor_before(range_after_cursor.start)
22317                                            ..buffer.anchor_after(range_after_cursor.end),
22318                                    )
22319                                    .collect::<String>()
22320                                    .to_ascii_lowercase();
22321                                completion
22322                                    .label
22323                                    .text
22324                                    .to_ascii_lowercase()
22325                                    .ends_with(&text_after_cursor)
22326                            } else {
22327                                true
22328                            }
22329                        }
22330                    }
22331                }
22332            };
22333
22334            if should_replace {
22335                replace_range.clone()
22336            } else {
22337                insert_range.clone()
22338            }
22339        } else {
22340            replace_range.clone()
22341        }
22342    };
22343
22344    if range_to_replace
22345        .end
22346        .cmp(cursor_position, &buffer_snapshot)
22347        .is_lt()
22348    {
22349        range_to_replace.end = *cursor_position;
22350    }
22351
22352    CompletionEdit {
22353        new_text,
22354        replace_range: range_to_replace.to_offset(buffer),
22355        snippet,
22356    }
22357}
22358
22359struct CompletionEdit {
22360    new_text: String,
22361    replace_range: Range<usize>,
22362    snippet: Option<Snippet>,
22363}
22364
22365fn insert_extra_newline_brackets(
22366    buffer: &MultiBufferSnapshot,
22367    range: Range<usize>,
22368    language: &language::LanguageScope,
22369) -> bool {
22370    let leading_whitespace_len = buffer
22371        .reversed_chars_at(range.start)
22372        .take_while(|c| c.is_whitespace() && *c != '\n')
22373        .map(|c| c.len_utf8())
22374        .sum::<usize>();
22375    let trailing_whitespace_len = buffer
22376        .chars_at(range.end)
22377        .take_while(|c| c.is_whitespace() && *c != '\n')
22378        .map(|c| c.len_utf8())
22379        .sum::<usize>();
22380    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
22381
22382    language.brackets().any(|(pair, enabled)| {
22383        let pair_start = pair.start.trim_end();
22384        let pair_end = pair.end.trim_start();
22385
22386        enabled
22387            && pair.newline
22388            && buffer.contains_str_at(range.end, pair_end)
22389            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
22390    })
22391}
22392
22393fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
22394    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
22395        [(buffer, range, _)] => (*buffer, range.clone()),
22396        _ => return false,
22397    };
22398    let pair = {
22399        let mut result: Option<BracketMatch> = None;
22400
22401        for pair in buffer
22402            .all_bracket_ranges(range.clone())
22403            .filter(move |pair| {
22404                pair.open_range.start <= range.start && pair.close_range.end >= range.end
22405            })
22406        {
22407            let len = pair.close_range.end - pair.open_range.start;
22408
22409            if let Some(existing) = &result {
22410                let existing_len = existing.close_range.end - existing.open_range.start;
22411                if len > existing_len {
22412                    continue;
22413                }
22414            }
22415
22416            result = Some(pair);
22417        }
22418
22419        result
22420    };
22421    let Some(pair) = pair else {
22422        return false;
22423    };
22424    pair.newline_only
22425        && buffer
22426            .chars_for_range(pair.open_range.end..range.start)
22427            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
22428            .all(|c| c.is_whitespace() && c != '\n')
22429}
22430
22431fn update_uncommitted_diff_for_buffer(
22432    editor: Entity<Editor>,
22433    project: &Entity<Project>,
22434    buffers: impl IntoIterator<Item = Entity<Buffer>>,
22435    buffer: Entity<MultiBuffer>,
22436    cx: &mut App,
22437) -> Task<()> {
22438    let mut tasks = Vec::new();
22439    project.update(cx, |project, cx| {
22440        for buffer in buffers {
22441            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
22442                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
22443            }
22444        }
22445    });
22446    cx.spawn(async move |cx| {
22447        let diffs = future::join_all(tasks).await;
22448        if editor
22449            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
22450            .unwrap_or(false)
22451        {
22452            return;
22453        }
22454
22455        buffer
22456            .update(cx, |buffer, cx| {
22457                for diff in diffs.into_iter().flatten() {
22458                    buffer.add_diff(diff, cx);
22459                }
22460            })
22461            .ok();
22462    })
22463}
22464
22465fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
22466    let tab_size = tab_size.get() as usize;
22467    let mut width = offset;
22468
22469    for ch in text.chars() {
22470        width += if ch == '\t' {
22471            tab_size - (width % tab_size)
22472        } else {
22473            1
22474        };
22475    }
22476
22477    width - offset
22478}
22479
22480#[cfg(test)]
22481mod tests {
22482    use super::*;
22483
22484    #[test]
22485    fn test_string_size_with_expanded_tabs() {
22486        let nz = |val| NonZeroU32::new(val).unwrap();
22487        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
22488        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
22489        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
22490        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
22491        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
22492        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
22493        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
22494        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
22495    }
22496}
22497
22498/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
22499struct WordBreakingTokenizer<'a> {
22500    input: &'a str,
22501}
22502
22503impl<'a> WordBreakingTokenizer<'a> {
22504    fn new(input: &'a str) -> Self {
22505        Self { input }
22506    }
22507}
22508
22509fn is_char_ideographic(ch: char) -> bool {
22510    use unicode_script::Script::*;
22511    use unicode_script::UnicodeScript;
22512    matches!(ch.script(), Han | Tangut | Yi)
22513}
22514
22515fn is_grapheme_ideographic(text: &str) -> bool {
22516    text.chars().any(is_char_ideographic)
22517}
22518
22519fn is_grapheme_whitespace(text: &str) -> bool {
22520    text.chars().any(|x| x.is_whitespace())
22521}
22522
22523fn should_stay_with_preceding_ideograph(text: &str) -> bool {
22524    text.chars()
22525        .next()
22526        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
22527}
22528
22529#[derive(PartialEq, Eq, Debug, Clone, Copy)]
22530enum WordBreakToken<'a> {
22531    Word { token: &'a str, grapheme_len: usize },
22532    InlineWhitespace { token: &'a str, grapheme_len: usize },
22533    Newline,
22534}
22535
22536impl<'a> Iterator for WordBreakingTokenizer<'a> {
22537    /// Yields a span, the count of graphemes in the token, and whether it was
22538    /// whitespace. Note that it also breaks at word boundaries.
22539    type Item = WordBreakToken<'a>;
22540
22541    fn next(&mut self) -> Option<Self::Item> {
22542        use unicode_segmentation::UnicodeSegmentation;
22543        if self.input.is_empty() {
22544            return None;
22545        }
22546
22547        let mut iter = self.input.graphemes(true).peekable();
22548        let mut offset = 0;
22549        let mut grapheme_len = 0;
22550        if let Some(first_grapheme) = iter.next() {
22551            let is_newline = first_grapheme == "\n";
22552            let is_whitespace = is_grapheme_whitespace(first_grapheme);
22553            offset += first_grapheme.len();
22554            grapheme_len += 1;
22555            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
22556                if let Some(grapheme) = iter.peek().copied()
22557                    && should_stay_with_preceding_ideograph(grapheme)
22558                {
22559                    offset += grapheme.len();
22560                    grapheme_len += 1;
22561                }
22562            } else {
22563                let mut words = self.input[offset..].split_word_bound_indices().peekable();
22564                let mut next_word_bound = words.peek().copied();
22565                if next_word_bound.is_some_and(|(i, _)| i == 0) {
22566                    next_word_bound = words.next();
22567                }
22568                while let Some(grapheme) = iter.peek().copied() {
22569                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
22570                        break;
22571                    };
22572                    if is_grapheme_whitespace(grapheme) != is_whitespace
22573                        || (grapheme == "\n") != is_newline
22574                    {
22575                        break;
22576                    };
22577                    offset += grapheme.len();
22578                    grapheme_len += 1;
22579                    iter.next();
22580                }
22581            }
22582            let token = &self.input[..offset];
22583            self.input = &self.input[offset..];
22584            if token == "\n" {
22585                Some(WordBreakToken::Newline)
22586            } else if is_whitespace {
22587                Some(WordBreakToken::InlineWhitespace {
22588                    token,
22589                    grapheme_len,
22590                })
22591            } else {
22592                Some(WordBreakToken::Word {
22593                    token,
22594                    grapheme_len,
22595                })
22596            }
22597        } else {
22598            None
22599        }
22600    }
22601}
22602
22603#[test]
22604fn test_word_breaking_tokenizer() {
22605    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
22606        ("", &[]),
22607        ("  ", &[whitespace("  ", 2)]),
22608        ("Ʒ", &[word("Ʒ", 1)]),
22609        ("Ǽ", &[word("Ǽ", 1)]),
22610        ("", &[word("", 1)]),
22611        ("⋑⋑", &[word("⋑⋑", 2)]),
22612        (
22613            "原理,进而",
22614            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
22615        ),
22616        (
22617            "hello world",
22618            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
22619        ),
22620        (
22621            "hello, world",
22622            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
22623        ),
22624        (
22625            "  hello world",
22626            &[
22627                whitespace("  ", 2),
22628                word("hello", 5),
22629                whitespace(" ", 1),
22630                word("world", 5),
22631            ],
22632        ),
22633        (
22634            "这是什么 \n 钢笔",
22635            &[
22636                word("", 1),
22637                word("", 1),
22638                word("", 1),
22639                word("", 1),
22640                whitespace(" ", 1),
22641                newline(),
22642                whitespace(" ", 1),
22643                word("", 1),
22644                word("", 1),
22645            ],
22646        ),
22647        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
22648    ];
22649
22650    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22651        WordBreakToken::Word {
22652            token,
22653            grapheme_len,
22654        }
22655    }
22656
22657    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22658        WordBreakToken::InlineWhitespace {
22659            token,
22660            grapheme_len,
22661        }
22662    }
22663
22664    fn newline() -> WordBreakToken<'static> {
22665        WordBreakToken::Newline
22666    }
22667
22668    for (input, result) in tests {
22669        assert_eq!(
22670            WordBreakingTokenizer::new(input)
22671                .collect::<Vec<_>>()
22672                .as_slice(),
22673            *result,
22674        );
22675    }
22676}
22677
22678fn wrap_with_prefix(
22679    first_line_prefix: String,
22680    subsequent_lines_prefix: String,
22681    unwrapped_text: String,
22682    wrap_column: usize,
22683    tab_size: NonZeroU32,
22684    preserve_existing_whitespace: bool,
22685) -> String {
22686    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
22687    let subsequent_lines_prefix_len =
22688        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
22689    let mut wrapped_text = String::new();
22690    let mut current_line = first_line_prefix;
22691    let mut is_first_line = true;
22692
22693    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
22694    let mut current_line_len = first_line_prefix_len;
22695    let mut in_whitespace = false;
22696    for token in tokenizer {
22697        let have_preceding_whitespace = in_whitespace;
22698        match token {
22699            WordBreakToken::Word {
22700                token,
22701                grapheme_len,
22702            } => {
22703                in_whitespace = false;
22704                let current_prefix_len = if is_first_line {
22705                    first_line_prefix_len
22706                } else {
22707                    subsequent_lines_prefix_len
22708                };
22709                if current_line_len + grapheme_len > wrap_column
22710                    && current_line_len != current_prefix_len
22711                {
22712                    wrapped_text.push_str(current_line.trim_end());
22713                    wrapped_text.push('\n');
22714                    is_first_line = false;
22715                    current_line = subsequent_lines_prefix.clone();
22716                    current_line_len = subsequent_lines_prefix_len;
22717                }
22718                current_line.push_str(token);
22719                current_line_len += grapheme_len;
22720            }
22721            WordBreakToken::InlineWhitespace {
22722                mut token,
22723                mut grapheme_len,
22724            } => {
22725                in_whitespace = true;
22726                if have_preceding_whitespace && !preserve_existing_whitespace {
22727                    continue;
22728                }
22729                if !preserve_existing_whitespace {
22730                    // Keep a single whitespace grapheme as-is
22731                    if let Some(first) =
22732                        unicode_segmentation::UnicodeSegmentation::graphemes(token, true).next()
22733                    {
22734                        token = first;
22735                    } else {
22736                        token = " ";
22737                    }
22738                    grapheme_len = 1;
22739                }
22740                let current_prefix_len = if is_first_line {
22741                    first_line_prefix_len
22742                } else {
22743                    subsequent_lines_prefix_len
22744                };
22745                if current_line_len + grapheme_len > wrap_column {
22746                    wrapped_text.push_str(current_line.trim_end());
22747                    wrapped_text.push('\n');
22748                    is_first_line = false;
22749                    current_line = subsequent_lines_prefix.clone();
22750                    current_line_len = subsequent_lines_prefix_len;
22751                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
22752                    current_line.push_str(token);
22753                    current_line_len += grapheme_len;
22754                }
22755            }
22756            WordBreakToken::Newline => {
22757                in_whitespace = true;
22758                let current_prefix_len = if is_first_line {
22759                    first_line_prefix_len
22760                } else {
22761                    subsequent_lines_prefix_len
22762                };
22763                if preserve_existing_whitespace {
22764                    wrapped_text.push_str(current_line.trim_end());
22765                    wrapped_text.push('\n');
22766                    is_first_line = false;
22767                    current_line = subsequent_lines_prefix.clone();
22768                    current_line_len = subsequent_lines_prefix_len;
22769                } else if have_preceding_whitespace {
22770                    continue;
22771                } else if current_line_len + 1 > wrap_column
22772                    && current_line_len != current_prefix_len
22773                {
22774                    wrapped_text.push_str(current_line.trim_end());
22775                    wrapped_text.push('\n');
22776                    is_first_line = false;
22777                    current_line = subsequent_lines_prefix.clone();
22778                    current_line_len = subsequent_lines_prefix_len;
22779                } else if current_line_len != current_prefix_len {
22780                    current_line.push(' ');
22781                    current_line_len += 1;
22782                }
22783            }
22784        }
22785    }
22786
22787    if !current_line.is_empty() {
22788        wrapped_text.push_str(&current_line);
22789    }
22790    wrapped_text
22791}
22792
22793#[test]
22794fn test_wrap_with_prefix() {
22795    assert_eq!(
22796        wrap_with_prefix(
22797            "# ".to_string(),
22798            "# ".to_string(),
22799            "abcdefg".to_string(),
22800            4,
22801            NonZeroU32::new(4).unwrap(),
22802            false,
22803        ),
22804        "# abcdefg"
22805    );
22806    assert_eq!(
22807        wrap_with_prefix(
22808            "".to_string(),
22809            "".to_string(),
22810            "\thello world".to_string(),
22811            8,
22812            NonZeroU32::new(4).unwrap(),
22813            false,
22814        ),
22815        "hello\nworld"
22816    );
22817    assert_eq!(
22818        wrap_with_prefix(
22819            "// ".to_string(),
22820            "// ".to_string(),
22821            "xx \nyy zz aa bb cc".to_string(),
22822            12,
22823            NonZeroU32::new(4).unwrap(),
22824            false,
22825        ),
22826        "// xx yy zz\n// aa bb cc"
22827    );
22828    assert_eq!(
22829        wrap_with_prefix(
22830            String::new(),
22831            String::new(),
22832            "这是什么 \n 钢笔".to_string(),
22833            3,
22834            NonZeroU32::new(4).unwrap(),
22835            false,
22836        ),
22837        "这是什\n么 钢\n"
22838    );
22839    assert_eq!(
22840        wrap_with_prefix(
22841            String::new(),
22842            String::new(),
22843            format!("foo{}bar", '\u{2009}'), // thin space
22844            80,
22845            NonZeroU32::new(4).unwrap(),
22846            false,
22847        ),
22848        format!("foo{}bar", '\u{2009}')
22849    );
22850}
22851
22852pub trait CollaborationHub {
22853    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
22854    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
22855    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
22856}
22857
22858impl CollaborationHub for Entity<Project> {
22859    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
22860        self.read(cx).collaborators()
22861    }
22862
22863    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
22864        self.read(cx).user_store().read(cx).participant_indices()
22865    }
22866
22867    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
22868        let this = self.read(cx);
22869        let user_ids = this.collaborators().values().map(|c| c.user_id);
22870        this.user_store().read(cx).participant_names(user_ids, cx)
22871    }
22872}
22873
22874pub trait SemanticsProvider {
22875    fn hover(
22876        &self,
22877        buffer: &Entity<Buffer>,
22878        position: text::Anchor,
22879        cx: &mut App,
22880    ) -> Option<Task<Option<Vec<project::Hover>>>>;
22881
22882    fn inline_values(
22883        &self,
22884        buffer_handle: Entity<Buffer>,
22885        range: Range<text::Anchor>,
22886        cx: &mut App,
22887    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22888
22889    fn inlay_hints(
22890        &self,
22891        buffer_handle: Entity<Buffer>,
22892        range: Range<text::Anchor>,
22893        cx: &mut App,
22894    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22895
22896    fn resolve_inlay_hint(
22897        &self,
22898        hint: InlayHint,
22899        buffer_handle: Entity<Buffer>,
22900        server_id: LanguageServerId,
22901        cx: &mut App,
22902    ) -> Option<Task<anyhow::Result<InlayHint>>>;
22903
22904    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
22905
22906    fn document_highlights(
22907        &self,
22908        buffer: &Entity<Buffer>,
22909        position: text::Anchor,
22910        cx: &mut App,
22911    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
22912
22913    fn definitions(
22914        &self,
22915        buffer: &Entity<Buffer>,
22916        position: text::Anchor,
22917        kind: GotoDefinitionKind,
22918        cx: &mut App,
22919    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
22920
22921    fn range_for_rename(
22922        &self,
22923        buffer: &Entity<Buffer>,
22924        position: text::Anchor,
22925        cx: &mut App,
22926    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
22927
22928    fn perform_rename(
22929        &self,
22930        buffer: &Entity<Buffer>,
22931        position: text::Anchor,
22932        new_name: String,
22933        cx: &mut App,
22934    ) -> Option<Task<Result<ProjectTransaction>>>;
22935}
22936
22937pub trait CompletionProvider {
22938    fn completions(
22939        &self,
22940        excerpt_id: ExcerptId,
22941        buffer: &Entity<Buffer>,
22942        buffer_position: text::Anchor,
22943        trigger: CompletionContext,
22944        window: &mut Window,
22945        cx: &mut Context<Editor>,
22946    ) -> Task<Result<Vec<CompletionResponse>>>;
22947
22948    fn resolve_completions(
22949        &self,
22950        _buffer: Entity<Buffer>,
22951        _completion_indices: Vec<usize>,
22952        _completions: Rc<RefCell<Box<[Completion]>>>,
22953        _cx: &mut Context<Editor>,
22954    ) -> Task<Result<bool>> {
22955        Task::ready(Ok(false))
22956    }
22957
22958    fn apply_additional_edits_for_completion(
22959        &self,
22960        _buffer: Entity<Buffer>,
22961        _completions: Rc<RefCell<Box<[Completion]>>>,
22962        _completion_index: usize,
22963        _push_to_history: bool,
22964        _cx: &mut Context<Editor>,
22965    ) -> Task<Result<Option<language::Transaction>>> {
22966        Task::ready(Ok(None))
22967    }
22968
22969    fn is_completion_trigger(
22970        &self,
22971        buffer: &Entity<Buffer>,
22972        position: language::Anchor,
22973        text: &str,
22974        trigger_in_words: bool,
22975        menu_is_open: bool,
22976        cx: &mut Context<Editor>,
22977    ) -> bool;
22978
22979    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
22980
22981    fn sort_completions(&self) -> bool {
22982        true
22983    }
22984
22985    fn filter_completions(&self) -> bool {
22986        true
22987    }
22988}
22989
22990pub trait CodeActionProvider {
22991    fn id(&self) -> Arc<str>;
22992
22993    fn code_actions(
22994        &self,
22995        buffer: &Entity<Buffer>,
22996        range: Range<text::Anchor>,
22997        window: &mut Window,
22998        cx: &mut App,
22999    ) -> Task<Result<Vec<CodeAction>>>;
23000
23001    fn apply_code_action(
23002        &self,
23003        buffer_handle: Entity<Buffer>,
23004        action: CodeAction,
23005        excerpt_id: ExcerptId,
23006        push_to_history: bool,
23007        window: &mut Window,
23008        cx: &mut App,
23009    ) -> Task<Result<ProjectTransaction>>;
23010}
23011
23012impl CodeActionProvider for Entity<Project> {
23013    fn id(&self) -> Arc<str> {
23014        "project".into()
23015    }
23016
23017    fn code_actions(
23018        &self,
23019        buffer: &Entity<Buffer>,
23020        range: Range<text::Anchor>,
23021        _window: &mut Window,
23022        cx: &mut App,
23023    ) -> Task<Result<Vec<CodeAction>>> {
23024        self.update(cx, |project, cx| {
23025            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
23026            let code_actions = project.code_actions(buffer, range, None, cx);
23027            cx.background_spawn(async move {
23028                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
23029                Ok(code_lens_actions
23030                    .context("code lens fetch")?
23031                    .into_iter()
23032                    .flatten()
23033                    .chain(
23034                        code_actions
23035                            .context("code action fetch")?
23036                            .into_iter()
23037                            .flatten(),
23038                    )
23039                    .collect())
23040            })
23041        })
23042    }
23043
23044    fn apply_code_action(
23045        &self,
23046        buffer_handle: Entity<Buffer>,
23047        action: CodeAction,
23048        _excerpt_id: ExcerptId,
23049        push_to_history: bool,
23050        _window: &mut Window,
23051        cx: &mut App,
23052    ) -> Task<Result<ProjectTransaction>> {
23053        self.update(cx, |project, cx| {
23054            project.apply_code_action(buffer_handle, action, push_to_history, cx)
23055        })
23056    }
23057}
23058
23059fn snippet_completions(
23060    project: &Project,
23061    buffer: &Entity<Buffer>,
23062    buffer_position: text::Anchor,
23063    cx: &mut App,
23064) -> Task<Result<CompletionResponse>> {
23065    let languages = buffer.read(cx).languages_at(buffer_position);
23066    let snippet_store = project.snippets().read(cx);
23067
23068    let scopes: Vec<_> = languages
23069        .iter()
23070        .filter_map(|language| {
23071            let language_name = language.lsp_id();
23072            let snippets = snippet_store.snippets_for(Some(language_name), cx);
23073
23074            if snippets.is_empty() {
23075                None
23076            } else {
23077                Some((language.default_scope(), snippets))
23078            }
23079        })
23080        .collect();
23081
23082    if scopes.is_empty() {
23083        return Task::ready(Ok(CompletionResponse {
23084            completions: vec![],
23085            display_options: CompletionDisplayOptions::default(),
23086            is_incomplete: false,
23087        }));
23088    }
23089
23090    let snapshot = buffer.read(cx).text_snapshot();
23091    let executor = cx.background_executor().clone();
23092
23093    cx.background_spawn(async move {
23094        let mut is_incomplete = false;
23095        let mut completions: Vec<Completion> = Vec::new();
23096        for (scope, snippets) in scopes.into_iter() {
23097            let classifier =
23098                CharClassifier::new(Some(scope)).scope_context(Some(CharScopeContext::Completion));
23099
23100            const MAX_WORD_PREFIX_LEN: usize = 128;
23101            let last_word: String = snapshot
23102                .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
23103                .take(MAX_WORD_PREFIX_LEN)
23104                .take_while(|c| classifier.is_word(*c))
23105                .collect::<String>()
23106                .chars()
23107                .rev()
23108                .collect();
23109
23110            if last_word.is_empty() {
23111                return Ok(CompletionResponse {
23112                    completions: vec![],
23113                    display_options: CompletionDisplayOptions::default(),
23114                    is_incomplete: true,
23115                });
23116            }
23117
23118            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
23119            let to_lsp = |point: &text::Anchor| {
23120                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
23121                point_to_lsp(end)
23122            };
23123            let lsp_end = to_lsp(&buffer_position);
23124
23125            let candidates = snippets
23126                .iter()
23127                .enumerate()
23128                .flat_map(|(ix, snippet)| {
23129                    snippet
23130                        .prefix
23131                        .iter()
23132                        .map(move |prefix| StringMatchCandidate::new(ix, prefix))
23133                })
23134                .collect::<Vec<StringMatchCandidate>>();
23135
23136            const MAX_RESULTS: usize = 100;
23137            let mut matches = fuzzy::match_strings(
23138                &candidates,
23139                &last_word,
23140                last_word.chars().any(|c| c.is_uppercase()),
23141                true,
23142                MAX_RESULTS,
23143                &Default::default(),
23144                executor.clone(),
23145            )
23146            .await;
23147
23148            if matches.len() >= MAX_RESULTS {
23149                is_incomplete = true;
23150            }
23151
23152            // Remove all candidates where the query's start does not match the start of any word in the candidate
23153            if let Some(query_start) = last_word.chars().next() {
23154                matches.retain(|string_match| {
23155                    split_words(&string_match.string).any(|word| {
23156                        // Check that the first codepoint of the word as lowercase matches the first
23157                        // codepoint of the query as lowercase
23158                        word.chars()
23159                            .flat_map(|codepoint| codepoint.to_lowercase())
23160                            .zip(query_start.to_lowercase())
23161                            .all(|(word_cp, query_cp)| word_cp == query_cp)
23162                    })
23163                });
23164            }
23165
23166            let matched_strings = matches
23167                .into_iter()
23168                .map(|m| m.string)
23169                .collect::<HashSet<_>>();
23170
23171            completions.extend(snippets.iter().filter_map(|snippet| {
23172                let matching_prefix = snippet
23173                    .prefix
23174                    .iter()
23175                    .find(|prefix| matched_strings.contains(*prefix))?;
23176                let start = as_offset - last_word.len();
23177                let start = snapshot.anchor_before(start);
23178                let range = start..buffer_position;
23179                let lsp_start = to_lsp(&start);
23180                let lsp_range = lsp::Range {
23181                    start: lsp_start,
23182                    end: lsp_end,
23183                };
23184                Some(Completion {
23185                    replace_range: range,
23186                    new_text: snippet.body.clone(),
23187                    source: CompletionSource::Lsp {
23188                        insert_range: None,
23189                        server_id: LanguageServerId(usize::MAX),
23190                        resolved: true,
23191                        lsp_completion: Box::new(lsp::CompletionItem {
23192                            label: snippet.prefix.first().unwrap().clone(),
23193                            kind: Some(CompletionItemKind::SNIPPET),
23194                            label_details: snippet.description.as_ref().map(|description| {
23195                                lsp::CompletionItemLabelDetails {
23196                                    detail: Some(description.clone()),
23197                                    description: None,
23198                                }
23199                            }),
23200                            insert_text_format: Some(InsertTextFormat::SNIPPET),
23201                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
23202                                lsp::InsertReplaceEdit {
23203                                    new_text: snippet.body.clone(),
23204                                    insert: lsp_range,
23205                                    replace: lsp_range,
23206                                },
23207                            )),
23208                            filter_text: Some(snippet.body.clone()),
23209                            sort_text: Some(char::MAX.to_string()),
23210                            ..lsp::CompletionItem::default()
23211                        }),
23212                        lsp_defaults: None,
23213                    },
23214                    label: CodeLabel::plain(matching_prefix.clone(), None),
23215                    icon_path: None,
23216                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
23217                        single_line: snippet.name.clone().into(),
23218                        plain_text: snippet
23219                            .description
23220                            .clone()
23221                            .map(|description| description.into()),
23222                    }),
23223                    insert_text_mode: None,
23224                    confirm: None,
23225                })
23226            }))
23227        }
23228
23229        Ok(CompletionResponse {
23230            completions,
23231            display_options: CompletionDisplayOptions::default(),
23232            is_incomplete,
23233        })
23234    })
23235}
23236
23237impl CompletionProvider for Entity<Project> {
23238    fn completions(
23239        &self,
23240        _excerpt_id: ExcerptId,
23241        buffer: &Entity<Buffer>,
23242        buffer_position: text::Anchor,
23243        options: CompletionContext,
23244        _window: &mut Window,
23245        cx: &mut Context<Editor>,
23246    ) -> Task<Result<Vec<CompletionResponse>>> {
23247        self.update(cx, |project, cx| {
23248            let snippets = snippet_completions(project, buffer, buffer_position, cx);
23249            let project_completions = project.completions(buffer, buffer_position, options, cx);
23250            cx.background_spawn(async move {
23251                let mut responses = project_completions.await?;
23252                let snippets = snippets.await?;
23253                if !snippets.completions.is_empty() {
23254                    responses.push(snippets);
23255                }
23256                Ok(responses)
23257            })
23258        })
23259    }
23260
23261    fn resolve_completions(
23262        &self,
23263        buffer: Entity<Buffer>,
23264        completion_indices: Vec<usize>,
23265        completions: Rc<RefCell<Box<[Completion]>>>,
23266        cx: &mut Context<Editor>,
23267    ) -> Task<Result<bool>> {
23268        self.update(cx, |project, cx| {
23269            project.lsp_store().update(cx, |lsp_store, cx| {
23270                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
23271            })
23272        })
23273    }
23274
23275    fn apply_additional_edits_for_completion(
23276        &self,
23277        buffer: Entity<Buffer>,
23278        completions: Rc<RefCell<Box<[Completion]>>>,
23279        completion_index: usize,
23280        push_to_history: bool,
23281        cx: &mut Context<Editor>,
23282    ) -> Task<Result<Option<language::Transaction>>> {
23283        self.update(cx, |project, cx| {
23284            project.lsp_store().update(cx, |lsp_store, cx| {
23285                lsp_store.apply_additional_edits_for_completion(
23286                    buffer,
23287                    completions,
23288                    completion_index,
23289                    push_to_history,
23290                    cx,
23291                )
23292            })
23293        })
23294    }
23295
23296    fn is_completion_trigger(
23297        &self,
23298        buffer: &Entity<Buffer>,
23299        position: language::Anchor,
23300        text: &str,
23301        trigger_in_words: bool,
23302        menu_is_open: bool,
23303        cx: &mut Context<Editor>,
23304    ) -> bool {
23305        let mut chars = text.chars();
23306        let char = if let Some(char) = chars.next() {
23307            char
23308        } else {
23309            return false;
23310        };
23311        if chars.next().is_some() {
23312            return false;
23313        }
23314
23315        let buffer = buffer.read(cx);
23316        let snapshot = buffer.snapshot();
23317        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
23318            return false;
23319        }
23320        let classifier = snapshot
23321            .char_classifier_at(position)
23322            .scope_context(Some(CharScopeContext::Completion));
23323        if trigger_in_words && classifier.is_word(char) {
23324            return true;
23325        }
23326
23327        buffer.completion_triggers().contains(text)
23328    }
23329}
23330
23331impl SemanticsProvider for Entity<Project> {
23332    fn hover(
23333        &self,
23334        buffer: &Entity<Buffer>,
23335        position: text::Anchor,
23336        cx: &mut App,
23337    ) -> Option<Task<Option<Vec<project::Hover>>>> {
23338        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
23339    }
23340
23341    fn document_highlights(
23342        &self,
23343        buffer: &Entity<Buffer>,
23344        position: text::Anchor,
23345        cx: &mut App,
23346    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
23347        Some(self.update(cx, |project, cx| {
23348            project.document_highlights(buffer, position, cx)
23349        }))
23350    }
23351
23352    fn definitions(
23353        &self,
23354        buffer: &Entity<Buffer>,
23355        position: text::Anchor,
23356        kind: GotoDefinitionKind,
23357        cx: &mut App,
23358    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
23359        Some(self.update(cx, |project, cx| match kind {
23360            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
23361            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
23362            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
23363            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
23364        }))
23365    }
23366
23367    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
23368        self.update(cx, |project, cx| {
23369            if project
23370                .active_debug_session(cx)
23371                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
23372            {
23373                return true;
23374            }
23375
23376            buffer.update(cx, |buffer, cx| {
23377                project.any_language_server_supports_inlay_hints(buffer, cx)
23378            })
23379        })
23380    }
23381
23382    fn inline_values(
23383        &self,
23384        buffer_handle: Entity<Buffer>,
23385        range: Range<text::Anchor>,
23386        cx: &mut App,
23387    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
23388        self.update(cx, |project, cx| {
23389            let (session, active_stack_frame) = project.active_debug_session(cx)?;
23390
23391            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
23392        })
23393    }
23394
23395    fn inlay_hints(
23396        &self,
23397        buffer_handle: Entity<Buffer>,
23398        range: Range<text::Anchor>,
23399        cx: &mut App,
23400    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
23401        Some(self.update(cx, |project, cx| {
23402            project.inlay_hints(buffer_handle, range, cx)
23403        }))
23404    }
23405
23406    fn resolve_inlay_hint(
23407        &self,
23408        hint: InlayHint,
23409        buffer_handle: Entity<Buffer>,
23410        server_id: LanguageServerId,
23411        cx: &mut App,
23412    ) -> Option<Task<anyhow::Result<InlayHint>>> {
23413        Some(self.update(cx, |project, cx| {
23414            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
23415        }))
23416    }
23417
23418    fn range_for_rename(
23419        &self,
23420        buffer: &Entity<Buffer>,
23421        position: text::Anchor,
23422        cx: &mut App,
23423    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
23424        Some(self.update(cx, |project, cx| {
23425            let buffer = buffer.clone();
23426            let task = project.prepare_rename(buffer.clone(), position, cx);
23427            cx.spawn(async move |_, cx| {
23428                Ok(match task.await? {
23429                    PrepareRenameResponse::Success(range) => Some(range),
23430                    PrepareRenameResponse::InvalidPosition => None,
23431                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
23432                        // Fallback on using TreeSitter info to determine identifier range
23433                        buffer.read_with(cx, |buffer, _| {
23434                            let snapshot = buffer.snapshot();
23435                            let (range, kind) = snapshot.surrounding_word(position, None);
23436                            if kind != Some(CharKind::Word) {
23437                                return None;
23438                            }
23439                            Some(
23440                                snapshot.anchor_before(range.start)
23441                                    ..snapshot.anchor_after(range.end),
23442                            )
23443                        })?
23444                    }
23445                })
23446            })
23447        }))
23448    }
23449
23450    fn perform_rename(
23451        &self,
23452        buffer: &Entity<Buffer>,
23453        position: text::Anchor,
23454        new_name: String,
23455        cx: &mut App,
23456    ) -> Option<Task<Result<ProjectTransaction>>> {
23457        Some(self.update(cx, |project, cx| {
23458            project.perform_rename(buffer.clone(), position, new_name, cx)
23459        }))
23460    }
23461}
23462
23463fn inlay_hint_settings(
23464    location: Anchor,
23465    snapshot: &MultiBufferSnapshot,
23466    cx: &mut Context<Editor>,
23467) -> InlayHintSettings {
23468    let file = snapshot.file_at(location);
23469    let language = snapshot.language_at(location).map(|l| l.name());
23470    language_settings(language, file, cx).inlay_hints
23471}
23472
23473fn consume_contiguous_rows(
23474    contiguous_row_selections: &mut Vec<Selection<Point>>,
23475    selection: &Selection<Point>,
23476    display_map: &DisplaySnapshot,
23477    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
23478) -> (MultiBufferRow, MultiBufferRow) {
23479    contiguous_row_selections.push(selection.clone());
23480    let start_row = starting_row(selection, display_map);
23481    let mut end_row = ending_row(selection, display_map);
23482
23483    while let Some(next_selection) = selections.peek() {
23484        if next_selection.start.row <= end_row.0 {
23485            end_row = ending_row(next_selection, display_map);
23486            contiguous_row_selections.push(selections.next().unwrap().clone());
23487        } else {
23488            break;
23489        }
23490    }
23491    (start_row, end_row)
23492}
23493
23494fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23495    if selection.start.column > 0 {
23496        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
23497    } else {
23498        MultiBufferRow(selection.start.row)
23499    }
23500}
23501
23502fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23503    if next_selection.end.column > 0 || next_selection.is_empty() {
23504        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
23505    } else {
23506        MultiBufferRow(next_selection.end.row)
23507    }
23508}
23509
23510impl EditorSnapshot {
23511    pub fn remote_selections_in_range<'a>(
23512        &'a self,
23513        range: &'a Range<Anchor>,
23514        collaboration_hub: &dyn CollaborationHub,
23515        cx: &'a App,
23516    ) -> impl 'a + Iterator<Item = RemoteSelection> {
23517        let participant_names = collaboration_hub.user_names(cx);
23518        let participant_indices = collaboration_hub.user_participant_indices(cx);
23519        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
23520        let collaborators_by_replica_id = collaborators_by_peer_id
23521            .values()
23522            .map(|collaborator| (collaborator.replica_id, collaborator))
23523            .collect::<HashMap<_, _>>();
23524        self.buffer_snapshot()
23525            .selections_in_range(range, false)
23526            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
23527                if replica_id == ReplicaId::AGENT {
23528                    Some(RemoteSelection {
23529                        replica_id,
23530                        selection,
23531                        cursor_shape,
23532                        line_mode,
23533                        collaborator_id: CollaboratorId::Agent,
23534                        user_name: Some("Agent".into()),
23535                        color: cx.theme().players().agent(),
23536                    })
23537                } else {
23538                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
23539                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
23540                    let user_name = participant_names.get(&collaborator.user_id).cloned();
23541                    Some(RemoteSelection {
23542                        replica_id,
23543                        selection,
23544                        cursor_shape,
23545                        line_mode,
23546                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
23547                        user_name,
23548                        color: if let Some(index) = participant_index {
23549                            cx.theme().players().color_for_participant(index.0)
23550                        } else {
23551                            cx.theme().players().absent()
23552                        },
23553                    })
23554                }
23555            })
23556    }
23557
23558    pub fn hunks_for_ranges(
23559        &self,
23560        ranges: impl IntoIterator<Item = Range<Point>>,
23561    ) -> Vec<MultiBufferDiffHunk> {
23562        let mut hunks = Vec::new();
23563        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
23564            HashMap::default();
23565        for query_range in ranges {
23566            let query_rows =
23567                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
23568            for hunk in self.buffer_snapshot().diff_hunks_in_range(
23569                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
23570            ) {
23571                // Include deleted hunks that are adjacent to the query range, because
23572                // otherwise they would be missed.
23573                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
23574                if hunk.status().is_deleted() {
23575                    intersects_range |= hunk.row_range.start == query_rows.end;
23576                    intersects_range |= hunk.row_range.end == query_rows.start;
23577                }
23578                if intersects_range {
23579                    if !processed_buffer_rows
23580                        .entry(hunk.buffer_id)
23581                        .or_default()
23582                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
23583                    {
23584                        continue;
23585                    }
23586                    hunks.push(hunk);
23587                }
23588            }
23589        }
23590
23591        hunks
23592    }
23593
23594    fn display_diff_hunks_for_rows<'a>(
23595        &'a self,
23596        display_rows: Range<DisplayRow>,
23597        folded_buffers: &'a HashSet<BufferId>,
23598    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
23599        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
23600        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
23601
23602        self.buffer_snapshot()
23603            .diff_hunks_in_range(buffer_start..buffer_end)
23604            .filter_map(|hunk| {
23605                if folded_buffers.contains(&hunk.buffer_id) {
23606                    return None;
23607                }
23608
23609                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
23610                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
23611
23612                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
23613                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
23614
23615                let display_hunk = if hunk_display_start.column() != 0 {
23616                    DisplayDiffHunk::Folded {
23617                        display_row: hunk_display_start.row(),
23618                    }
23619                } else {
23620                    let mut end_row = hunk_display_end.row();
23621                    if hunk_display_end.column() > 0 {
23622                        end_row.0 += 1;
23623                    }
23624                    let is_created_file = hunk.is_created_file();
23625                    DisplayDiffHunk::Unfolded {
23626                        status: hunk.status(),
23627                        diff_base_byte_range: hunk.diff_base_byte_range,
23628                        display_row_range: hunk_display_start.row()..end_row,
23629                        multi_buffer_range: Anchor::range_in_buffer(
23630                            hunk.excerpt_id,
23631                            hunk.buffer_id,
23632                            hunk.buffer_range,
23633                        ),
23634                        is_created_file,
23635                    }
23636                };
23637
23638                Some(display_hunk)
23639            })
23640    }
23641
23642    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
23643        self.display_snapshot
23644            .buffer_snapshot()
23645            .language_at(position)
23646    }
23647
23648    pub fn is_focused(&self) -> bool {
23649        self.is_focused
23650    }
23651
23652    pub fn placeholder_text(&self) -> Option<String> {
23653        self.placeholder_display_snapshot
23654            .as_ref()
23655            .map(|display_map| display_map.text())
23656    }
23657
23658    pub fn scroll_position(&self) -> gpui::Point<ScrollOffset> {
23659        self.scroll_anchor.scroll_position(&self.display_snapshot)
23660    }
23661
23662    fn gutter_dimensions(
23663        &self,
23664        font_id: FontId,
23665        font_size: Pixels,
23666        max_line_number_width: Pixels,
23667        cx: &App,
23668    ) -> Option<GutterDimensions> {
23669        if !self.show_gutter {
23670            return None;
23671        }
23672
23673        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
23674        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
23675
23676        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
23677            matches!(
23678                ProjectSettings::get_global(cx).git.git_gutter,
23679                GitGutterSetting::TrackedFiles
23680            )
23681        });
23682        let gutter_settings = EditorSettings::get_global(cx).gutter;
23683        let show_line_numbers = self
23684            .show_line_numbers
23685            .unwrap_or(gutter_settings.line_numbers);
23686        let line_gutter_width = if show_line_numbers {
23687            // Avoid flicker-like gutter resizes when the line number gains another digit by
23688            // only resizing the gutter on files with > 10**min_line_number_digits lines.
23689            let min_width_for_number_on_gutter =
23690                ch_advance * gutter_settings.min_line_number_digits as f32;
23691            max_line_number_width.max(min_width_for_number_on_gutter)
23692        } else {
23693            0.0.into()
23694        };
23695
23696        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
23697        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
23698
23699        let git_blame_entries_width =
23700            self.git_blame_gutter_max_author_length
23701                .map(|max_author_length| {
23702                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
23703                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
23704
23705                    /// The number of characters to dedicate to gaps and margins.
23706                    const SPACING_WIDTH: usize = 4;
23707
23708                    let max_char_count = max_author_length.min(renderer.max_author_length())
23709                        + ::git::SHORT_SHA_LENGTH
23710                        + MAX_RELATIVE_TIMESTAMP.len()
23711                        + SPACING_WIDTH;
23712
23713                    ch_advance * max_char_count
23714                });
23715
23716        let is_singleton = self.buffer_snapshot().is_singleton();
23717
23718        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
23719        left_padding += if !is_singleton {
23720            ch_width * 4.0
23721        } else if show_runnables || show_breakpoints {
23722            ch_width * 3.0
23723        } else if show_git_gutter && show_line_numbers {
23724            ch_width * 2.0
23725        } else if show_git_gutter || show_line_numbers {
23726            ch_width
23727        } else {
23728            px(0.)
23729        };
23730
23731        let shows_folds = is_singleton && gutter_settings.folds;
23732
23733        let right_padding = if shows_folds && show_line_numbers {
23734            ch_width * 4.0
23735        } else if shows_folds || (!is_singleton && show_line_numbers) {
23736            ch_width * 3.0
23737        } else if show_line_numbers {
23738            ch_width
23739        } else {
23740            px(0.)
23741        };
23742
23743        Some(GutterDimensions {
23744            left_padding,
23745            right_padding,
23746            width: line_gutter_width + left_padding + right_padding,
23747            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
23748            git_blame_entries_width,
23749        })
23750    }
23751
23752    pub fn render_crease_toggle(
23753        &self,
23754        buffer_row: MultiBufferRow,
23755        row_contains_cursor: bool,
23756        editor: Entity<Editor>,
23757        window: &mut Window,
23758        cx: &mut App,
23759    ) -> Option<AnyElement> {
23760        let folded = self.is_line_folded(buffer_row);
23761        let mut is_foldable = false;
23762
23763        if let Some(crease) = self
23764            .crease_snapshot
23765            .query_row(buffer_row, self.buffer_snapshot())
23766        {
23767            is_foldable = true;
23768            match crease {
23769                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
23770                    if let Some(render_toggle) = render_toggle {
23771                        let toggle_callback =
23772                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
23773                                if folded {
23774                                    editor.update(cx, |editor, cx| {
23775                                        editor.fold_at(buffer_row, window, cx)
23776                                    });
23777                                } else {
23778                                    editor.update(cx, |editor, cx| {
23779                                        editor.unfold_at(buffer_row, window, cx)
23780                                    });
23781                                }
23782                            });
23783                        return Some((render_toggle)(
23784                            buffer_row,
23785                            folded,
23786                            toggle_callback,
23787                            window,
23788                            cx,
23789                        ));
23790                    }
23791                }
23792            }
23793        }
23794
23795        is_foldable |= self.starts_indent(buffer_row);
23796
23797        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
23798            Some(
23799                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
23800                    .toggle_state(folded)
23801                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
23802                        if folded {
23803                            this.unfold_at(buffer_row, window, cx);
23804                        } else {
23805                            this.fold_at(buffer_row, window, cx);
23806                        }
23807                    }))
23808                    .into_any_element(),
23809            )
23810        } else {
23811            None
23812        }
23813    }
23814
23815    pub fn render_crease_trailer(
23816        &self,
23817        buffer_row: MultiBufferRow,
23818        window: &mut Window,
23819        cx: &mut App,
23820    ) -> Option<AnyElement> {
23821        let folded = self.is_line_folded(buffer_row);
23822        if let Crease::Inline { render_trailer, .. } = self
23823            .crease_snapshot
23824            .query_row(buffer_row, self.buffer_snapshot())?
23825        {
23826            let render_trailer = render_trailer.as_ref()?;
23827            Some(render_trailer(buffer_row, folded, window, cx))
23828        } else {
23829            None
23830        }
23831    }
23832}
23833
23834impl Deref for EditorSnapshot {
23835    type Target = DisplaySnapshot;
23836
23837    fn deref(&self) -> &Self::Target {
23838        &self.display_snapshot
23839    }
23840}
23841
23842#[derive(Clone, Debug, PartialEq, Eq)]
23843pub enum EditorEvent {
23844    InputIgnored {
23845        text: Arc<str>,
23846    },
23847    InputHandled {
23848        utf16_range_to_replace: Option<Range<isize>>,
23849        text: Arc<str>,
23850    },
23851    ExcerptsAdded {
23852        buffer: Entity<Buffer>,
23853        predecessor: ExcerptId,
23854        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
23855    },
23856    ExcerptsRemoved {
23857        ids: Vec<ExcerptId>,
23858        removed_buffer_ids: Vec<BufferId>,
23859    },
23860    BufferFoldToggled {
23861        ids: Vec<ExcerptId>,
23862        folded: bool,
23863    },
23864    ExcerptsEdited {
23865        ids: Vec<ExcerptId>,
23866    },
23867    ExcerptsExpanded {
23868        ids: Vec<ExcerptId>,
23869    },
23870    BufferEdited,
23871    Edited {
23872        transaction_id: clock::Lamport,
23873    },
23874    Reparsed(BufferId),
23875    Focused,
23876    FocusedIn,
23877    Blurred,
23878    DirtyChanged,
23879    Saved,
23880    TitleChanged,
23881    SelectionsChanged {
23882        local: bool,
23883    },
23884    ScrollPositionChanged {
23885        local: bool,
23886        autoscroll: bool,
23887    },
23888    TransactionUndone {
23889        transaction_id: clock::Lamport,
23890    },
23891    TransactionBegun {
23892        transaction_id: clock::Lamport,
23893    },
23894    CursorShapeChanged,
23895    BreadcrumbsChanged,
23896    PushedToNavHistory {
23897        anchor: Anchor,
23898        is_deactivate: bool,
23899    },
23900}
23901
23902impl EventEmitter<EditorEvent> for Editor {}
23903
23904impl Focusable for Editor {
23905    fn focus_handle(&self, _cx: &App) -> FocusHandle {
23906        self.focus_handle.clone()
23907    }
23908}
23909
23910impl Render for Editor {
23911    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23912        let settings = ThemeSettings::get_global(cx);
23913
23914        let mut text_style = match self.mode {
23915            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
23916                color: cx.theme().colors().editor_foreground,
23917                font_family: settings.ui_font.family.clone(),
23918                font_features: settings.ui_font.features.clone(),
23919                font_fallbacks: settings.ui_font.fallbacks.clone(),
23920                font_size: rems(0.875).into(),
23921                font_weight: settings.ui_font.weight,
23922                line_height: relative(settings.buffer_line_height.value()),
23923                ..Default::default()
23924            },
23925            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
23926                color: cx.theme().colors().editor_foreground,
23927                font_family: settings.buffer_font.family.clone(),
23928                font_features: settings.buffer_font.features.clone(),
23929                font_fallbacks: settings.buffer_font.fallbacks.clone(),
23930                font_size: settings.buffer_font_size(cx).into(),
23931                font_weight: settings.buffer_font.weight,
23932                line_height: relative(settings.buffer_line_height.value()),
23933                ..Default::default()
23934            },
23935        };
23936        if let Some(text_style_refinement) = &self.text_style_refinement {
23937            text_style.refine(text_style_refinement)
23938        }
23939
23940        let background = match self.mode {
23941            EditorMode::SingleLine => cx.theme().system().transparent,
23942            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
23943            EditorMode::Full { .. } => cx.theme().colors().editor_background,
23944            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
23945        };
23946
23947        EditorElement::new(
23948            &cx.entity(),
23949            EditorStyle {
23950                background,
23951                border: cx.theme().colors().border,
23952                local_player: cx.theme().players().local(),
23953                text: text_style,
23954                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
23955                syntax: cx.theme().syntax().clone(),
23956                status: cx.theme().status().clone(),
23957                inlay_hints_style: make_inlay_hints_style(cx),
23958                edit_prediction_styles: make_suggestion_styles(cx),
23959                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
23960                show_underlines: self.diagnostics_enabled(),
23961            },
23962        )
23963    }
23964}
23965
23966impl EntityInputHandler for Editor {
23967    fn text_for_range(
23968        &mut self,
23969        range_utf16: Range<usize>,
23970        adjusted_range: &mut Option<Range<usize>>,
23971        _: &mut Window,
23972        cx: &mut Context<Self>,
23973    ) -> Option<String> {
23974        let snapshot = self.buffer.read(cx).read(cx);
23975        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
23976        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
23977        if (start.0..end.0) != range_utf16 {
23978            adjusted_range.replace(start.0..end.0);
23979        }
23980        Some(snapshot.text_for_range(start..end).collect())
23981    }
23982
23983    fn selected_text_range(
23984        &mut self,
23985        ignore_disabled_input: bool,
23986        _: &mut Window,
23987        cx: &mut Context<Self>,
23988    ) -> Option<UTF16Selection> {
23989        // Prevent the IME menu from appearing when holding down an alphabetic key
23990        // while input is disabled.
23991        if !ignore_disabled_input && !self.input_enabled {
23992            return None;
23993        }
23994
23995        let selection = self
23996            .selections
23997            .newest::<OffsetUtf16>(&self.display_snapshot(cx));
23998        let range = selection.range();
23999
24000        Some(UTF16Selection {
24001            range: range.start.0..range.end.0,
24002            reversed: selection.reversed,
24003        })
24004    }
24005
24006    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
24007        let snapshot = self.buffer.read(cx).read(cx);
24008        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
24009        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
24010    }
24011
24012    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
24013        self.clear_highlights::<InputComposition>(cx);
24014        self.ime_transaction.take();
24015    }
24016
24017    fn replace_text_in_range(
24018        &mut self,
24019        range_utf16: Option<Range<usize>>,
24020        text: &str,
24021        window: &mut Window,
24022        cx: &mut Context<Self>,
24023    ) {
24024        if !self.input_enabled {
24025            cx.emit(EditorEvent::InputIgnored { text: text.into() });
24026            return;
24027        }
24028
24029        self.transact(window, cx, |this, window, cx| {
24030            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
24031                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
24032                Some(this.selection_replacement_ranges(range_utf16, cx))
24033            } else {
24034                this.marked_text_ranges(cx)
24035            };
24036
24037            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
24038                let newest_selection_id = this.selections.newest_anchor().id;
24039                this.selections
24040                    .all::<OffsetUtf16>(&this.display_snapshot(cx))
24041                    .iter()
24042                    .zip(ranges_to_replace.iter())
24043                    .find_map(|(selection, range)| {
24044                        if selection.id == newest_selection_id {
24045                            Some(
24046                                (range.start.0 as isize - selection.head().0 as isize)
24047                                    ..(range.end.0 as isize - selection.head().0 as isize),
24048                            )
24049                        } else {
24050                            None
24051                        }
24052                    })
24053            });
24054
24055            cx.emit(EditorEvent::InputHandled {
24056                utf16_range_to_replace: range_to_replace,
24057                text: text.into(),
24058            });
24059
24060            if let Some(new_selected_ranges) = new_selected_ranges {
24061                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
24062                    selections.select_ranges(new_selected_ranges)
24063                });
24064                this.backspace(&Default::default(), window, cx);
24065            }
24066
24067            this.handle_input(text, window, cx);
24068        });
24069
24070        if let Some(transaction) = self.ime_transaction {
24071            self.buffer.update(cx, |buffer, cx| {
24072                buffer.group_until_transaction(transaction, cx);
24073            });
24074        }
24075
24076        self.unmark_text(window, cx);
24077    }
24078
24079    fn replace_and_mark_text_in_range(
24080        &mut self,
24081        range_utf16: Option<Range<usize>>,
24082        text: &str,
24083        new_selected_range_utf16: Option<Range<usize>>,
24084        window: &mut Window,
24085        cx: &mut Context<Self>,
24086    ) {
24087        if !self.input_enabled {
24088            return;
24089        }
24090
24091        let transaction = self.transact(window, cx, |this, window, cx| {
24092            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
24093                let snapshot = this.buffer.read(cx).read(cx);
24094                if let Some(relative_range_utf16) = range_utf16.as_ref() {
24095                    for marked_range in &mut marked_ranges {
24096                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
24097                        marked_range.start.0 += relative_range_utf16.start;
24098                        marked_range.start =
24099                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
24100                        marked_range.end =
24101                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
24102                    }
24103                }
24104                Some(marked_ranges)
24105            } else if let Some(range_utf16) = range_utf16 {
24106                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
24107                Some(this.selection_replacement_ranges(range_utf16, cx))
24108            } else {
24109                None
24110            };
24111
24112            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
24113                let newest_selection_id = this.selections.newest_anchor().id;
24114                this.selections
24115                    .all::<OffsetUtf16>(&this.display_snapshot(cx))
24116                    .iter()
24117                    .zip(ranges_to_replace.iter())
24118                    .find_map(|(selection, range)| {
24119                        if selection.id == newest_selection_id {
24120                            Some(
24121                                (range.start.0 as isize - selection.head().0 as isize)
24122                                    ..(range.end.0 as isize - selection.head().0 as isize),
24123                            )
24124                        } else {
24125                            None
24126                        }
24127                    })
24128            });
24129
24130            cx.emit(EditorEvent::InputHandled {
24131                utf16_range_to_replace: range_to_replace,
24132                text: text.into(),
24133            });
24134
24135            if let Some(ranges) = ranges_to_replace {
24136                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
24137                    s.select_ranges(ranges)
24138                });
24139            }
24140
24141            let marked_ranges = {
24142                let snapshot = this.buffer.read(cx).read(cx);
24143                this.selections
24144                    .disjoint_anchors_arc()
24145                    .iter()
24146                    .map(|selection| {
24147                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
24148                    })
24149                    .collect::<Vec<_>>()
24150            };
24151
24152            if text.is_empty() {
24153                this.unmark_text(window, cx);
24154            } else {
24155                this.highlight_text::<InputComposition>(
24156                    marked_ranges.clone(),
24157                    HighlightStyle {
24158                        underline: Some(UnderlineStyle {
24159                            thickness: px(1.),
24160                            color: None,
24161                            wavy: false,
24162                        }),
24163                        ..Default::default()
24164                    },
24165                    cx,
24166                );
24167            }
24168
24169            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
24170            let use_autoclose = this.use_autoclose;
24171            let use_auto_surround = this.use_auto_surround;
24172            this.set_use_autoclose(false);
24173            this.set_use_auto_surround(false);
24174            this.handle_input(text, window, cx);
24175            this.set_use_autoclose(use_autoclose);
24176            this.set_use_auto_surround(use_auto_surround);
24177
24178            if let Some(new_selected_range) = new_selected_range_utf16 {
24179                let snapshot = this.buffer.read(cx).read(cx);
24180                let new_selected_ranges = marked_ranges
24181                    .into_iter()
24182                    .map(|marked_range| {
24183                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
24184                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
24185                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
24186                        snapshot.clip_offset_utf16(new_start, Bias::Left)
24187                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
24188                    })
24189                    .collect::<Vec<_>>();
24190
24191                drop(snapshot);
24192                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
24193                    selections.select_ranges(new_selected_ranges)
24194                });
24195            }
24196        });
24197
24198        self.ime_transaction = self.ime_transaction.or(transaction);
24199        if let Some(transaction) = self.ime_transaction {
24200            self.buffer.update(cx, |buffer, cx| {
24201                buffer.group_until_transaction(transaction, cx);
24202            });
24203        }
24204
24205        if self.text_highlights::<InputComposition>(cx).is_none() {
24206            self.ime_transaction.take();
24207        }
24208    }
24209
24210    fn bounds_for_range(
24211        &mut self,
24212        range_utf16: Range<usize>,
24213        element_bounds: gpui::Bounds<Pixels>,
24214        window: &mut Window,
24215        cx: &mut Context<Self>,
24216    ) -> Option<gpui::Bounds<Pixels>> {
24217        let text_layout_details = self.text_layout_details(window);
24218        let CharacterDimensions {
24219            em_width,
24220            em_advance,
24221            line_height,
24222        } = self.character_dimensions(window);
24223
24224        let snapshot = self.snapshot(window, cx);
24225        let scroll_position = snapshot.scroll_position();
24226        let scroll_left = scroll_position.x * ScrollOffset::from(em_advance);
24227
24228        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
24229        let x = Pixels::from(
24230            ScrollOffset::from(
24231                snapshot.x_for_display_point(start, &text_layout_details)
24232                    + self.gutter_dimensions.full_width(),
24233            ) - scroll_left,
24234        );
24235        let y = line_height * (start.row().as_f64() - scroll_position.y) as f32;
24236
24237        Some(Bounds {
24238            origin: element_bounds.origin + point(x, y),
24239            size: size(em_width, line_height),
24240        })
24241    }
24242
24243    fn character_index_for_point(
24244        &mut self,
24245        point: gpui::Point<Pixels>,
24246        _window: &mut Window,
24247        _cx: &mut Context<Self>,
24248    ) -> Option<usize> {
24249        let position_map = self.last_position_map.as_ref()?;
24250        if !position_map.text_hitbox.contains(&point) {
24251            return None;
24252        }
24253        let display_point = position_map.point_for_position(point).previous_valid;
24254        let anchor = position_map
24255            .snapshot
24256            .display_point_to_anchor(display_point, Bias::Left);
24257        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot());
24258        Some(utf16_offset.0)
24259    }
24260}
24261
24262trait SelectionExt {
24263    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
24264    fn spanned_rows(
24265        &self,
24266        include_end_if_at_line_start: bool,
24267        map: &DisplaySnapshot,
24268    ) -> Range<MultiBufferRow>;
24269}
24270
24271impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
24272    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
24273        let start = self
24274            .start
24275            .to_point(map.buffer_snapshot())
24276            .to_display_point(map);
24277        let end = self
24278            .end
24279            .to_point(map.buffer_snapshot())
24280            .to_display_point(map);
24281        if self.reversed {
24282            end..start
24283        } else {
24284            start..end
24285        }
24286    }
24287
24288    fn spanned_rows(
24289        &self,
24290        include_end_if_at_line_start: bool,
24291        map: &DisplaySnapshot,
24292    ) -> Range<MultiBufferRow> {
24293        let start = self.start.to_point(map.buffer_snapshot());
24294        let mut end = self.end.to_point(map.buffer_snapshot());
24295        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
24296            end.row -= 1;
24297        }
24298
24299        let buffer_start = map.prev_line_boundary(start).0;
24300        let buffer_end = map.next_line_boundary(end).0;
24301        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
24302    }
24303}
24304
24305impl<T: InvalidationRegion> InvalidationStack<T> {
24306    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
24307    where
24308        S: Clone + ToOffset,
24309    {
24310        while let Some(region) = self.last() {
24311            let all_selections_inside_invalidation_ranges =
24312                if selections.len() == region.ranges().len() {
24313                    selections
24314                        .iter()
24315                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
24316                        .all(|(selection, invalidation_range)| {
24317                            let head = selection.head().to_offset(buffer);
24318                            invalidation_range.start <= head && invalidation_range.end >= head
24319                        })
24320                } else {
24321                    false
24322                };
24323
24324            if all_selections_inside_invalidation_ranges {
24325                break;
24326            } else {
24327                self.pop();
24328            }
24329        }
24330    }
24331}
24332
24333impl<T> Default for InvalidationStack<T> {
24334    fn default() -> Self {
24335        Self(Default::default())
24336    }
24337}
24338
24339impl<T> Deref for InvalidationStack<T> {
24340    type Target = Vec<T>;
24341
24342    fn deref(&self) -> &Self::Target {
24343        &self.0
24344    }
24345}
24346
24347impl<T> DerefMut for InvalidationStack<T> {
24348    fn deref_mut(&mut self) -> &mut Self::Target {
24349        &mut self.0
24350    }
24351}
24352
24353impl InvalidationRegion for SnippetState {
24354    fn ranges(&self) -> &[Range<Anchor>] {
24355        &self.ranges[self.active_index]
24356    }
24357}
24358
24359fn edit_prediction_edit_text(
24360    current_snapshot: &BufferSnapshot,
24361    edits: &[(Range<Anchor>, String)],
24362    edit_preview: &EditPreview,
24363    include_deletions: bool,
24364    cx: &App,
24365) -> HighlightedText {
24366    let edits = edits
24367        .iter()
24368        .map(|(anchor, text)| {
24369            (
24370                anchor.start.text_anchor..anchor.end.text_anchor,
24371                text.clone(),
24372            )
24373        })
24374        .collect::<Vec<_>>();
24375
24376    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
24377}
24378
24379fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, String)], cx: &App) -> HighlightedText {
24380    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
24381    // Just show the raw edit text with basic styling
24382    let mut text = String::new();
24383    let mut highlights = Vec::new();
24384
24385    let insertion_highlight_style = HighlightStyle {
24386        color: Some(cx.theme().colors().text),
24387        ..Default::default()
24388    };
24389
24390    for (_, edit_text) in edits {
24391        let start_offset = text.len();
24392        text.push_str(edit_text);
24393        let end_offset = text.len();
24394
24395        if start_offset < end_offset {
24396            highlights.push((start_offset..end_offset, insertion_highlight_style));
24397        }
24398    }
24399
24400    HighlightedText {
24401        text: text.into(),
24402        highlights,
24403    }
24404}
24405
24406pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
24407    match severity {
24408        lsp::DiagnosticSeverity::ERROR => colors.error,
24409        lsp::DiagnosticSeverity::WARNING => colors.warning,
24410        lsp::DiagnosticSeverity::INFORMATION => colors.info,
24411        lsp::DiagnosticSeverity::HINT => colors.info,
24412        _ => colors.ignored,
24413    }
24414}
24415
24416pub fn styled_runs_for_code_label<'a>(
24417    label: &'a CodeLabel,
24418    syntax_theme: &'a theme::SyntaxTheme,
24419) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
24420    let fade_out = HighlightStyle {
24421        fade_out: Some(0.35),
24422        ..Default::default()
24423    };
24424
24425    let mut prev_end = label.filter_range.end;
24426    label
24427        .runs
24428        .iter()
24429        .enumerate()
24430        .flat_map(move |(ix, (range, highlight_id))| {
24431            let style = if let Some(style) = highlight_id.style(syntax_theme) {
24432                style
24433            } else {
24434                return Default::default();
24435            };
24436            let muted_style = style.highlight(fade_out);
24437
24438            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
24439            if range.start >= label.filter_range.end {
24440                if range.start > prev_end {
24441                    runs.push((prev_end..range.start, fade_out));
24442                }
24443                runs.push((range.clone(), muted_style));
24444            } else if range.end <= label.filter_range.end {
24445                runs.push((range.clone(), style));
24446            } else {
24447                runs.push((range.start..label.filter_range.end, style));
24448                runs.push((label.filter_range.end..range.end, muted_style));
24449            }
24450            prev_end = cmp::max(prev_end, range.end);
24451
24452            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
24453                runs.push((prev_end..label.text.len(), fade_out));
24454            }
24455
24456            runs
24457        })
24458}
24459
24460pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
24461    let mut prev_index = 0;
24462    let mut prev_codepoint: Option<char> = None;
24463    text.char_indices()
24464        .chain([(text.len(), '\0')])
24465        .filter_map(move |(index, codepoint)| {
24466            let prev_codepoint = prev_codepoint.replace(codepoint)?;
24467            let is_boundary = index == text.len()
24468                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
24469                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
24470            if is_boundary {
24471                let chunk = &text[prev_index..index];
24472                prev_index = index;
24473                Some(chunk)
24474            } else {
24475                None
24476            }
24477        })
24478}
24479
24480pub trait RangeToAnchorExt: Sized {
24481    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
24482
24483    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
24484        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot());
24485        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
24486    }
24487}
24488
24489impl<T: ToOffset> RangeToAnchorExt for Range<T> {
24490    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
24491        let start_offset = self.start.to_offset(snapshot);
24492        let end_offset = self.end.to_offset(snapshot);
24493        if start_offset == end_offset {
24494            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
24495        } else {
24496            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
24497        }
24498    }
24499}
24500
24501pub trait RowExt {
24502    fn as_f64(&self) -> f64;
24503
24504    fn next_row(&self) -> Self;
24505
24506    fn previous_row(&self) -> Self;
24507
24508    fn minus(&self, other: Self) -> u32;
24509}
24510
24511impl RowExt for DisplayRow {
24512    fn as_f64(&self) -> f64 {
24513        self.0 as _
24514    }
24515
24516    fn next_row(&self) -> Self {
24517        Self(self.0 + 1)
24518    }
24519
24520    fn previous_row(&self) -> Self {
24521        Self(self.0.saturating_sub(1))
24522    }
24523
24524    fn minus(&self, other: Self) -> u32 {
24525        self.0 - other.0
24526    }
24527}
24528
24529impl RowExt for MultiBufferRow {
24530    fn as_f64(&self) -> f64 {
24531        self.0 as _
24532    }
24533
24534    fn next_row(&self) -> Self {
24535        Self(self.0 + 1)
24536    }
24537
24538    fn previous_row(&self) -> Self {
24539        Self(self.0.saturating_sub(1))
24540    }
24541
24542    fn minus(&self, other: Self) -> u32 {
24543        self.0 - other.0
24544    }
24545}
24546
24547trait RowRangeExt {
24548    type Row;
24549
24550    fn len(&self) -> usize;
24551
24552    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
24553}
24554
24555impl RowRangeExt for Range<MultiBufferRow> {
24556    type Row = MultiBufferRow;
24557
24558    fn len(&self) -> usize {
24559        (self.end.0 - self.start.0) as usize
24560    }
24561
24562    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
24563        (self.start.0..self.end.0).map(MultiBufferRow)
24564    }
24565}
24566
24567impl RowRangeExt for Range<DisplayRow> {
24568    type Row = DisplayRow;
24569
24570    fn len(&self) -> usize {
24571        (self.end.0 - self.start.0) as usize
24572    }
24573
24574    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
24575        (self.start.0..self.end.0).map(DisplayRow)
24576    }
24577}
24578
24579/// If select range has more than one line, we
24580/// just point the cursor to range.start.
24581fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
24582    if range.start.row == range.end.row {
24583        range
24584    } else {
24585        range.start..range.start
24586    }
24587}
24588pub struct KillRing(ClipboardItem);
24589impl Global for KillRing {}
24590
24591const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
24592
24593enum BreakpointPromptEditAction {
24594    Log,
24595    Condition,
24596    HitCondition,
24597}
24598
24599struct BreakpointPromptEditor {
24600    pub(crate) prompt: Entity<Editor>,
24601    editor: WeakEntity<Editor>,
24602    breakpoint_anchor: Anchor,
24603    breakpoint: Breakpoint,
24604    edit_action: BreakpointPromptEditAction,
24605    block_ids: HashSet<CustomBlockId>,
24606    editor_margins: Arc<Mutex<EditorMargins>>,
24607    _subscriptions: Vec<Subscription>,
24608}
24609
24610impl BreakpointPromptEditor {
24611    const MAX_LINES: u8 = 4;
24612
24613    fn new(
24614        editor: WeakEntity<Editor>,
24615        breakpoint_anchor: Anchor,
24616        breakpoint: Breakpoint,
24617        edit_action: BreakpointPromptEditAction,
24618        window: &mut Window,
24619        cx: &mut Context<Self>,
24620    ) -> Self {
24621        let base_text = match edit_action {
24622            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
24623            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
24624            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
24625        }
24626        .map(|msg| msg.to_string())
24627        .unwrap_or_default();
24628
24629        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
24630        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
24631
24632        let prompt = cx.new(|cx| {
24633            let mut prompt = Editor::new(
24634                EditorMode::AutoHeight {
24635                    min_lines: 1,
24636                    max_lines: Some(Self::MAX_LINES as usize),
24637                },
24638                buffer,
24639                None,
24640                window,
24641                cx,
24642            );
24643            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
24644            prompt.set_show_cursor_when_unfocused(false, cx);
24645            prompt.set_placeholder_text(
24646                match edit_action {
24647                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
24648                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
24649                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
24650                },
24651                window,
24652                cx,
24653            );
24654
24655            prompt
24656        });
24657
24658        Self {
24659            prompt,
24660            editor,
24661            breakpoint_anchor,
24662            breakpoint,
24663            edit_action,
24664            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
24665            block_ids: Default::default(),
24666            _subscriptions: vec![],
24667        }
24668    }
24669
24670    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
24671        self.block_ids.extend(block_ids)
24672    }
24673
24674    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
24675        if let Some(editor) = self.editor.upgrade() {
24676            let message = self
24677                .prompt
24678                .read(cx)
24679                .buffer
24680                .read(cx)
24681                .as_singleton()
24682                .expect("A multi buffer in breakpoint prompt isn't possible")
24683                .read(cx)
24684                .as_rope()
24685                .to_string();
24686
24687            editor.update(cx, |editor, cx| {
24688                editor.edit_breakpoint_at_anchor(
24689                    self.breakpoint_anchor,
24690                    self.breakpoint.clone(),
24691                    match self.edit_action {
24692                        BreakpointPromptEditAction::Log => {
24693                            BreakpointEditAction::EditLogMessage(message.into())
24694                        }
24695                        BreakpointPromptEditAction::Condition => {
24696                            BreakpointEditAction::EditCondition(message.into())
24697                        }
24698                        BreakpointPromptEditAction::HitCondition => {
24699                            BreakpointEditAction::EditHitCondition(message.into())
24700                        }
24701                    },
24702                    cx,
24703                );
24704
24705                editor.remove_blocks(self.block_ids.clone(), None, cx);
24706                cx.focus_self(window);
24707            });
24708        }
24709    }
24710
24711    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
24712        self.editor
24713            .update(cx, |editor, cx| {
24714                editor.remove_blocks(self.block_ids.clone(), None, cx);
24715                window.focus(&editor.focus_handle);
24716            })
24717            .log_err();
24718    }
24719
24720    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
24721        let settings = ThemeSettings::get_global(cx);
24722        let text_style = TextStyle {
24723            color: if self.prompt.read(cx).read_only(cx) {
24724                cx.theme().colors().text_disabled
24725            } else {
24726                cx.theme().colors().text
24727            },
24728            font_family: settings.buffer_font.family.clone(),
24729            font_fallbacks: settings.buffer_font.fallbacks.clone(),
24730            font_size: settings.buffer_font_size(cx).into(),
24731            font_weight: settings.buffer_font.weight,
24732            line_height: relative(settings.buffer_line_height.value()),
24733            ..Default::default()
24734        };
24735        EditorElement::new(
24736            &self.prompt,
24737            EditorStyle {
24738                background: cx.theme().colors().editor_background,
24739                local_player: cx.theme().players().local(),
24740                text: text_style,
24741                ..Default::default()
24742            },
24743        )
24744    }
24745}
24746
24747impl Render for BreakpointPromptEditor {
24748    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24749        let editor_margins = *self.editor_margins.lock();
24750        let gutter_dimensions = editor_margins.gutter;
24751        h_flex()
24752            .key_context("Editor")
24753            .bg(cx.theme().colors().editor_background)
24754            .border_y_1()
24755            .border_color(cx.theme().status().info_border)
24756            .size_full()
24757            .py(window.line_height() / 2.5)
24758            .on_action(cx.listener(Self::confirm))
24759            .on_action(cx.listener(Self::cancel))
24760            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
24761            .child(div().flex_1().child(self.render_prompt_editor(cx)))
24762    }
24763}
24764
24765impl Focusable for BreakpointPromptEditor {
24766    fn focus_handle(&self, cx: &App) -> FocusHandle {
24767        self.prompt.focus_handle(cx)
24768    }
24769}
24770
24771fn all_edits_insertions_or_deletions(
24772    edits: &Vec<(Range<Anchor>, String)>,
24773    snapshot: &MultiBufferSnapshot,
24774) -> bool {
24775    let mut all_insertions = true;
24776    let mut all_deletions = true;
24777
24778    for (range, new_text) in edits.iter() {
24779        let range_is_empty = range.to_offset(snapshot).is_empty();
24780        let text_is_empty = new_text.is_empty();
24781
24782        if range_is_empty != text_is_empty {
24783            if range_is_empty {
24784                all_deletions = false;
24785            } else {
24786                all_insertions = false;
24787            }
24788        } else {
24789            return false;
24790        }
24791
24792        if !all_insertions && !all_deletions {
24793            return false;
24794        }
24795    }
24796    all_insertions || all_deletions
24797}
24798
24799struct MissingEditPredictionKeybindingTooltip;
24800
24801impl Render for MissingEditPredictionKeybindingTooltip {
24802    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24803        ui::tooltip_container(cx, |container, cx| {
24804            container
24805                .flex_shrink_0()
24806                .max_w_80()
24807                .min_h(rems_from_px(124.))
24808                .justify_between()
24809                .child(
24810                    v_flex()
24811                        .flex_1()
24812                        .text_ui_sm(cx)
24813                        .child(Label::new("Conflict with Accept Keybinding"))
24814                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
24815                )
24816                .child(
24817                    h_flex()
24818                        .pb_1()
24819                        .gap_1()
24820                        .items_end()
24821                        .w_full()
24822                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
24823                            window.dispatch_action(zed_actions::OpenKeymapFile.boxed_clone(), cx)
24824                        }))
24825                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
24826                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
24827                        })),
24828                )
24829        })
24830    }
24831}
24832
24833#[derive(Debug, Clone, Copy, PartialEq)]
24834pub struct LineHighlight {
24835    pub background: Background,
24836    pub border: Option<gpui::Hsla>,
24837    pub include_gutter: bool,
24838    pub type_id: Option<TypeId>,
24839}
24840
24841struct LineManipulationResult {
24842    pub new_text: String,
24843    pub line_count_before: usize,
24844    pub line_count_after: usize,
24845}
24846
24847fn render_diff_hunk_controls(
24848    row: u32,
24849    status: &DiffHunkStatus,
24850    hunk_range: Range<Anchor>,
24851    is_created_file: bool,
24852    line_height: Pixels,
24853    editor: &Entity<Editor>,
24854    _window: &mut Window,
24855    cx: &mut App,
24856) -> AnyElement {
24857    h_flex()
24858        .h(line_height)
24859        .mr_1()
24860        .gap_1()
24861        .px_0p5()
24862        .pb_1()
24863        .border_x_1()
24864        .border_b_1()
24865        .border_color(cx.theme().colors().border_variant)
24866        .rounded_b_lg()
24867        .bg(cx.theme().colors().editor_background)
24868        .gap_1()
24869        .block_mouse_except_scroll()
24870        .shadow_md()
24871        .child(if status.has_secondary_hunk() {
24872            Button::new(("stage", row as u64), "Stage")
24873                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24874                .tooltip({
24875                    let focus_handle = editor.focus_handle(cx);
24876                    move |window, cx| {
24877                        Tooltip::for_action_in(
24878                            "Stage Hunk",
24879                            &::git::ToggleStaged,
24880                            &focus_handle,
24881                            window,
24882                            cx,
24883                        )
24884                    }
24885                })
24886                .on_click({
24887                    let editor = editor.clone();
24888                    move |_event, _window, cx| {
24889                        editor.update(cx, |editor, cx| {
24890                            editor.stage_or_unstage_diff_hunks(
24891                                true,
24892                                vec![hunk_range.start..hunk_range.start],
24893                                cx,
24894                            );
24895                        });
24896                    }
24897                })
24898        } else {
24899            Button::new(("unstage", row as u64), "Unstage")
24900                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24901                .tooltip({
24902                    let focus_handle = editor.focus_handle(cx);
24903                    move |window, cx| {
24904                        Tooltip::for_action_in(
24905                            "Unstage Hunk",
24906                            &::git::ToggleStaged,
24907                            &focus_handle,
24908                            window,
24909                            cx,
24910                        )
24911                    }
24912                })
24913                .on_click({
24914                    let editor = editor.clone();
24915                    move |_event, _window, cx| {
24916                        editor.update(cx, |editor, cx| {
24917                            editor.stage_or_unstage_diff_hunks(
24918                                false,
24919                                vec![hunk_range.start..hunk_range.start],
24920                                cx,
24921                            );
24922                        });
24923                    }
24924                })
24925        })
24926        .child(
24927            Button::new(("restore", row as u64), "Restore")
24928                .tooltip({
24929                    let focus_handle = editor.focus_handle(cx);
24930                    move |window, cx| {
24931                        Tooltip::for_action_in(
24932                            "Restore Hunk",
24933                            &::git::Restore,
24934                            &focus_handle,
24935                            window,
24936                            cx,
24937                        )
24938                    }
24939                })
24940                .on_click({
24941                    let editor = editor.clone();
24942                    move |_event, window, cx| {
24943                        editor.update(cx, |editor, cx| {
24944                            let snapshot = editor.snapshot(window, cx);
24945                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot());
24946                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
24947                        });
24948                    }
24949                })
24950                .disabled(is_created_file),
24951        )
24952        .when(
24953            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
24954            |el| {
24955                el.child(
24956                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
24957                        .shape(IconButtonShape::Square)
24958                        .icon_size(IconSize::Small)
24959                        // .disabled(!has_multiple_hunks)
24960                        .tooltip({
24961                            let focus_handle = editor.focus_handle(cx);
24962                            move |window, cx| {
24963                                Tooltip::for_action_in(
24964                                    "Next Hunk",
24965                                    &GoToHunk,
24966                                    &focus_handle,
24967                                    window,
24968                                    cx,
24969                                )
24970                            }
24971                        })
24972                        .on_click({
24973                            let editor = editor.clone();
24974                            move |_event, window, cx| {
24975                                editor.update(cx, |editor, cx| {
24976                                    let snapshot = editor.snapshot(window, cx);
24977                                    let position =
24978                                        hunk_range.end.to_point(&snapshot.buffer_snapshot());
24979                                    editor.go_to_hunk_before_or_after_position(
24980                                        &snapshot,
24981                                        position,
24982                                        Direction::Next,
24983                                        window,
24984                                        cx,
24985                                    );
24986                                    editor.expand_selected_diff_hunks(cx);
24987                                });
24988                            }
24989                        }),
24990                )
24991                .child(
24992                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
24993                        .shape(IconButtonShape::Square)
24994                        .icon_size(IconSize::Small)
24995                        // .disabled(!has_multiple_hunks)
24996                        .tooltip({
24997                            let focus_handle = editor.focus_handle(cx);
24998                            move |window, cx| {
24999                                Tooltip::for_action_in(
25000                                    "Previous Hunk",
25001                                    &GoToPreviousHunk,
25002                                    &focus_handle,
25003                                    window,
25004                                    cx,
25005                                )
25006                            }
25007                        })
25008                        .on_click({
25009                            let editor = editor.clone();
25010                            move |_event, window, cx| {
25011                                editor.update(cx, |editor, cx| {
25012                                    let snapshot = editor.snapshot(window, cx);
25013                                    let point =
25014                                        hunk_range.start.to_point(&snapshot.buffer_snapshot());
25015                                    editor.go_to_hunk_before_or_after_position(
25016                                        &snapshot,
25017                                        point,
25018                                        Direction::Prev,
25019                                        window,
25020                                        cx,
25021                                    );
25022                                    editor.expand_selected_diff_hunks(cx);
25023                                });
25024                            }
25025                        }),
25026                )
25027            },
25028        )
25029        .into_any_element()
25030}
25031
25032pub fn multibuffer_context_lines(cx: &App) -> u32 {
25033    EditorSettings::try_get(cx)
25034        .map(|settings| settings.excerpt_context_lines)
25035        .unwrap_or(2)
25036        .min(32)
25037}