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//!
   11//! All other submodules and structs are mostly concerned with holding editor data about the way it displays current buffer region(s).
   12//!
   13//! If you're looking to improve Vim mode, you should check out Vim crate that wraps Editor and overrides its behavior.
   14pub mod actions;
   15mod blink_manager;
   16mod clangd_ext;
   17pub mod code_context_menus;
   18pub mod display_map;
   19mod editor_settings;
   20mod element;
   21mod git;
   22mod highlight_matching_bracket;
   23mod hover_links;
   24pub mod hover_popover;
   25mod indent_guides;
   26mod inlays;
   27pub mod items;
   28mod jsx_tag_auto_close;
   29mod linked_editing_ranges;
   30mod lsp_colors;
   31mod lsp_ext;
   32mod mouse_context_menu;
   33pub mod movement;
   34mod persistence;
   35mod rust_analyzer_ext;
   36pub mod scroll;
   37mod selections_collection;
   38pub mod tasks;
   39
   40#[cfg(test)]
   41mod code_completion_tests;
   42#[cfg(test)]
   43mod edit_prediction_tests;
   44#[cfg(test)]
   45mod editor_tests;
   46mod signature_help;
   47#[cfg(any(test, feature = "test-support"))]
   48pub mod test;
   49
   50pub(crate) use actions::*;
   51pub use display_map::{ChunkRenderer, ChunkRendererContext, DisplayPoint, FoldPlaceholder};
   52pub use edit_prediction::Direction;
   53pub use editor_settings::{
   54    CurrentLineHighlight, DocumentColorsRenderMode, EditorSettings, HideMouseMode,
   55    ScrollBeyondLastLine, ScrollbarAxes, SearchSettings, ShowMinimap,
   56};
   57pub use element::{
   58    CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition,
   59};
   60pub use git::blame::BlameRenderer;
   61pub use hover_popover::hover_markdown_style;
   62pub use inlays::Inlay;
   63pub use items::MAX_TAB_TITLE_LEN;
   64pub use lsp::CompletionContext;
   65pub use lsp_ext::lsp_tasks;
   66pub use multi_buffer::{
   67    Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, PathKey,
   68    RowInfo, ToOffset, ToPoint,
   69};
   70pub use text::Bias;
   71
   72use ::git::{
   73    Restore,
   74    blame::{BlameEntry, ParsedCommitMessage},
   75    status::FileStatus,
   76};
   77use aho_corasick::AhoCorasick;
   78use anyhow::{Context as _, Result, anyhow};
   79use blink_manager::BlinkManager;
   80use buffer_diff::DiffHunkStatus;
   81use client::{Collaborator, ParticipantIndex, parse_zed_link};
   82use clock::ReplicaId;
   83use code_context_menus::{
   84    AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu,
   85    CompletionsMenu, ContextMenuOrigin,
   86};
   87use collections::{BTreeMap, HashMap, HashSet, VecDeque};
   88use convert_case::{Case, Casing};
   89use dap::TelemetrySpawnLocation;
   90use display_map::*;
   91use edit_prediction::{EditPredictionProvider, EditPredictionProviderHandle};
   92use editor_settings::{GoToDefinitionFallback, Minimap as MinimapSettings};
   93use element::{AcceptEditPredictionBinding, LineWithInvisibles, PositionMap, layout_line};
   94use futures::{
   95    FutureExt, StreamExt as _,
   96    future::{self, Shared, join},
   97    stream::FuturesUnordered,
   98};
   99use fuzzy::{StringMatch, StringMatchCandidate};
  100use git::blame::{GitBlame, GlobalBlameRenderer};
  101use gpui::{
  102    Action, Animation, AnimationExt, AnyElement, App, AppContext, AsyncWindowContext,
  103    AvailableSpace, Background, Bounds, ClickEvent, ClipboardEntry, ClipboardItem, Context,
  104    DispatchPhase, Edges, Entity, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent,
  105    Focusable, FontId, FontWeight, Global, HighlightStyle, Hsla, KeyContext, Modifiers,
  106    MouseButton, MouseDownEvent, PaintQuad, ParentElement, Pixels, Render, ScrollHandle,
  107    SharedString, Size, Stateful, Styled, Subscription, Task, TextStyle, TextStyleRefinement,
  108    UTF16Selection, UnderlineStyle, UniformListScrollHandle, WeakEntity, WeakFocusHandle, Window,
  109    div, point, prelude::*, pulsating_between, px, relative, size,
  110};
  111use hover_links::{HoverLink, HoveredLinkState, find_file};
  112use hover_popover::{HoverState, hide_hover};
  113use indent_guides::ActiveIndentGuidesState;
  114use inlays::{InlaySplice, inlay_hints::InlayHintRefreshReason};
  115use itertools::{Either, Itertools};
  116use language::{
  117    AutoindentMode, BlockCommentConfig, BracketMatch, BracketPair, Buffer, BufferRow,
  118    BufferSnapshot, Capability, CharClassifier, CharKind, CharScopeContext, CodeLabel, CursorShape,
  119    DiagnosticEntryRef, DiffOptions, EditPredictionsMode, EditPreview, HighlightedText, IndentKind,
  120    IndentSize, Language, OffsetRangeExt, Point, Runnable, RunnableRange, Selection, SelectionGoal,
  121    TextObject, TransactionId, TreeSitterOptions, WordsQuery,
  122    language_settings::{
  123        self, LspInsertMode, RewrapBehavior, WordsCompletionMode, all_language_settings,
  124        language_settings,
  125    },
  126    point_from_lsp, point_to_lsp, text_diff_with_options,
  127};
  128use linked_editing_ranges::refresh_linked_ranges;
  129use lsp::{
  130    CodeActionKind, CompletionItemKind, CompletionTriggerKind, InsertTextFormat, InsertTextMode,
  131    LanguageServerId,
  132};
  133use lsp_colors::LspColorData;
  134use markdown::Markdown;
  135use mouse_context_menu::MouseContextMenu;
  136use movement::TextLayoutDetails;
  137use multi_buffer::{
  138    ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow,
  139};
  140use parking_lot::Mutex;
  141use persistence::DB;
  142use project::{
  143    BreakpointWithPosition, CodeAction, Completion, CompletionDisplayOptions, CompletionIntent,
  144    CompletionResponse, CompletionSource, DisableAiSettings, DocumentHighlight, InlayHint, InlayId,
  145    InvalidationStrategy, Location, LocationLink, PrepareRenameResponse, Project, ProjectItem,
  146    ProjectPath, ProjectTransaction, TaskSourceKind,
  147    debugger::{
  148        breakpoint_store::{
  149            Breakpoint, BreakpointEditAction, BreakpointSessionState, BreakpointState,
  150            BreakpointStore, BreakpointStoreEvent,
  151        },
  152        session::{Session, SessionEvent},
  153    },
  154    git_store::GitStoreEvent,
  155    lsp_store::{
  156        CacheInlayHints, CompletionDocumentation, FormatTrigger, LspFormatTarget,
  157        OpenLspBufferHandle,
  158    },
  159    project_settings::{DiagnosticSeverity, GoToDiagnosticSeverityFilter, ProjectSettings},
  160};
  161use rand::seq::SliceRandom;
  162use rpc::{ErrorCode, ErrorExt, proto::PeerId};
  163use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager};
  164use selections_collection::{MutableSelectionsCollection, SelectionsCollection};
  165use serde::{Deserialize, Serialize};
  166use settings::{GitGutterSetting, Settings, SettingsLocation, SettingsStore, update_settings_file};
  167use smallvec::{SmallVec, smallvec};
  168use snippet::Snippet;
  169use std::{
  170    any::{Any, TypeId},
  171    borrow::Cow,
  172    cell::{OnceCell, RefCell},
  173    cmp::{self, Ordering, Reverse},
  174    iter::{self, Peekable},
  175    mem,
  176    num::NonZeroU32,
  177    ops::{Deref, DerefMut, Not, Range, RangeInclusive},
  178    path::{Path, PathBuf},
  179    rc::Rc,
  180    sync::Arc,
  181    time::{Duration, Instant},
  182};
  183use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};
  184use text::{BufferId, FromAnchor, OffsetUtf16, Rope, ToOffset as _};
  185use theme::{
  186    ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, Theme, ThemeSettings,
  187    observe_buffer_font_size_adjustment,
  188};
  189use ui::{
  190    ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName,
  191    IconSize, Indicator, Key, Tooltip, h_flex, prelude::*, scrollbars::ScrollbarAutoHide,
  192};
  193use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};
  194use workspace::{
  195    CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, OpenInTerminal, OpenTerminal,
  196    RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection, TabBarSettings, Toast,
  197    ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  198    item::{ItemBufferKind, ItemHandle, PreviewTabsSettings, SaveOptions},
  199    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  200    searchable::SearchEvent,
  201};
  202
  203use crate::{
  204    code_context_menus::CompletionsMenuSource,
  205    editor_settings::MultiCursorModifier,
  206    hover_links::{find_url, find_url_from_range},
  207    inlays::{
  208        InlineValueCache,
  209        inlay_hints::{LspInlayHintData, inlay_hint_settings},
  210    },
  211    scroll::{ScrollOffset, ScrollPixelOffset},
  212    selections_collection::resolve_selections_wrapping_blocks,
  213    signature_help::{SignatureHelpHiddenBy, SignatureHelpState},
  214};
  215
  216pub const FILE_HEADER_HEIGHT: u32 = 2;
  217pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  218const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  219const MAX_LINE_LEN: usize = 1024;
  220const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  221const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  222pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  223#[doc(hidden)]
  224pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  225pub const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  226
  227pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  228pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  229pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  230pub const FETCH_COLORS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(150);
  231
  232pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  233pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  234pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  235
  236pub type RenderDiffHunkControlsFn = Arc<
  237    dyn Fn(
  238        u32,
  239        &DiffHunkStatus,
  240        Range<Anchor>,
  241        bool,
  242        Pixels,
  243        &Entity<Editor>,
  244        &mut Window,
  245        &mut App,
  246    ) -> AnyElement,
  247>;
  248
  249enum ReportEditorEvent {
  250    Saved { auto_saved: bool },
  251    EditorOpened,
  252    Closed,
  253}
  254
  255impl ReportEditorEvent {
  256    pub fn event_type(&self) -> &'static str {
  257        match self {
  258            Self::Saved { .. } => "Editor Saved",
  259            Self::EditorOpened => "Editor Opened",
  260            Self::Closed => "Editor Closed",
  261        }
  262    }
  263}
  264
  265pub enum ActiveDebugLine {}
  266pub enum DebugStackFrameLine {}
  267enum DocumentHighlightRead {}
  268enum DocumentHighlightWrite {}
  269enum InputComposition {}
  270pub enum PendingInput {}
  271enum SelectedTextHighlight {}
  272
  273pub enum ConflictsOuter {}
  274pub enum ConflictsOurs {}
  275pub enum ConflictsTheirs {}
  276pub enum ConflictsOursMarker {}
  277pub enum ConflictsTheirsMarker {}
  278
  279#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  280pub enum Navigated {
  281    Yes,
  282    No,
  283}
  284
  285impl Navigated {
  286    pub fn from_bool(yes: bool) -> Navigated {
  287        if yes { Navigated::Yes } else { Navigated::No }
  288    }
  289}
  290
  291#[derive(Debug, Clone, PartialEq, Eq)]
  292enum DisplayDiffHunk {
  293    Folded {
  294        display_row: DisplayRow,
  295    },
  296    Unfolded {
  297        is_created_file: bool,
  298        diff_base_byte_range: Range<usize>,
  299        display_row_range: Range<DisplayRow>,
  300        multi_buffer_range: Range<Anchor>,
  301        status: DiffHunkStatus,
  302    },
  303}
  304
  305pub enum HideMouseCursorOrigin {
  306    TypingAction,
  307    MovementAction,
  308}
  309
  310pub fn init_settings(cx: &mut App) {
  311    EditorSettings::register(cx);
  312}
  313
  314pub fn init(cx: &mut App) {
  315    init_settings(cx);
  316
  317    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  318
  319    workspace::register_project_item::<Editor>(cx);
  320    workspace::FollowableViewRegistry::register::<Editor>(cx);
  321    workspace::register_serializable_item::<Editor>(cx);
  322
  323    cx.observe_new(
  324        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  325            workspace.register_action(Editor::new_file);
  326            workspace.register_action(Editor::new_file_split);
  327            workspace.register_action(Editor::new_file_vertical);
  328            workspace.register_action(Editor::new_file_horizontal);
  329            workspace.register_action(Editor::cancel_language_server_work);
  330            workspace.register_action(Editor::toggle_focus);
  331        },
  332    )
  333    .detach();
  334
  335    cx.on_action(move |_: &workspace::NewFile, cx| {
  336        let app_state = workspace::AppState::global(cx);
  337        if let Some(app_state) = app_state.upgrade() {
  338            workspace::open_new(
  339                Default::default(),
  340                app_state,
  341                cx,
  342                |workspace, window, cx| {
  343                    Editor::new_file(workspace, &Default::default(), window, cx)
  344                },
  345            )
  346            .detach();
  347        }
  348    });
  349    cx.on_action(move |_: &workspace::NewWindow, cx| {
  350        let app_state = workspace::AppState::global(cx);
  351        if let Some(app_state) = app_state.upgrade() {
  352            workspace::open_new(
  353                Default::default(),
  354                app_state,
  355                cx,
  356                |workspace, window, cx| {
  357                    cx.activate(true);
  358                    Editor::new_file(workspace, &Default::default(), window, cx)
  359                },
  360            )
  361            .detach();
  362        }
  363    });
  364}
  365
  366pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  367    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  368}
  369
  370pub trait DiagnosticRenderer {
  371    fn render_group(
  372        &self,
  373        diagnostic_group: Vec<DiagnosticEntryRef<'_, Point>>,
  374        buffer_id: BufferId,
  375        snapshot: EditorSnapshot,
  376        editor: WeakEntity<Editor>,
  377        cx: &mut App,
  378    ) -> Vec<BlockProperties<Anchor>>;
  379
  380    fn render_hover(
  381        &self,
  382        diagnostic_group: Vec<DiagnosticEntryRef<'_, Point>>,
  383        range: Range<Point>,
  384        buffer_id: BufferId,
  385        cx: &mut App,
  386    ) -> Option<Entity<markdown::Markdown>>;
  387
  388    fn open_link(
  389        &self,
  390        editor: &mut Editor,
  391        link: SharedString,
  392        window: &mut Window,
  393        cx: &mut Context<Editor>,
  394    );
  395}
  396
  397pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  398
  399impl GlobalDiagnosticRenderer {
  400    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  401        cx.try_global::<Self>().map(|g| g.0.clone())
  402    }
  403}
  404
  405impl gpui::Global for GlobalDiagnosticRenderer {}
  406pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  407    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  408}
  409
  410pub struct SearchWithinRange;
  411
  412trait InvalidationRegion {
  413    fn ranges(&self) -> &[Range<Anchor>];
  414}
  415
  416#[derive(Clone, Debug, PartialEq)]
  417pub enum SelectPhase {
  418    Begin {
  419        position: DisplayPoint,
  420        add: bool,
  421        click_count: usize,
  422    },
  423    BeginColumnar {
  424        position: DisplayPoint,
  425        reset: bool,
  426        mode: ColumnarMode,
  427        goal_column: u32,
  428    },
  429    Extend {
  430        position: DisplayPoint,
  431        click_count: usize,
  432    },
  433    Update {
  434        position: DisplayPoint,
  435        goal_column: u32,
  436        scroll_delta: gpui::Point<f32>,
  437    },
  438    End,
  439}
  440
  441#[derive(Clone, Debug, PartialEq)]
  442pub enum ColumnarMode {
  443    FromMouse,
  444    FromSelection,
  445}
  446
  447#[derive(Clone, Debug)]
  448pub enum SelectMode {
  449    Character,
  450    Word(Range<Anchor>),
  451    Line(Range<Anchor>),
  452    All,
  453}
  454
  455#[derive(Clone, PartialEq, Eq, Debug)]
  456pub enum EditorMode {
  457    SingleLine,
  458    AutoHeight {
  459        min_lines: usize,
  460        max_lines: Option<usize>,
  461    },
  462    Full {
  463        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  464        scale_ui_elements_with_buffer_font_size: bool,
  465        /// When set to `true`, the editor will render a background for the active line.
  466        show_active_line_background: bool,
  467        /// When set to `true`, the editor's height will be determined by its content.
  468        sized_by_content: bool,
  469    },
  470    Minimap {
  471        parent: WeakEntity<Editor>,
  472    },
  473}
  474
  475impl EditorMode {
  476    pub fn full() -> Self {
  477        Self::Full {
  478            scale_ui_elements_with_buffer_font_size: true,
  479            show_active_line_background: true,
  480            sized_by_content: false,
  481        }
  482    }
  483
  484    #[inline]
  485    pub fn is_full(&self) -> bool {
  486        matches!(self, Self::Full { .. })
  487    }
  488
  489    #[inline]
  490    pub fn is_single_line(&self) -> bool {
  491        matches!(self, Self::SingleLine { .. })
  492    }
  493
  494    #[inline]
  495    fn is_minimap(&self) -> bool {
  496        matches!(self, Self::Minimap { .. })
  497    }
  498}
  499
  500#[derive(Copy, Clone, Debug)]
  501pub enum SoftWrap {
  502    /// Prefer not to wrap at all.
  503    ///
  504    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  505    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  506    GitDiff,
  507    /// Prefer a single line generally, unless an overly long line is encountered.
  508    None,
  509    /// Soft wrap lines that exceed the editor width.
  510    EditorWidth,
  511    /// Soft wrap lines at the preferred line length.
  512    Column(u32),
  513    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  514    Bounded(u32),
  515}
  516
  517#[derive(Clone)]
  518pub struct EditorStyle {
  519    pub background: Hsla,
  520    pub border: Hsla,
  521    pub local_player: PlayerColor,
  522    pub text: TextStyle,
  523    pub scrollbar_width: Pixels,
  524    pub syntax: Arc<SyntaxTheme>,
  525    pub status: StatusColors,
  526    pub inlay_hints_style: HighlightStyle,
  527    pub edit_prediction_styles: EditPredictionStyles,
  528    pub unnecessary_code_fade: f32,
  529    pub show_underlines: bool,
  530}
  531
  532impl Default for EditorStyle {
  533    fn default() -> Self {
  534        Self {
  535            background: Hsla::default(),
  536            border: Hsla::default(),
  537            local_player: PlayerColor::default(),
  538            text: TextStyle::default(),
  539            scrollbar_width: Pixels::default(),
  540            syntax: Default::default(),
  541            // HACK: Status colors don't have a real default.
  542            // We should look into removing the status colors from the editor
  543            // style and retrieve them directly from the theme.
  544            status: StatusColors::dark(),
  545            inlay_hints_style: HighlightStyle::default(),
  546            edit_prediction_styles: EditPredictionStyles {
  547                insertion: HighlightStyle::default(),
  548                whitespace: HighlightStyle::default(),
  549            },
  550            unnecessary_code_fade: Default::default(),
  551            show_underlines: true,
  552        }
  553    }
  554}
  555
  556pub fn make_inlay_hints_style(cx: &mut App) -> HighlightStyle {
  557    let show_background = language_settings::language_settings(None, None, cx)
  558        .inlay_hints
  559        .show_background;
  560
  561    let mut style = cx.theme().syntax().get("hint");
  562
  563    if style.color.is_none() {
  564        style.color = Some(cx.theme().status().hint);
  565    }
  566
  567    if !show_background {
  568        style.background_color = None;
  569        return style;
  570    }
  571
  572    if style.background_color.is_none() {
  573        style.background_color = Some(cx.theme().status().hint_background);
  574    }
  575
  576    style
  577}
  578
  579pub fn make_suggestion_styles(cx: &mut App) -> EditPredictionStyles {
  580    EditPredictionStyles {
  581        insertion: HighlightStyle {
  582            color: Some(cx.theme().status().predictive),
  583            ..HighlightStyle::default()
  584        },
  585        whitespace: HighlightStyle {
  586            background_color: Some(cx.theme().status().created_background),
  587            ..HighlightStyle::default()
  588        },
  589    }
  590}
  591
  592type CompletionId = usize;
  593
  594pub(crate) enum EditDisplayMode {
  595    TabAccept,
  596    DiffPopover,
  597    Inline,
  598}
  599
  600enum EditPrediction {
  601    Edit {
  602        edits: Vec<(Range<Anchor>, String)>,
  603        edit_preview: Option<EditPreview>,
  604        display_mode: EditDisplayMode,
  605        snapshot: BufferSnapshot,
  606    },
  607    /// Move to a specific location in the active editor
  608    MoveWithin {
  609        target: Anchor,
  610        snapshot: BufferSnapshot,
  611    },
  612    /// Move to a specific location in a different editor (not the active one)
  613    MoveOutside {
  614        target: language::Anchor,
  615        snapshot: BufferSnapshot,
  616    },
  617}
  618
  619struct EditPredictionState {
  620    inlay_ids: Vec<InlayId>,
  621    completion: EditPrediction,
  622    completion_id: Option<SharedString>,
  623    invalidation_range: Option<Range<Anchor>>,
  624}
  625
  626enum EditPredictionSettings {
  627    Disabled,
  628    Enabled {
  629        show_in_menu: bool,
  630        preview_requires_modifier: bool,
  631    },
  632}
  633
  634enum EditPredictionHighlight {}
  635
  636#[derive(Debug, Clone)]
  637struct InlineDiagnostic {
  638    message: SharedString,
  639    group_id: usize,
  640    is_primary: bool,
  641    start: Point,
  642    severity: lsp::DiagnosticSeverity,
  643}
  644
  645pub enum MenuEditPredictionsPolicy {
  646    Never,
  647    ByProvider,
  648}
  649
  650pub enum EditPredictionPreview {
  651    /// Modifier is not pressed
  652    Inactive { released_too_fast: bool },
  653    /// Modifier pressed
  654    Active {
  655        since: Instant,
  656        previous_scroll_position: Option<ScrollAnchor>,
  657    },
  658}
  659
  660impl EditPredictionPreview {
  661    pub fn released_too_fast(&self) -> bool {
  662        match self {
  663            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  664            EditPredictionPreview::Active { .. } => false,
  665        }
  666    }
  667
  668    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  669        if let EditPredictionPreview::Active {
  670            previous_scroll_position,
  671            ..
  672        } = self
  673        {
  674            *previous_scroll_position = scroll_position;
  675        }
  676    }
  677}
  678
  679pub struct ContextMenuOptions {
  680    pub min_entries_visible: usize,
  681    pub max_entries_visible: usize,
  682    pub placement: Option<ContextMenuPlacement>,
  683}
  684
  685#[derive(Debug, Clone, PartialEq, Eq)]
  686pub enum ContextMenuPlacement {
  687    Above,
  688    Below,
  689}
  690
  691#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  692struct EditorActionId(usize);
  693
  694impl EditorActionId {
  695    pub fn post_inc(&mut self) -> Self {
  696        let answer = self.0;
  697
  698        *self = Self(answer + 1);
  699
  700        Self(answer)
  701    }
  702}
  703
  704// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  705// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  706
  707type BackgroundHighlight = (fn(&Theme) -> Hsla, Arc<[Range<Anchor>]>);
  708type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
  709
  710#[derive(Default)]
  711struct ScrollbarMarkerState {
  712    scrollbar_size: Size<Pixels>,
  713    dirty: bool,
  714    markers: Arc<[PaintQuad]>,
  715    pending_refresh: Option<Task<Result<()>>>,
  716}
  717
  718impl ScrollbarMarkerState {
  719    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  720        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  721    }
  722}
  723
  724#[derive(Clone, Copy, PartialEq, Eq)]
  725pub enum MinimapVisibility {
  726    Disabled,
  727    Enabled {
  728        /// The configuration currently present in the users settings.
  729        setting_configuration: bool,
  730        /// Whether to override the currently set visibility from the users setting.
  731        toggle_override: bool,
  732    },
  733}
  734
  735impl MinimapVisibility {
  736    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  737        if mode.is_full() {
  738            Self::Enabled {
  739                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  740                toggle_override: false,
  741            }
  742        } else {
  743            Self::Disabled
  744        }
  745    }
  746
  747    fn hidden(&self) -> Self {
  748        match *self {
  749            Self::Enabled {
  750                setting_configuration,
  751                ..
  752            } => Self::Enabled {
  753                setting_configuration,
  754                toggle_override: setting_configuration,
  755            },
  756            Self::Disabled => Self::Disabled,
  757        }
  758    }
  759
  760    fn disabled(&self) -> bool {
  761        matches!(*self, Self::Disabled)
  762    }
  763
  764    fn settings_visibility(&self) -> bool {
  765        match *self {
  766            Self::Enabled {
  767                setting_configuration,
  768                ..
  769            } => setting_configuration,
  770            _ => false,
  771        }
  772    }
  773
  774    fn visible(&self) -> bool {
  775        match *self {
  776            Self::Enabled {
  777                setting_configuration,
  778                toggle_override,
  779            } => setting_configuration ^ toggle_override,
  780            _ => false,
  781        }
  782    }
  783
  784    fn toggle_visibility(&self) -> Self {
  785        match *self {
  786            Self::Enabled {
  787                toggle_override,
  788                setting_configuration,
  789            } => Self::Enabled {
  790                setting_configuration,
  791                toggle_override: !toggle_override,
  792            },
  793            Self::Disabled => Self::Disabled,
  794        }
  795    }
  796}
  797
  798#[derive(Clone, Debug)]
  799struct RunnableTasks {
  800    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  801    offset: multi_buffer::Anchor,
  802    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  803    column: u32,
  804    // Values of all named captures, including those starting with '_'
  805    extra_variables: HashMap<String, String>,
  806    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  807    context_range: Range<BufferOffset>,
  808}
  809
  810impl RunnableTasks {
  811    fn resolve<'a>(
  812        &'a self,
  813        cx: &'a task::TaskContext,
  814    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  815        self.templates.iter().filter_map(|(kind, template)| {
  816            template
  817                .resolve_task(&kind.to_id_base(), cx)
  818                .map(|task| (kind.clone(), task))
  819        })
  820    }
  821}
  822
  823#[derive(Clone)]
  824pub struct ResolvedTasks {
  825    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  826    position: Anchor,
  827}
  828
  829#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  830struct BufferOffset(usize);
  831
  832/// Addons allow storing per-editor state in other crates (e.g. Vim)
  833pub trait Addon: 'static {
  834    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  835
  836    fn render_buffer_header_controls(
  837        &self,
  838        _: &ExcerptInfo,
  839        _: &Window,
  840        _: &App,
  841    ) -> Option<AnyElement> {
  842        None
  843    }
  844
  845    fn override_status_for_buffer_id(&self, _: BufferId, _: &App) -> Option<FileStatus> {
  846        None
  847    }
  848
  849    fn to_any(&self) -> &dyn std::any::Any;
  850
  851    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  852        None
  853    }
  854}
  855
  856struct ChangeLocation {
  857    current: Option<Vec<Anchor>>,
  858    original: Vec<Anchor>,
  859}
  860impl ChangeLocation {
  861    fn locations(&self) -> &[Anchor] {
  862        self.current.as_ref().unwrap_or(&self.original)
  863    }
  864}
  865
  866/// A set of caret positions, registered when the editor was edited.
  867pub struct ChangeList {
  868    changes: Vec<ChangeLocation>,
  869    /// Currently "selected" change.
  870    position: Option<usize>,
  871}
  872
  873impl ChangeList {
  874    pub fn new() -> Self {
  875        Self {
  876            changes: Vec::new(),
  877            position: None,
  878        }
  879    }
  880
  881    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  882    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  883    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  884        if self.changes.is_empty() {
  885            return None;
  886        }
  887
  888        let prev = self.position.unwrap_or(self.changes.len());
  889        let next = if direction == Direction::Prev {
  890            prev.saturating_sub(count)
  891        } else {
  892            (prev + count).min(self.changes.len() - 1)
  893        };
  894        self.position = Some(next);
  895        self.changes.get(next).map(|change| change.locations())
  896    }
  897
  898    /// Adds a new change to the list, resetting the change list position.
  899    pub fn push_to_change_list(&mut self, group: bool, new_positions: Vec<Anchor>) {
  900        self.position.take();
  901        if let Some(last) = self.changes.last_mut()
  902            && group
  903        {
  904            last.current = Some(new_positions)
  905        } else {
  906            self.changes.push(ChangeLocation {
  907                original: new_positions,
  908                current: None,
  909            });
  910        }
  911    }
  912
  913    pub fn last(&self) -> Option<&[Anchor]> {
  914        self.changes.last().map(|change| change.locations())
  915    }
  916
  917    pub fn last_before_grouping(&self) -> Option<&[Anchor]> {
  918        self.changes.last().map(|change| change.original.as_slice())
  919    }
  920
  921    pub fn invert_last_group(&mut self) {
  922        if let Some(last) = self.changes.last_mut()
  923            && let Some(current) = last.current.as_mut()
  924        {
  925            mem::swap(&mut last.original, current);
  926        }
  927    }
  928}
  929
  930#[derive(Clone)]
  931struct InlineBlamePopoverState {
  932    scroll_handle: ScrollHandle,
  933    commit_message: Option<ParsedCommitMessage>,
  934    markdown: Entity<Markdown>,
  935}
  936
  937struct InlineBlamePopover {
  938    position: gpui::Point<Pixels>,
  939    hide_task: Option<Task<()>>,
  940    popover_bounds: Option<Bounds<Pixels>>,
  941    popover_state: InlineBlamePopoverState,
  942    keyboard_grace: bool,
  943}
  944
  945enum SelectionDragState {
  946    /// State when no drag related activity is detected.
  947    None,
  948    /// State when the mouse is down on a selection that is about to be dragged.
  949    ReadyToDrag {
  950        selection: Selection<Anchor>,
  951        click_position: gpui::Point<Pixels>,
  952        mouse_down_time: Instant,
  953    },
  954    /// State when the mouse is dragging the selection in the editor.
  955    Dragging {
  956        selection: Selection<Anchor>,
  957        drop_cursor: Selection<Anchor>,
  958        hide_drop_cursor: bool,
  959    },
  960}
  961
  962enum ColumnarSelectionState {
  963    FromMouse {
  964        selection_tail: Anchor,
  965        display_point: Option<DisplayPoint>,
  966    },
  967    FromSelection {
  968        selection_tail: Anchor,
  969    },
  970}
  971
  972/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
  973/// a breakpoint on them.
  974#[derive(Clone, Copy, Debug, PartialEq, Eq)]
  975struct PhantomBreakpointIndicator {
  976    display_row: DisplayRow,
  977    /// There's a small debounce between hovering over the line and showing the indicator.
  978    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
  979    is_active: bool,
  980    collides_with_existing_breakpoint: bool,
  981}
  982
  983/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
  984///
  985/// See the [module level documentation](self) for more information.
  986pub struct Editor {
  987    focus_handle: FocusHandle,
  988    last_focused_descendant: Option<WeakFocusHandle>,
  989    /// The text buffer being edited
  990    buffer: Entity<MultiBuffer>,
  991    /// Map of how text in the buffer should be displayed.
  992    /// Handles soft wraps, folds, fake inlay text insertions, etc.
  993    pub display_map: Entity<DisplayMap>,
  994    placeholder_display_map: Option<Entity<DisplayMap>>,
  995    pub selections: SelectionsCollection,
  996    pub scroll_manager: ScrollManager,
  997    /// When inline assist editors are linked, they all render cursors because
  998    /// typing enters text into each of them, even the ones that aren't focused.
  999    pub(crate) show_cursor_when_unfocused: bool,
 1000    columnar_selection_state: Option<ColumnarSelectionState>,
 1001    add_selections_state: Option<AddSelectionsState>,
 1002    select_next_state: Option<SelectNextState>,
 1003    select_prev_state: Option<SelectNextState>,
 1004    selection_history: SelectionHistory,
 1005    defer_selection_effects: bool,
 1006    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
 1007    autoclose_regions: Vec<AutocloseRegion>,
 1008    snippet_stack: InvalidationStack<SnippetState>,
 1009    select_syntax_node_history: SelectSyntaxNodeHistory,
 1010    ime_transaction: Option<TransactionId>,
 1011    pub diagnostics_max_severity: DiagnosticSeverity,
 1012    active_diagnostics: ActiveDiagnostic,
 1013    show_inline_diagnostics: bool,
 1014    inline_diagnostics_update: Task<()>,
 1015    inline_diagnostics_enabled: bool,
 1016    diagnostics_enabled: bool,
 1017    word_completions_enabled: bool,
 1018    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
 1019    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
 1020    hard_wrap: Option<usize>,
 1021    project: Option<Entity<Project>>,
 1022    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
 1023    completion_provider: Option<Rc<dyn CompletionProvider>>,
 1024    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 1025    blink_manager: Entity<BlinkManager>,
 1026    show_cursor_names: bool,
 1027    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1028    pub show_local_selections: bool,
 1029    mode: EditorMode,
 1030    show_breadcrumbs: bool,
 1031    show_gutter: bool,
 1032    show_scrollbars: ScrollbarAxes,
 1033    minimap_visibility: MinimapVisibility,
 1034    offset_content: bool,
 1035    disable_expand_excerpt_buttons: bool,
 1036    show_line_numbers: Option<bool>,
 1037    use_relative_line_numbers: Option<bool>,
 1038    show_git_diff_gutter: Option<bool>,
 1039    show_code_actions: Option<bool>,
 1040    show_runnables: Option<bool>,
 1041    show_breakpoints: Option<bool>,
 1042    show_wrap_guides: Option<bool>,
 1043    show_indent_guides: Option<bool>,
 1044    highlight_order: usize,
 1045    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1046    background_highlights: HashMap<HighlightKey, BackgroundHighlight>,
 1047    gutter_highlights: HashMap<TypeId, GutterHighlight>,
 1048    scrollbar_marker_state: ScrollbarMarkerState,
 1049    active_indent_guides_state: ActiveIndentGuidesState,
 1050    nav_history: Option<ItemNavHistory>,
 1051    context_menu: RefCell<Option<CodeContextMenu>>,
 1052    context_menu_options: Option<ContextMenuOptions>,
 1053    mouse_context_menu: Option<MouseContextMenu>,
 1054    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1055    inline_blame_popover: Option<InlineBlamePopover>,
 1056    inline_blame_popover_show_task: Option<Task<()>>,
 1057    signature_help_state: SignatureHelpState,
 1058    auto_signature_help: Option<bool>,
 1059    find_all_references_task_sources: Vec<Anchor>,
 1060    next_completion_id: CompletionId,
 1061    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1062    code_actions_task: Option<Task<Result<()>>>,
 1063    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1064    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1065    document_highlights_task: Option<Task<()>>,
 1066    linked_editing_range_task: Option<Task<Option<()>>>,
 1067    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1068    pending_rename: Option<RenameState>,
 1069    searchable: bool,
 1070    cursor_shape: CursorShape,
 1071    current_line_highlight: Option<CurrentLineHighlight>,
 1072    collapse_matches: bool,
 1073    autoindent_mode: Option<AutoindentMode>,
 1074    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1075    input_enabled: bool,
 1076    use_modal_editing: bool,
 1077    read_only: bool,
 1078    leader_id: Option<CollaboratorId>,
 1079    remote_id: Option<ViewId>,
 1080    pub hover_state: HoverState,
 1081    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1082    gutter_hovered: bool,
 1083    hovered_link_state: Option<HoveredLinkState>,
 1084    edit_prediction_provider: Option<RegisteredEditPredictionProvider>,
 1085    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1086    active_edit_prediction: Option<EditPredictionState>,
 1087    /// Used to prevent flickering as the user types while the menu is open
 1088    stale_edit_prediction_in_menu: Option<EditPredictionState>,
 1089    edit_prediction_settings: EditPredictionSettings,
 1090    edit_predictions_hidden_for_vim_mode: bool,
 1091    show_edit_predictions_override: Option<bool>,
 1092    menu_edit_predictions_policy: MenuEditPredictionsPolicy,
 1093    edit_prediction_preview: EditPredictionPreview,
 1094    edit_prediction_indent_conflict: bool,
 1095    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1096    next_inlay_id: usize,
 1097    next_color_inlay_id: usize,
 1098    _subscriptions: Vec<Subscription>,
 1099    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1100    gutter_dimensions: GutterDimensions,
 1101    style: Option<EditorStyle>,
 1102    text_style_refinement: Option<TextStyleRefinement>,
 1103    next_editor_action_id: EditorActionId,
 1104    editor_actions: Rc<
 1105        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1106    >,
 1107    use_autoclose: bool,
 1108    use_auto_surround: bool,
 1109    auto_replace_emoji_shortcode: bool,
 1110    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1111    show_git_blame_gutter: bool,
 1112    show_git_blame_inline: bool,
 1113    show_git_blame_inline_delay_task: Option<Task<()>>,
 1114    git_blame_inline_enabled: bool,
 1115    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1116    serialize_dirty_buffers: bool,
 1117    show_selection_menu: Option<bool>,
 1118    blame: Option<Entity<GitBlame>>,
 1119    blame_subscription: Option<Subscription>,
 1120    custom_context_menu: Option<
 1121        Box<
 1122            dyn 'static
 1123                + Fn(
 1124                    &mut Self,
 1125                    DisplayPoint,
 1126                    &mut Window,
 1127                    &mut Context<Self>,
 1128                ) -> Option<Entity<ui::ContextMenu>>,
 1129        >,
 1130    >,
 1131    last_bounds: Option<Bounds<Pixels>>,
 1132    last_position_map: Option<Rc<PositionMap>>,
 1133    expect_bounds_change: Option<Bounds<Pixels>>,
 1134    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1135    tasks_update_task: Option<Task<()>>,
 1136    breakpoint_store: Option<Entity<BreakpointStore>>,
 1137    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1138    hovered_diff_hunk_row: Option<DisplayRow>,
 1139    pull_diagnostics_task: Task<()>,
 1140    in_project_search: bool,
 1141    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1142    breadcrumb_header: Option<String>,
 1143    focused_block: Option<FocusedBlock>,
 1144    next_scroll_position: NextScrollCursorCenterTopBottom,
 1145    addons: HashMap<TypeId, Box<dyn Addon>>,
 1146    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1147    load_diff_task: Option<Shared<Task<()>>>,
 1148    /// Whether we are temporarily displaying a diff other than git's
 1149    temporary_diff_override: bool,
 1150    selection_mark_mode: bool,
 1151    toggle_fold_multiple_buffers: Task<()>,
 1152    _scroll_cursor_center_top_bottom_task: Task<()>,
 1153    serialize_selections: Task<()>,
 1154    serialize_folds: Task<()>,
 1155    mouse_cursor_hidden: bool,
 1156    minimap: Option<Entity<Self>>,
 1157    hide_mouse_mode: HideMouseMode,
 1158    pub change_list: ChangeList,
 1159    inline_value_cache: InlineValueCache,
 1160    selection_drag_state: SelectionDragState,
 1161    colors: Option<LspColorData>,
 1162    post_scroll_update: Task<()>,
 1163    refresh_colors_task: Task<()>,
 1164    inlay_hints: Option<LspInlayHintData>,
 1165    folding_newlines: Task<()>,
 1166    pub lookup_key: Option<Box<dyn Any + Send + Sync>>,
 1167}
 1168
 1169fn debounce_value(debounce_ms: u64) -> Option<Duration> {
 1170    if debounce_ms > 0 {
 1171        Some(Duration::from_millis(debounce_ms))
 1172    } else {
 1173        None
 1174    }
 1175}
 1176
 1177#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1178enum NextScrollCursorCenterTopBottom {
 1179    #[default]
 1180    Center,
 1181    Top,
 1182    Bottom,
 1183}
 1184
 1185impl NextScrollCursorCenterTopBottom {
 1186    fn next(&self) -> Self {
 1187        match self {
 1188            Self::Center => Self::Top,
 1189            Self::Top => Self::Bottom,
 1190            Self::Bottom => Self::Center,
 1191        }
 1192    }
 1193}
 1194
 1195#[derive(Clone)]
 1196pub struct EditorSnapshot {
 1197    pub mode: EditorMode,
 1198    show_gutter: bool,
 1199    show_line_numbers: Option<bool>,
 1200    show_git_diff_gutter: Option<bool>,
 1201    show_code_actions: Option<bool>,
 1202    show_runnables: Option<bool>,
 1203    show_breakpoints: Option<bool>,
 1204    git_blame_gutter_max_author_length: Option<usize>,
 1205    pub display_snapshot: DisplaySnapshot,
 1206    pub placeholder_display_snapshot: Option<DisplaySnapshot>,
 1207    is_focused: bool,
 1208    scroll_anchor: ScrollAnchor,
 1209    ongoing_scroll: OngoingScroll,
 1210    current_line_highlight: CurrentLineHighlight,
 1211    gutter_hovered: bool,
 1212}
 1213
 1214#[derive(Default, Debug, Clone, Copy)]
 1215pub struct GutterDimensions {
 1216    pub left_padding: Pixels,
 1217    pub right_padding: Pixels,
 1218    pub width: Pixels,
 1219    pub margin: Pixels,
 1220    pub git_blame_entries_width: Option<Pixels>,
 1221}
 1222
 1223impl GutterDimensions {
 1224    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1225        Self {
 1226            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1227            ..Default::default()
 1228        }
 1229    }
 1230
 1231    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1232        -cx.text_system().descent(font_id, font_size)
 1233    }
 1234    /// The full width of the space taken up by the gutter.
 1235    pub fn full_width(&self) -> Pixels {
 1236        self.margin + self.width
 1237    }
 1238
 1239    /// The width of the space reserved for the fold indicators,
 1240    /// use alongside 'justify_end' and `gutter_width` to
 1241    /// right align content with the line numbers
 1242    pub fn fold_area_width(&self) -> Pixels {
 1243        self.margin + self.right_padding
 1244    }
 1245}
 1246
 1247struct CharacterDimensions {
 1248    em_width: Pixels,
 1249    em_advance: Pixels,
 1250    line_height: Pixels,
 1251}
 1252
 1253#[derive(Debug)]
 1254pub struct RemoteSelection {
 1255    pub replica_id: ReplicaId,
 1256    pub selection: Selection<Anchor>,
 1257    pub cursor_shape: CursorShape,
 1258    pub collaborator_id: CollaboratorId,
 1259    pub line_mode: bool,
 1260    pub user_name: Option<SharedString>,
 1261    pub color: PlayerColor,
 1262}
 1263
 1264#[derive(Clone, Debug)]
 1265struct SelectionHistoryEntry {
 1266    selections: Arc<[Selection<Anchor>]>,
 1267    select_next_state: Option<SelectNextState>,
 1268    select_prev_state: Option<SelectNextState>,
 1269    add_selections_state: Option<AddSelectionsState>,
 1270}
 1271
 1272#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 1273enum SelectionHistoryMode {
 1274    Normal,
 1275    Undoing,
 1276    Redoing,
 1277    Skipping,
 1278}
 1279
 1280#[derive(Clone, PartialEq, Eq, Hash)]
 1281struct HoveredCursor {
 1282    replica_id: ReplicaId,
 1283    selection_id: usize,
 1284}
 1285
 1286impl Default for SelectionHistoryMode {
 1287    fn default() -> Self {
 1288        Self::Normal
 1289    }
 1290}
 1291
 1292#[derive(Debug)]
 1293/// SelectionEffects controls the side-effects of updating the selection.
 1294///
 1295/// The default behaviour does "what you mostly want":
 1296/// - it pushes to the nav history if the cursor moved by >10 lines
 1297/// - it re-triggers completion requests
 1298/// - it scrolls to fit
 1299///
 1300/// You might want to modify these behaviours. For example when doing a "jump"
 1301/// like go to definition, we always want to add to nav history; but when scrolling
 1302/// in vim mode we never do.
 1303///
 1304/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1305/// move.
 1306#[derive(Clone)]
 1307pub struct SelectionEffects {
 1308    nav_history: Option<bool>,
 1309    completions: bool,
 1310    scroll: Option<Autoscroll>,
 1311}
 1312
 1313impl Default for SelectionEffects {
 1314    fn default() -> Self {
 1315        Self {
 1316            nav_history: None,
 1317            completions: true,
 1318            scroll: Some(Autoscroll::fit()),
 1319        }
 1320    }
 1321}
 1322impl SelectionEffects {
 1323    pub fn scroll(scroll: Autoscroll) -> Self {
 1324        Self {
 1325            scroll: Some(scroll),
 1326            ..Default::default()
 1327        }
 1328    }
 1329
 1330    pub fn no_scroll() -> Self {
 1331        Self {
 1332            scroll: None,
 1333            ..Default::default()
 1334        }
 1335    }
 1336
 1337    pub fn completions(self, completions: bool) -> Self {
 1338        Self {
 1339            completions,
 1340            ..self
 1341        }
 1342    }
 1343
 1344    pub fn nav_history(self, nav_history: bool) -> Self {
 1345        Self {
 1346            nav_history: Some(nav_history),
 1347            ..self
 1348        }
 1349    }
 1350}
 1351
 1352struct DeferredSelectionEffectsState {
 1353    changed: bool,
 1354    effects: SelectionEffects,
 1355    old_cursor_position: Anchor,
 1356    history_entry: SelectionHistoryEntry,
 1357}
 1358
 1359#[derive(Default)]
 1360struct SelectionHistory {
 1361    #[allow(clippy::type_complexity)]
 1362    selections_by_transaction:
 1363        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1364    mode: SelectionHistoryMode,
 1365    undo_stack: VecDeque<SelectionHistoryEntry>,
 1366    redo_stack: VecDeque<SelectionHistoryEntry>,
 1367}
 1368
 1369impl SelectionHistory {
 1370    #[track_caller]
 1371    fn insert_transaction(
 1372        &mut self,
 1373        transaction_id: TransactionId,
 1374        selections: Arc<[Selection<Anchor>]>,
 1375    ) {
 1376        if selections.is_empty() {
 1377            log::error!(
 1378                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1379                std::panic::Location::caller()
 1380            );
 1381            return;
 1382        }
 1383        self.selections_by_transaction
 1384            .insert(transaction_id, (selections, None));
 1385    }
 1386
 1387    #[allow(clippy::type_complexity)]
 1388    fn transaction(
 1389        &self,
 1390        transaction_id: TransactionId,
 1391    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1392        self.selections_by_transaction.get(&transaction_id)
 1393    }
 1394
 1395    #[allow(clippy::type_complexity)]
 1396    fn transaction_mut(
 1397        &mut self,
 1398        transaction_id: TransactionId,
 1399    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1400        self.selections_by_transaction.get_mut(&transaction_id)
 1401    }
 1402
 1403    fn push(&mut self, entry: SelectionHistoryEntry) {
 1404        if !entry.selections.is_empty() {
 1405            match self.mode {
 1406                SelectionHistoryMode::Normal => {
 1407                    self.push_undo(entry);
 1408                    self.redo_stack.clear();
 1409                }
 1410                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1411                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1412                SelectionHistoryMode::Skipping => {}
 1413            }
 1414        }
 1415    }
 1416
 1417    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1418        if self
 1419            .undo_stack
 1420            .back()
 1421            .is_none_or(|e| e.selections != entry.selections)
 1422        {
 1423            self.undo_stack.push_back(entry);
 1424            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1425                self.undo_stack.pop_front();
 1426            }
 1427        }
 1428    }
 1429
 1430    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1431        if self
 1432            .redo_stack
 1433            .back()
 1434            .is_none_or(|e| e.selections != entry.selections)
 1435        {
 1436            self.redo_stack.push_back(entry);
 1437            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1438                self.redo_stack.pop_front();
 1439            }
 1440        }
 1441    }
 1442}
 1443
 1444#[derive(Clone, Copy)]
 1445pub struct RowHighlightOptions {
 1446    pub autoscroll: bool,
 1447    pub include_gutter: bool,
 1448}
 1449
 1450impl Default for RowHighlightOptions {
 1451    fn default() -> Self {
 1452        Self {
 1453            autoscroll: Default::default(),
 1454            include_gutter: true,
 1455        }
 1456    }
 1457}
 1458
 1459struct RowHighlight {
 1460    index: usize,
 1461    range: Range<Anchor>,
 1462    color: Hsla,
 1463    options: RowHighlightOptions,
 1464    type_id: TypeId,
 1465}
 1466
 1467#[derive(Clone, Debug)]
 1468struct AddSelectionsState {
 1469    groups: Vec<AddSelectionsGroup>,
 1470}
 1471
 1472#[derive(Clone, Debug)]
 1473struct AddSelectionsGroup {
 1474    above: bool,
 1475    stack: Vec<usize>,
 1476}
 1477
 1478#[derive(Clone)]
 1479struct SelectNextState {
 1480    query: AhoCorasick,
 1481    wordwise: bool,
 1482    done: bool,
 1483}
 1484
 1485impl std::fmt::Debug for SelectNextState {
 1486    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1487        f.debug_struct(std::any::type_name::<Self>())
 1488            .field("wordwise", &self.wordwise)
 1489            .field("done", &self.done)
 1490            .finish()
 1491    }
 1492}
 1493
 1494#[derive(Debug)]
 1495struct AutocloseRegion {
 1496    selection_id: usize,
 1497    range: Range<Anchor>,
 1498    pair: BracketPair,
 1499}
 1500
 1501#[derive(Debug)]
 1502struct SnippetState {
 1503    ranges: Vec<Vec<Range<Anchor>>>,
 1504    active_index: usize,
 1505    choices: Vec<Option<Vec<String>>>,
 1506}
 1507
 1508#[doc(hidden)]
 1509pub struct RenameState {
 1510    pub range: Range<Anchor>,
 1511    pub old_name: Arc<str>,
 1512    pub editor: Entity<Editor>,
 1513    block_id: CustomBlockId,
 1514}
 1515
 1516struct InvalidationStack<T>(Vec<T>);
 1517
 1518struct RegisteredEditPredictionProvider {
 1519    provider: Arc<dyn EditPredictionProviderHandle>,
 1520    _subscription: Subscription,
 1521}
 1522
 1523#[derive(Debug, PartialEq, Eq)]
 1524pub struct ActiveDiagnosticGroup {
 1525    pub active_range: Range<Anchor>,
 1526    pub active_message: String,
 1527    pub group_id: usize,
 1528    pub blocks: HashSet<CustomBlockId>,
 1529}
 1530
 1531#[derive(Debug, PartialEq, Eq)]
 1532
 1533pub(crate) enum ActiveDiagnostic {
 1534    None,
 1535    All,
 1536    Group(ActiveDiagnosticGroup),
 1537}
 1538
 1539#[derive(Serialize, Deserialize, Clone, Debug)]
 1540pub struct ClipboardSelection {
 1541    /// The number of bytes in this selection.
 1542    pub len: usize,
 1543    /// Whether this was a full-line selection.
 1544    pub is_entire_line: bool,
 1545    /// The indentation of the first line when this content was originally copied.
 1546    pub first_line_indent: u32,
 1547}
 1548
 1549// selections, scroll behavior, was newest selection reversed
 1550type SelectSyntaxNodeHistoryState = (
 1551    Box<[Selection<usize>]>,
 1552    SelectSyntaxNodeScrollBehavior,
 1553    bool,
 1554);
 1555
 1556#[derive(Default)]
 1557struct SelectSyntaxNodeHistory {
 1558    stack: Vec<SelectSyntaxNodeHistoryState>,
 1559    // disable temporarily to allow changing selections without losing the stack
 1560    pub disable_clearing: bool,
 1561}
 1562
 1563impl SelectSyntaxNodeHistory {
 1564    pub fn try_clear(&mut self) {
 1565        if !self.disable_clearing {
 1566            self.stack.clear();
 1567        }
 1568    }
 1569
 1570    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1571        self.stack.push(selection);
 1572    }
 1573
 1574    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1575        self.stack.pop()
 1576    }
 1577}
 1578
 1579enum SelectSyntaxNodeScrollBehavior {
 1580    CursorTop,
 1581    FitSelection,
 1582    CursorBottom,
 1583}
 1584
 1585#[derive(Debug)]
 1586pub(crate) struct NavigationData {
 1587    cursor_anchor: Anchor,
 1588    cursor_position: Point,
 1589    scroll_anchor: ScrollAnchor,
 1590    scroll_top_row: u32,
 1591}
 1592
 1593#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1594pub enum GotoDefinitionKind {
 1595    Symbol,
 1596    Declaration,
 1597    Type,
 1598    Implementation,
 1599}
 1600
 1601pub enum FormatTarget {
 1602    Buffers(HashSet<Entity<Buffer>>),
 1603    Ranges(Vec<Range<MultiBufferPoint>>),
 1604}
 1605
 1606pub(crate) struct FocusedBlock {
 1607    id: BlockId,
 1608    focus_handle: WeakFocusHandle,
 1609}
 1610
 1611#[derive(Clone)]
 1612enum JumpData {
 1613    MultiBufferRow {
 1614        row: MultiBufferRow,
 1615        line_offset_from_top: u32,
 1616    },
 1617    MultiBufferPoint {
 1618        excerpt_id: ExcerptId,
 1619        position: Point,
 1620        anchor: text::Anchor,
 1621        line_offset_from_top: u32,
 1622    },
 1623}
 1624
 1625pub enum MultibufferSelectionMode {
 1626    First,
 1627    All,
 1628}
 1629
 1630#[derive(Clone, Copy, Debug, Default)]
 1631pub struct RewrapOptions {
 1632    pub override_language_settings: bool,
 1633    pub preserve_existing_whitespace: bool,
 1634}
 1635
 1636impl Editor {
 1637    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1638        let buffer = cx.new(|cx| Buffer::local("", cx));
 1639        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1640        Self::new(EditorMode::SingleLine, buffer, None, window, cx)
 1641    }
 1642
 1643    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1644        let buffer = cx.new(|cx| Buffer::local("", cx));
 1645        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1646        Self::new(EditorMode::full(), buffer, None, window, cx)
 1647    }
 1648
 1649    pub fn auto_height(
 1650        min_lines: usize,
 1651        max_lines: usize,
 1652        window: &mut Window,
 1653        cx: &mut Context<Self>,
 1654    ) -> Self {
 1655        let buffer = cx.new(|cx| Buffer::local("", cx));
 1656        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1657        Self::new(
 1658            EditorMode::AutoHeight {
 1659                min_lines,
 1660                max_lines: Some(max_lines),
 1661            },
 1662            buffer,
 1663            None,
 1664            window,
 1665            cx,
 1666        )
 1667    }
 1668
 1669    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1670    /// The editor grows as tall as needed to fit its content.
 1671    pub fn auto_height_unbounded(
 1672        min_lines: usize,
 1673        window: &mut Window,
 1674        cx: &mut Context<Self>,
 1675    ) -> Self {
 1676        let buffer = cx.new(|cx| Buffer::local("", cx));
 1677        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1678        Self::new(
 1679            EditorMode::AutoHeight {
 1680                min_lines,
 1681                max_lines: None,
 1682            },
 1683            buffer,
 1684            None,
 1685            window,
 1686            cx,
 1687        )
 1688    }
 1689
 1690    pub fn for_buffer(
 1691        buffer: Entity<Buffer>,
 1692        project: Option<Entity<Project>>,
 1693        window: &mut Window,
 1694        cx: &mut Context<Self>,
 1695    ) -> Self {
 1696        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1697        Self::new(EditorMode::full(), buffer, project, window, cx)
 1698    }
 1699
 1700    pub fn for_multibuffer(
 1701        buffer: Entity<MultiBuffer>,
 1702        project: Option<Entity<Project>>,
 1703        window: &mut Window,
 1704        cx: &mut Context<Self>,
 1705    ) -> Self {
 1706        Self::new(EditorMode::full(), buffer, project, window, cx)
 1707    }
 1708
 1709    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1710        let mut clone = Self::new(
 1711            self.mode.clone(),
 1712            self.buffer.clone(),
 1713            self.project.clone(),
 1714            window,
 1715            cx,
 1716        );
 1717        self.display_map.update(cx, |display_map, cx| {
 1718            let snapshot = display_map.snapshot(cx);
 1719            clone.display_map.update(cx, |display_map, cx| {
 1720                display_map.set_state(&snapshot, cx);
 1721            });
 1722        });
 1723        clone.folds_did_change(cx);
 1724        clone.selections.clone_state(&self.selections);
 1725        clone.scroll_manager.clone_state(&self.scroll_manager);
 1726        clone.searchable = self.searchable;
 1727        clone.read_only = self.read_only;
 1728        clone
 1729    }
 1730
 1731    pub fn new(
 1732        mode: EditorMode,
 1733        buffer: Entity<MultiBuffer>,
 1734        project: Option<Entity<Project>>,
 1735        window: &mut Window,
 1736        cx: &mut Context<Self>,
 1737    ) -> Self {
 1738        Editor::new_internal(mode, buffer, project, None, window, cx)
 1739    }
 1740
 1741    fn new_internal(
 1742        mode: EditorMode,
 1743        multi_buffer: Entity<MultiBuffer>,
 1744        project: Option<Entity<Project>>,
 1745        display_map: Option<Entity<DisplayMap>>,
 1746        window: &mut Window,
 1747        cx: &mut Context<Self>,
 1748    ) -> Self {
 1749        debug_assert!(
 1750            display_map.is_none() || mode.is_minimap(),
 1751            "Providing a display map for a new editor is only intended for the minimap and might have unintended side effects otherwise!"
 1752        );
 1753
 1754        let full_mode = mode.is_full();
 1755        let is_minimap = mode.is_minimap();
 1756        let diagnostics_max_severity = if full_mode {
 1757            EditorSettings::get_global(cx)
 1758                .diagnostics_max_severity
 1759                .unwrap_or(DiagnosticSeverity::Hint)
 1760        } else {
 1761            DiagnosticSeverity::Off
 1762        };
 1763        let style = window.text_style();
 1764        let font_size = style.font_size.to_pixels(window.rem_size());
 1765        let editor = cx.entity().downgrade();
 1766        let fold_placeholder = FoldPlaceholder {
 1767            constrain_width: false,
 1768            render: Arc::new(move |fold_id, fold_range, cx| {
 1769                let editor = editor.clone();
 1770                div()
 1771                    .id(fold_id)
 1772                    .bg(cx.theme().colors().ghost_element_background)
 1773                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1774                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1775                    .rounded_xs()
 1776                    .size_full()
 1777                    .cursor_pointer()
 1778                    .child("⋯")
 1779                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1780                    .on_click(move |_, _window, cx| {
 1781                        editor
 1782                            .update(cx, |editor, cx| {
 1783                                editor.unfold_ranges(
 1784                                    &[fold_range.start..fold_range.end],
 1785                                    true,
 1786                                    false,
 1787                                    cx,
 1788                                );
 1789                                cx.stop_propagation();
 1790                            })
 1791                            .ok();
 1792                    })
 1793                    .into_any()
 1794            }),
 1795            merge_adjacent: true,
 1796            ..FoldPlaceholder::default()
 1797        };
 1798        let display_map = display_map.unwrap_or_else(|| {
 1799            cx.new(|cx| {
 1800                DisplayMap::new(
 1801                    multi_buffer.clone(),
 1802                    style.font(),
 1803                    font_size,
 1804                    None,
 1805                    FILE_HEADER_HEIGHT,
 1806                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1807                    fold_placeholder,
 1808                    diagnostics_max_severity,
 1809                    cx,
 1810                )
 1811            })
 1812        });
 1813
 1814        let selections = SelectionsCollection::new(display_map.clone(), multi_buffer.clone());
 1815
 1816        let blink_manager = cx.new(|cx| {
 1817            let mut blink_manager = BlinkManager::new(CURSOR_BLINK_INTERVAL, cx);
 1818            if is_minimap {
 1819                blink_manager.disable(cx);
 1820            }
 1821            blink_manager
 1822        });
 1823
 1824        let soft_wrap_mode_override =
 1825            matches!(mode, EditorMode::SingleLine).then(|| language_settings::SoftWrap::None);
 1826
 1827        let mut project_subscriptions = Vec::new();
 1828        if full_mode && let Some(project) = project.as_ref() {
 1829            project_subscriptions.push(cx.subscribe_in(
 1830                project,
 1831                window,
 1832                |editor, _, event, window, cx| match event {
 1833                    project::Event::RefreshCodeLens => {
 1834                        // we always query lens with actions, without storing them, always refreshing them
 1835                    }
 1836                    project::Event::RefreshInlayHints(server_id) => {
 1837                        editor.refresh_inlay_hints(
 1838                            InlayHintRefreshReason::RefreshRequested(*server_id),
 1839                            cx,
 1840                        );
 1841                    }
 1842                    project::Event::LanguageServerRemoved(..) => {
 1843                        if editor.tasks_update_task.is_none() {
 1844                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1845                        }
 1846                        editor.registered_buffers.clear();
 1847                        editor.register_visible_buffers(cx);
 1848                    }
 1849                    project::Event::LanguageServerAdded(..) => {
 1850                        if editor.tasks_update_task.is_none() {
 1851                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1852                        }
 1853                    }
 1854                    project::Event::SnippetEdit(id, snippet_edits) => {
 1855                        if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1856                            let focus_handle = editor.focus_handle(cx);
 1857                            if focus_handle.is_focused(window) {
 1858                                let snapshot = buffer.read(cx).snapshot();
 1859                                for (range, snippet) in snippet_edits {
 1860                                    let editor_range =
 1861                                        language::range_from_lsp(*range).to_offset(&snapshot);
 1862                                    editor
 1863                                        .insert_snippet(
 1864                                            &[editor_range],
 1865                                            snippet.clone(),
 1866                                            window,
 1867                                            cx,
 1868                                        )
 1869                                        .ok();
 1870                                }
 1871                            }
 1872                        }
 1873                    }
 1874                    project::Event::LanguageServerBufferRegistered { buffer_id, .. } => {
 1875                        let buffer_id = *buffer_id;
 1876                        if editor.buffer().read(cx).buffer(buffer_id).is_some() {
 1877                            editor.register_buffer(buffer_id, cx);
 1878                            editor.update_lsp_data(Some(buffer_id), window, cx);
 1879                            editor.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
 1880                            refresh_linked_ranges(editor, window, cx);
 1881                            editor.refresh_code_actions(window, cx);
 1882                            editor.refresh_document_highlights(cx);
 1883                        }
 1884                    }
 1885
 1886                    project::Event::EntryRenamed(transaction) => {
 1887                        let Some(workspace) = editor.workspace() else {
 1888                            return;
 1889                        };
 1890                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 1891                        else {
 1892                            return;
 1893                        };
 1894                        if active_editor.entity_id() == cx.entity_id() {
 1895                            let edited_buffers_already_open = {
 1896                                let other_editors: Vec<Entity<Editor>> = workspace
 1897                                    .read(cx)
 1898                                    .panes()
 1899                                    .iter()
 1900                                    .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
 1901                                    .filter(|editor| editor.entity_id() != cx.entity_id())
 1902                                    .collect();
 1903
 1904                                transaction.0.keys().all(|buffer| {
 1905                                    other_editors.iter().any(|editor| {
 1906                                        let multi_buffer = editor.read(cx).buffer();
 1907                                        multi_buffer.read(cx).is_singleton()
 1908                                            && multi_buffer.read(cx).as_singleton().map_or(
 1909                                                false,
 1910                                                |singleton| {
 1911                                                    singleton.entity_id() == buffer.entity_id()
 1912                                                },
 1913                                            )
 1914                                    })
 1915                                })
 1916                            };
 1917
 1918                            if !edited_buffers_already_open {
 1919                                let workspace = workspace.downgrade();
 1920                                let transaction = transaction.clone();
 1921                                cx.defer_in(window, move |_, window, cx| {
 1922                                    cx.spawn_in(window, async move |editor, cx| {
 1923                                        Self::open_project_transaction(
 1924                                            &editor,
 1925                                            workspace,
 1926                                            transaction,
 1927                                            "Rename".to_string(),
 1928                                            cx,
 1929                                        )
 1930                                        .await
 1931                                        .ok()
 1932                                    })
 1933                                    .detach();
 1934                                });
 1935                            }
 1936                        }
 1937                    }
 1938
 1939                    _ => {}
 1940                },
 1941            ));
 1942            if let Some(task_inventory) = project
 1943                .read(cx)
 1944                .task_store()
 1945                .read(cx)
 1946                .task_inventory()
 1947                .cloned()
 1948            {
 1949                project_subscriptions.push(cx.observe_in(
 1950                    &task_inventory,
 1951                    window,
 1952                    |editor, _, window, cx| {
 1953                        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1954                    },
 1955                ));
 1956            };
 1957
 1958            project_subscriptions.push(cx.subscribe_in(
 1959                &project.read(cx).breakpoint_store(),
 1960                window,
 1961                |editor, _, event, window, cx| match event {
 1962                    BreakpointStoreEvent::ClearDebugLines => {
 1963                        editor.clear_row_highlights::<ActiveDebugLine>();
 1964                        editor.refresh_inline_values(cx);
 1965                    }
 1966                    BreakpointStoreEvent::SetDebugLine => {
 1967                        if editor.go_to_active_debug_line(window, cx) {
 1968                            cx.stop_propagation();
 1969                        }
 1970
 1971                        editor.refresh_inline_values(cx);
 1972                    }
 1973                    _ => {}
 1974                },
 1975            ));
 1976            let git_store = project.read(cx).git_store().clone();
 1977            let project = project.clone();
 1978            project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 1979                if let GitStoreEvent::RepositoryAdded = event {
 1980                    this.load_diff_task = Some(
 1981                        update_uncommitted_diff_for_buffer(
 1982                            cx.entity(),
 1983                            &project,
 1984                            this.buffer.read(cx).all_buffers(),
 1985                            this.buffer.clone(),
 1986                            cx,
 1987                        )
 1988                        .shared(),
 1989                    );
 1990                }
 1991            }));
 1992        }
 1993
 1994        let buffer_snapshot = multi_buffer.read(cx).snapshot(cx);
 1995
 1996        let inlay_hint_settings =
 1997            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 1998        let focus_handle = cx.focus_handle();
 1999        if !is_minimap {
 2000            cx.on_focus(&focus_handle, window, Self::handle_focus)
 2001                .detach();
 2002            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 2003                .detach();
 2004            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 2005                .detach();
 2006            cx.on_blur(&focus_handle, window, Self::handle_blur)
 2007                .detach();
 2008            cx.observe_pending_input(window, Self::observe_pending_input)
 2009                .detach();
 2010        }
 2011
 2012        let show_indent_guides =
 2013            if matches!(mode, EditorMode::SingleLine | EditorMode::Minimap { .. }) {
 2014                Some(false)
 2015            } else {
 2016                None
 2017            };
 2018
 2019        let breakpoint_store = match (&mode, project.as_ref()) {
 2020            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 2021            _ => None,
 2022        };
 2023
 2024        let mut code_action_providers = Vec::new();
 2025        let mut load_uncommitted_diff = None;
 2026        if let Some(project) = project.clone() {
 2027            load_uncommitted_diff = Some(
 2028                update_uncommitted_diff_for_buffer(
 2029                    cx.entity(),
 2030                    &project,
 2031                    multi_buffer.read(cx).all_buffers(),
 2032                    multi_buffer.clone(),
 2033                    cx,
 2034                )
 2035                .shared(),
 2036            );
 2037            code_action_providers.push(Rc::new(project) as Rc<_>);
 2038        }
 2039
 2040        let mut editor = Self {
 2041            focus_handle,
 2042            show_cursor_when_unfocused: false,
 2043            last_focused_descendant: None,
 2044            buffer: multi_buffer.clone(),
 2045            display_map: display_map.clone(),
 2046            placeholder_display_map: None,
 2047            selections,
 2048            scroll_manager: ScrollManager::new(cx),
 2049            columnar_selection_state: None,
 2050            add_selections_state: None,
 2051            select_next_state: None,
 2052            select_prev_state: None,
 2053            selection_history: SelectionHistory::default(),
 2054            defer_selection_effects: false,
 2055            deferred_selection_effects_state: None,
 2056            autoclose_regions: Vec::new(),
 2057            snippet_stack: InvalidationStack::default(),
 2058            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2059            ime_transaction: None,
 2060            active_diagnostics: ActiveDiagnostic::None,
 2061            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2062            inline_diagnostics_update: Task::ready(()),
 2063            inline_diagnostics: Vec::new(),
 2064            soft_wrap_mode_override,
 2065            diagnostics_max_severity,
 2066            hard_wrap: None,
 2067            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2068            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2069            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2070            project,
 2071            blink_manager: blink_manager.clone(),
 2072            show_local_selections: true,
 2073            show_scrollbars: ScrollbarAxes {
 2074                horizontal: full_mode,
 2075                vertical: full_mode,
 2076            },
 2077            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2078            offset_content: !matches!(mode, EditorMode::SingleLine),
 2079            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2080            show_gutter: full_mode,
 2081            show_line_numbers: (!full_mode).then_some(false),
 2082            use_relative_line_numbers: None,
 2083            disable_expand_excerpt_buttons: !full_mode,
 2084            show_git_diff_gutter: None,
 2085            show_code_actions: None,
 2086            show_runnables: None,
 2087            show_breakpoints: None,
 2088            show_wrap_guides: None,
 2089            show_indent_guides,
 2090            highlight_order: 0,
 2091            highlighted_rows: HashMap::default(),
 2092            background_highlights: HashMap::default(),
 2093            gutter_highlights: HashMap::default(),
 2094            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2095            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2096            nav_history: None,
 2097            context_menu: RefCell::new(None),
 2098            context_menu_options: None,
 2099            mouse_context_menu: None,
 2100            completion_tasks: Vec::new(),
 2101            inline_blame_popover: None,
 2102            inline_blame_popover_show_task: None,
 2103            signature_help_state: SignatureHelpState::default(),
 2104            auto_signature_help: None,
 2105            find_all_references_task_sources: Vec::new(),
 2106            next_completion_id: 0,
 2107            next_inlay_id: 0,
 2108            code_action_providers,
 2109            available_code_actions: None,
 2110            code_actions_task: None,
 2111            quick_selection_highlight_task: None,
 2112            debounced_selection_highlight_task: None,
 2113            document_highlights_task: None,
 2114            linked_editing_range_task: None,
 2115            pending_rename: None,
 2116            searchable: !is_minimap,
 2117            cursor_shape: EditorSettings::get_global(cx)
 2118                .cursor_shape
 2119                .unwrap_or_default(),
 2120            current_line_highlight: None,
 2121            autoindent_mode: Some(AutoindentMode::EachLine),
 2122            collapse_matches: false,
 2123            workspace: None,
 2124            input_enabled: !is_minimap,
 2125            use_modal_editing: full_mode,
 2126            read_only: is_minimap,
 2127            use_autoclose: true,
 2128            use_auto_surround: true,
 2129            auto_replace_emoji_shortcode: false,
 2130            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2131            leader_id: None,
 2132            remote_id: None,
 2133            hover_state: HoverState::default(),
 2134            pending_mouse_down: None,
 2135            hovered_link_state: None,
 2136            edit_prediction_provider: None,
 2137            active_edit_prediction: None,
 2138            stale_edit_prediction_in_menu: None,
 2139            edit_prediction_preview: EditPredictionPreview::Inactive {
 2140                released_too_fast: false,
 2141            },
 2142            inline_diagnostics_enabled: full_mode,
 2143            diagnostics_enabled: full_mode,
 2144            word_completions_enabled: full_mode,
 2145            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2146            gutter_hovered: false,
 2147            pixel_position_of_newest_cursor: None,
 2148            last_bounds: None,
 2149            last_position_map: None,
 2150            expect_bounds_change: None,
 2151            gutter_dimensions: GutterDimensions::default(),
 2152            style: None,
 2153            show_cursor_names: false,
 2154            hovered_cursors: HashMap::default(),
 2155            next_editor_action_id: EditorActionId::default(),
 2156            editor_actions: Rc::default(),
 2157            edit_predictions_hidden_for_vim_mode: false,
 2158            show_edit_predictions_override: None,
 2159            menu_edit_predictions_policy: MenuEditPredictionsPolicy::ByProvider,
 2160            edit_prediction_settings: EditPredictionSettings::Disabled,
 2161            edit_prediction_indent_conflict: false,
 2162            edit_prediction_requires_modifier_in_indent_conflict: true,
 2163            custom_context_menu: None,
 2164            show_git_blame_gutter: false,
 2165            show_git_blame_inline: false,
 2166            show_selection_menu: None,
 2167            show_git_blame_inline_delay_task: None,
 2168            git_blame_inline_enabled: full_mode
 2169                && ProjectSettings::get_global(cx).git.inline_blame.enabled,
 2170            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2171            serialize_dirty_buffers: !is_minimap
 2172                && ProjectSettings::get_global(cx)
 2173                    .session
 2174                    .restore_unsaved_buffers,
 2175            blame: None,
 2176            blame_subscription: None,
 2177            tasks: BTreeMap::default(),
 2178
 2179            breakpoint_store,
 2180            gutter_breakpoint_indicator: (None, None),
 2181            hovered_diff_hunk_row: None,
 2182            _subscriptions: (!is_minimap)
 2183                .then(|| {
 2184                    vec![
 2185                        cx.observe(&multi_buffer, Self::on_buffer_changed),
 2186                        cx.subscribe_in(&multi_buffer, window, Self::on_buffer_event),
 2187                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2188                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2189                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2190                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2191                        cx.observe_window_activation(window, |editor, window, cx| {
 2192                            let active = window.is_window_active();
 2193                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2194                                if active {
 2195                                    blink_manager.enable(cx);
 2196                                } else {
 2197                                    blink_manager.disable(cx);
 2198                                }
 2199                            });
 2200                            if active {
 2201                                editor.show_mouse_cursor(cx);
 2202                            }
 2203                        }),
 2204                    ]
 2205                })
 2206                .unwrap_or_default(),
 2207            tasks_update_task: None,
 2208            pull_diagnostics_task: Task::ready(()),
 2209            colors: None,
 2210            refresh_colors_task: Task::ready(()),
 2211            inlay_hints: None,
 2212            next_color_inlay_id: 0,
 2213            post_scroll_update: Task::ready(()),
 2214            linked_edit_ranges: Default::default(),
 2215            in_project_search: false,
 2216            previous_search_ranges: None,
 2217            breadcrumb_header: None,
 2218            focused_block: None,
 2219            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2220            addons: HashMap::default(),
 2221            registered_buffers: HashMap::default(),
 2222            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2223            selection_mark_mode: false,
 2224            toggle_fold_multiple_buffers: Task::ready(()),
 2225            serialize_selections: Task::ready(()),
 2226            serialize_folds: Task::ready(()),
 2227            text_style_refinement: None,
 2228            load_diff_task: load_uncommitted_diff,
 2229            temporary_diff_override: false,
 2230            mouse_cursor_hidden: false,
 2231            minimap: None,
 2232            hide_mouse_mode: EditorSettings::get_global(cx)
 2233                .hide_mouse
 2234                .unwrap_or_default(),
 2235            change_list: ChangeList::new(),
 2236            mode,
 2237            selection_drag_state: SelectionDragState::None,
 2238            folding_newlines: Task::ready(()),
 2239            lookup_key: None,
 2240        };
 2241
 2242        if is_minimap {
 2243            return editor;
 2244        }
 2245
 2246        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2247            editor
 2248                ._subscriptions
 2249                .push(cx.observe(breakpoints, |_, _, cx| {
 2250                    cx.notify();
 2251                }));
 2252        }
 2253        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2254        editor._subscriptions.extend(project_subscriptions);
 2255
 2256        editor._subscriptions.push(cx.subscribe_in(
 2257            &cx.entity(),
 2258            window,
 2259            |editor, _, e: &EditorEvent, window, cx| match e {
 2260                EditorEvent::ScrollPositionChanged { local, .. } => {
 2261                    if *local {
 2262                        let new_anchor = editor.scroll_manager.anchor();
 2263                        let snapshot = editor.snapshot(window, cx);
 2264                        editor.update_restoration_data(cx, move |data| {
 2265                            data.scroll_position = (
 2266                                new_anchor.top_row(snapshot.buffer_snapshot()),
 2267                                new_anchor.offset,
 2268                            );
 2269                        });
 2270                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2271                        editor.inline_blame_popover.take();
 2272                    }
 2273                }
 2274                EditorEvent::Edited { .. } => {
 2275                    if !vim_enabled(cx) {
 2276                        let display_map = editor.display_snapshot(cx);
 2277                        let selections = editor.selections.all_adjusted_display(&display_map);
 2278                        let pop_state = editor
 2279                            .change_list
 2280                            .last()
 2281                            .map(|previous| {
 2282                                previous.len() == selections.len()
 2283                                    && previous.iter().enumerate().all(|(ix, p)| {
 2284                                        p.to_display_point(&display_map).row()
 2285                                            == selections[ix].head().row()
 2286                                    })
 2287                            })
 2288                            .unwrap_or(false);
 2289                        let new_positions = selections
 2290                            .into_iter()
 2291                            .map(|s| display_map.display_point_to_anchor(s.head(), Bias::Left))
 2292                            .collect();
 2293                        editor
 2294                            .change_list
 2295                            .push_to_change_list(pop_state, new_positions);
 2296                    }
 2297                }
 2298                _ => (),
 2299            },
 2300        ));
 2301
 2302        if let Some(dap_store) = editor
 2303            .project
 2304            .as_ref()
 2305            .map(|project| project.read(cx).dap_store())
 2306        {
 2307            let weak_editor = cx.weak_entity();
 2308
 2309            editor
 2310                ._subscriptions
 2311                .push(
 2312                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2313                        let session_entity = cx.entity();
 2314                        weak_editor
 2315                            .update(cx, |editor, cx| {
 2316                                editor._subscriptions.push(
 2317                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2318                                );
 2319                            })
 2320                            .ok();
 2321                    }),
 2322                );
 2323
 2324            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2325                editor
 2326                    ._subscriptions
 2327                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2328            }
 2329        }
 2330
 2331        // skip adding the initial selection to selection history
 2332        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2333        editor.end_selection(window, cx);
 2334        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2335
 2336        editor.scroll_manager.show_scrollbars(window, cx);
 2337        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &multi_buffer, cx);
 2338
 2339        if full_mode {
 2340            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2341            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2342
 2343            if editor.git_blame_inline_enabled {
 2344                editor.start_git_blame_inline(false, window, cx);
 2345            }
 2346
 2347            editor.go_to_active_debug_line(window, cx);
 2348
 2349            editor.minimap =
 2350                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2351            editor.colors = Some(LspColorData::new(cx));
 2352            editor.inlay_hints = Some(LspInlayHintData::new(inlay_hint_settings));
 2353
 2354            if let Some(buffer) = multi_buffer.read(cx).as_singleton() {
 2355                editor.register_buffer(buffer.read(cx).remote_id(), cx);
 2356            }
 2357            editor.update_lsp_data(None, window, cx);
 2358            editor.report_editor_event(ReportEditorEvent::EditorOpened, None, cx);
 2359        }
 2360
 2361        editor
 2362    }
 2363
 2364    pub fn display_snapshot(&self, cx: &mut App) -> DisplaySnapshot {
 2365        self.selections.display_map(cx)
 2366    }
 2367
 2368    pub fn deploy_mouse_context_menu(
 2369        &mut self,
 2370        position: gpui::Point<Pixels>,
 2371        context_menu: Entity<ContextMenu>,
 2372        window: &mut Window,
 2373        cx: &mut Context<Self>,
 2374    ) {
 2375        self.mouse_context_menu = Some(MouseContextMenu::new(
 2376            self,
 2377            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2378            context_menu,
 2379            window,
 2380            cx,
 2381        ));
 2382    }
 2383
 2384    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2385        self.mouse_context_menu
 2386            .as_ref()
 2387            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2388    }
 2389
 2390    pub fn is_range_selected(&mut self, range: &Range<Anchor>, cx: &mut Context<Self>) -> bool {
 2391        if self
 2392            .selections
 2393            .pending_anchor()
 2394            .is_some_and(|pending_selection| {
 2395                let snapshot = self.buffer().read(cx).snapshot(cx);
 2396                pending_selection.range().includes(range, &snapshot)
 2397            })
 2398        {
 2399            return true;
 2400        }
 2401
 2402        self.selections
 2403            .disjoint_in_range::<usize>(range.clone(), &self.display_snapshot(cx))
 2404            .into_iter()
 2405            .any(|selection| {
 2406                // This is needed to cover a corner case, if we just check for an existing
 2407                // selection in the fold range, having a cursor at the start of the fold
 2408                // marks it as selected. Non-empty selections don't cause this.
 2409                let length = selection.end - selection.start;
 2410                length > 0
 2411            })
 2412    }
 2413
 2414    pub fn key_context(&self, window: &mut Window, cx: &mut App) -> KeyContext {
 2415        self.key_context_internal(self.has_active_edit_prediction(), window, cx)
 2416    }
 2417
 2418    fn key_context_internal(
 2419        &self,
 2420        has_active_edit_prediction: bool,
 2421        window: &mut Window,
 2422        cx: &mut App,
 2423    ) -> KeyContext {
 2424        let mut key_context = KeyContext::new_with_defaults();
 2425        key_context.add("Editor");
 2426        let mode = match self.mode {
 2427            EditorMode::SingleLine => "single_line",
 2428            EditorMode::AutoHeight { .. } => "auto_height",
 2429            EditorMode::Minimap { .. } => "minimap",
 2430            EditorMode::Full { .. } => "full",
 2431        };
 2432
 2433        if EditorSettings::jupyter_enabled(cx) {
 2434            key_context.add("jupyter");
 2435        }
 2436
 2437        key_context.set("mode", mode);
 2438        if self.pending_rename.is_some() {
 2439            key_context.add("renaming");
 2440        }
 2441
 2442        if !self.snippet_stack.is_empty() {
 2443            key_context.add("in_snippet");
 2444        }
 2445
 2446        match self.context_menu.borrow().as_ref() {
 2447            Some(CodeContextMenu::Completions(menu)) => {
 2448                if menu.visible() {
 2449                    key_context.add("menu");
 2450                    key_context.add("showing_completions");
 2451                }
 2452            }
 2453            Some(CodeContextMenu::CodeActions(menu)) => {
 2454                if menu.visible() {
 2455                    key_context.add("menu");
 2456                    key_context.add("showing_code_actions")
 2457                }
 2458            }
 2459            None => {}
 2460        }
 2461
 2462        if self.signature_help_state.has_multiple_signatures() {
 2463            key_context.add("showing_signature_help");
 2464        }
 2465
 2466        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2467        if !self.focus_handle(cx).contains_focused(window, cx)
 2468            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2469        {
 2470            for addon in self.addons.values() {
 2471                addon.extend_key_context(&mut key_context, cx)
 2472            }
 2473        }
 2474
 2475        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2476            if let Some(extension) = singleton_buffer.read(cx).file().and_then(|file| {
 2477                Some(
 2478                    file.full_path(cx)
 2479                        .extension()?
 2480                        .to_string_lossy()
 2481                        .into_owned(),
 2482                )
 2483            }) {
 2484                key_context.set("extension", extension);
 2485            }
 2486        } else {
 2487            key_context.add("multibuffer");
 2488        }
 2489
 2490        if has_active_edit_prediction {
 2491            if self.edit_prediction_in_conflict() {
 2492                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2493            } else {
 2494                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2495                key_context.add("copilot_suggestion");
 2496            }
 2497        }
 2498
 2499        if self.selection_mark_mode {
 2500            key_context.add("selection_mode");
 2501        }
 2502
 2503        let disjoint = self.selections.disjoint_anchors();
 2504        let snapshot = self.snapshot(window, cx);
 2505        let snapshot = snapshot.buffer_snapshot();
 2506        if self.mode == EditorMode::SingleLine
 2507            && let [selection] = disjoint
 2508            && selection.start == selection.end
 2509            && selection.end.to_offset(snapshot) == snapshot.len()
 2510        {
 2511            key_context.add("end_of_input");
 2512        }
 2513
 2514        key_context
 2515    }
 2516
 2517    pub fn last_bounds(&self) -> Option<&Bounds<Pixels>> {
 2518        self.last_bounds.as_ref()
 2519    }
 2520
 2521    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2522        if self.mouse_cursor_hidden {
 2523            self.mouse_cursor_hidden = false;
 2524            cx.notify();
 2525        }
 2526    }
 2527
 2528    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2529        let hide_mouse_cursor = match origin {
 2530            HideMouseCursorOrigin::TypingAction => {
 2531                matches!(
 2532                    self.hide_mouse_mode,
 2533                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2534                )
 2535            }
 2536            HideMouseCursorOrigin::MovementAction => {
 2537                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2538            }
 2539        };
 2540        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2541            self.mouse_cursor_hidden = hide_mouse_cursor;
 2542            cx.notify();
 2543        }
 2544    }
 2545
 2546    pub fn edit_prediction_in_conflict(&self) -> bool {
 2547        if !self.show_edit_predictions_in_menu() {
 2548            return false;
 2549        }
 2550
 2551        let showing_completions = self
 2552            .context_menu
 2553            .borrow()
 2554            .as_ref()
 2555            .is_some_and(|context| matches!(context, CodeContextMenu::Completions(_)));
 2556
 2557        showing_completions
 2558            || self.edit_prediction_requires_modifier()
 2559            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2560            // bindings to insert tab characters.
 2561            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2562    }
 2563
 2564    pub fn accept_edit_prediction_keybind(
 2565        &self,
 2566        accept_partial: bool,
 2567        window: &mut Window,
 2568        cx: &mut App,
 2569    ) -> AcceptEditPredictionBinding {
 2570        let key_context = self.key_context_internal(true, window, cx);
 2571        let in_conflict = self.edit_prediction_in_conflict();
 2572
 2573        let bindings = if accept_partial {
 2574            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2575        } else {
 2576            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2577        };
 2578
 2579        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2580        // just the first one.
 2581        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2582            !in_conflict
 2583                || binding
 2584                    .keystrokes()
 2585                    .first()
 2586                    .is_some_and(|keystroke| keystroke.modifiers().modified())
 2587        }))
 2588    }
 2589
 2590    pub fn new_file(
 2591        workspace: &mut Workspace,
 2592        _: &workspace::NewFile,
 2593        window: &mut Window,
 2594        cx: &mut Context<Workspace>,
 2595    ) {
 2596        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2597            "Failed to create buffer",
 2598            window,
 2599            cx,
 2600            |e, _, _| match e.error_code() {
 2601                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2602                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2603                e.error_tag("required").unwrap_or("the latest version")
 2604            )),
 2605                _ => None,
 2606            },
 2607        );
 2608    }
 2609
 2610    pub fn new_in_workspace(
 2611        workspace: &mut Workspace,
 2612        window: &mut Window,
 2613        cx: &mut Context<Workspace>,
 2614    ) -> Task<Result<Entity<Editor>>> {
 2615        let project = workspace.project().clone();
 2616        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2617
 2618        cx.spawn_in(window, async move |workspace, cx| {
 2619            let buffer = create.await?;
 2620            workspace.update_in(cx, |workspace, window, cx| {
 2621                let editor =
 2622                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2623                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2624                editor
 2625            })
 2626        })
 2627    }
 2628
 2629    fn new_file_vertical(
 2630        workspace: &mut Workspace,
 2631        _: &workspace::NewFileSplitVertical,
 2632        window: &mut Window,
 2633        cx: &mut Context<Workspace>,
 2634    ) {
 2635        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2636    }
 2637
 2638    fn new_file_horizontal(
 2639        workspace: &mut Workspace,
 2640        _: &workspace::NewFileSplitHorizontal,
 2641        window: &mut Window,
 2642        cx: &mut Context<Workspace>,
 2643    ) {
 2644        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2645    }
 2646
 2647    fn new_file_split(
 2648        workspace: &mut Workspace,
 2649        action: &workspace::NewFileSplit,
 2650        window: &mut Window,
 2651        cx: &mut Context<Workspace>,
 2652    ) {
 2653        Self::new_file_in_direction(workspace, action.0, window, cx)
 2654    }
 2655
 2656    fn new_file_in_direction(
 2657        workspace: &mut Workspace,
 2658        direction: SplitDirection,
 2659        window: &mut Window,
 2660        cx: &mut Context<Workspace>,
 2661    ) {
 2662        let project = workspace.project().clone();
 2663        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2664
 2665        cx.spawn_in(window, async move |workspace, cx| {
 2666            let buffer = create.await?;
 2667            workspace.update_in(cx, move |workspace, window, cx| {
 2668                workspace.split_item(
 2669                    direction,
 2670                    Box::new(
 2671                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2672                    ),
 2673                    window,
 2674                    cx,
 2675                )
 2676            })?;
 2677            anyhow::Ok(())
 2678        })
 2679        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2680            match e.error_code() {
 2681                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2682                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2683                e.error_tag("required").unwrap_or("the latest version")
 2684            )),
 2685                _ => None,
 2686            }
 2687        });
 2688    }
 2689
 2690    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2691        self.leader_id
 2692    }
 2693
 2694    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2695        &self.buffer
 2696    }
 2697
 2698    pub fn project(&self) -> Option<&Entity<Project>> {
 2699        self.project.as_ref()
 2700    }
 2701
 2702    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2703        self.workspace.as_ref()?.0.upgrade()
 2704    }
 2705
 2706    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2707        self.buffer().read(cx).title(cx)
 2708    }
 2709
 2710    pub fn snapshot(&self, window: &Window, cx: &mut App) -> EditorSnapshot {
 2711        let git_blame_gutter_max_author_length = self
 2712            .render_git_blame_gutter(cx)
 2713            .then(|| {
 2714                if let Some(blame) = self.blame.as_ref() {
 2715                    let max_author_length =
 2716                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2717                    Some(max_author_length)
 2718                } else {
 2719                    None
 2720                }
 2721            })
 2722            .flatten();
 2723
 2724        EditorSnapshot {
 2725            mode: self.mode.clone(),
 2726            show_gutter: self.show_gutter,
 2727            show_line_numbers: self.show_line_numbers,
 2728            show_git_diff_gutter: self.show_git_diff_gutter,
 2729            show_code_actions: self.show_code_actions,
 2730            show_runnables: self.show_runnables,
 2731            show_breakpoints: self.show_breakpoints,
 2732            git_blame_gutter_max_author_length,
 2733            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2734            placeholder_display_snapshot: self
 2735                .placeholder_display_map
 2736                .as_ref()
 2737                .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx))),
 2738            scroll_anchor: self.scroll_manager.anchor(),
 2739            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2740            is_focused: self.focus_handle.is_focused(window),
 2741            current_line_highlight: self
 2742                .current_line_highlight
 2743                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2744            gutter_hovered: self.gutter_hovered,
 2745        }
 2746    }
 2747
 2748    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2749        self.buffer.read(cx).language_at(point, cx)
 2750    }
 2751
 2752    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2753        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2754    }
 2755
 2756    pub fn active_excerpt(
 2757        &self,
 2758        cx: &App,
 2759    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2760        self.buffer
 2761            .read(cx)
 2762            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2763    }
 2764
 2765    pub fn mode(&self) -> &EditorMode {
 2766        &self.mode
 2767    }
 2768
 2769    pub fn set_mode(&mut self, mode: EditorMode) {
 2770        self.mode = mode;
 2771    }
 2772
 2773    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2774        self.collaboration_hub.as_deref()
 2775    }
 2776
 2777    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2778        self.collaboration_hub = Some(hub);
 2779    }
 2780
 2781    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2782        self.in_project_search = in_project_search;
 2783    }
 2784
 2785    pub fn set_custom_context_menu(
 2786        &mut self,
 2787        f: impl 'static
 2788        + Fn(
 2789            &mut Self,
 2790            DisplayPoint,
 2791            &mut Window,
 2792            &mut Context<Self>,
 2793        ) -> Option<Entity<ui::ContextMenu>>,
 2794    ) {
 2795        self.custom_context_menu = Some(Box::new(f))
 2796    }
 2797
 2798    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2799        self.completion_provider = provider;
 2800    }
 2801
 2802    #[cfg(any(test, feature = "test-support"))]
 2803    pub fn completion_provider(&self) -> Option<Rc<dyn CompletionProvider>> {
 2804        self.completion_provider.clone()
 2805    }
 2806
 2807    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2808        self.semantics_provider.clone()
 2809    }
 2810
 2811    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2812        self.semantics_provider = provider;
 2813    }
 2814
 2815    pub fn set_edit_prediction_provider<T>(
 2816        &mut self,
 2817        provider: Option<Entity<T>>,
 2818        window: &mut Window,
 2819        cx: &mut Context<Self>,
 2820    ) where
 2821        T: EditPredictionProvider,
 2822    {
 2823        self.edit_prediction_provider = provider.map(|provider| RegisteredEditPredictionProvider {
 2824            _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2825                if this.focus_handle.is_focused(window) {
 2826                    this.update_visible_edit_prediction(window, cx);
 2827                }
 2828            }),
 2829            provider: Arc::new(provider),
 2830        });
 2831        self.update_edit_prediction_settings(cx);
 2832        self.refresh_edit_prediction(false, false, window, cx);
 2833    }
 2834
 2835    pub fn placeholder_text(&self, cx: &mut App) -> Option<String> {
 2836        self.placeholder_display_map
 2837            .as_ref()
 2838            .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx)).text())
 2839    }
 2840
 2841    pub fn set_placeholder_text(
 2842        &mut self,
 2843        placeholder_text: &str,
 2844        window: &mut Window,
 2845        cx: &mut Context<Self>,
 2846    ) {
 2847        let multibuffer = cx
 2848            .new(|cx| MultiBuffer::singleton(cx.new(|cx| Buffer::local(placeholder_text, cx)), cx));
 2849
 2850        let style = window.text_style();
 2851
 2852        self.placeholder_display_map = Some(cx.new(|cx| {
 2853            DisplayMap::new(
 2854                multibuffer,
 2855                style.font(),
 2856                style.font_size.to_pixels(window.rem_size()),
 2857                None,
 2858                FILE_HEADER_HEIGHT,
 2859                MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 2860                Default::default(),
 2861                DiagnosticSeverity::Off,
 2862                cx,
 2863            )
 2864        }));
 2865        cx.notify();
 2866    }
 2867
 2868    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2869        self.cursor_shape = cursor_shape;
 2870
 2871        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2872        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2873
 2874        cx.notify();
 2875    }
 2876
 2877    pub fn set_current_line_highlight(
 2878        &mut self,
 2879        current_line_highlight: Option<CurrentLineHighlight>,
 2880    ) {
 2881        self.current_line_highlight = current_line_highlight;
 2882    }
 2883
 2884    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2885        self.collapse_matches = collapse_matches;
 2886    }
 2887
 2888    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2889        if self.collapse_matches {
 2890            return range.start..range.start;
 2891        }
 2892        range.clone()
 2893    }
 2894
 2895    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2896        if self.display_map.read(cx).clip_at_line_ends != clip {
 2897            self.display_map
 2898                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2899        }
 2900    }
 2901
 2902    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2903        self.input_enabled = input_enabled;
 2904    }
 2905
 2906    pub fn set_edit_predictions_hidden_for_vim_mode(
 2907        &mut self,
 2908        hidden: bool,
 2909        window: &mut Window,
 2910        cx: &mut Context<Self>,
 2911    ) {
 2912        if hidden != self.edit_predictions_hidden_for_vim_mode {
 2913            self.edit_predictions_hidden_for_vim_mode = hidden;
 2914            if hidden {
 2915                self.update_visible_edit_prediction(window, cx);
 2916            } else {
 2917                self.refresh_edit_prediction(true, false, window, cx);
 2918            }
 2919        }
 2920    }
 2921
 2922    pub fn set_menu_edit_predictions_policy(&mut self, value: MenuEditPredictionsPolicy) {
 2923        self.menu_edit_predictions_policy = value;
 2924    }
 2925
 2926    pub fn set_autoindent(&mut self, autoindent: bool) {
 2927        if autoindent {
 2928            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2929        } else {
 2930            self.autoindent_mode = None;
 2931        }
 2932    }
 2933
 2934    pub fn read_only(&self, cx: &App) -> bool {
 2935        self.read_only || self.buffer.read(cx).read_only()
 2936    }
 2937
 2938    pub fn set_read_only(&mut self, read_only: bool) {
 2939        self.read_only = read_only;
 2940    }
 2941
 2942    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2943        self.use_autoclose = autoclose;
 2944    }
 2945
 2946    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2947        self.use_auto_surround = auto_surround;
 2948    }
 2949
 2950    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2951        self.auto_replace_emoji_shortcode = auto_replace;
 2952    }
 2953
 2954    pub fn toggle_edit_predictions(
 2955        &mut self,
 2956        _: &ToggleEditPrediction,
 2957        window: &mut Window,
 2958        cx: &mut Context<Self>,
 2959    ) {
 2960        if self.show_edit_predictions_override.is_some() {
 2961            self.set_show_edit_predictions(None, window, cx);
 2962        } else {
 2963            let show_edit_predictions = !self.edit_predictions_enabled();
 2964            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2965        }
 2966    }
 2967
 2968    pub fn set_show_edit_predictions(
 2969        &mut self,
 2970        show_edit_predictions: Option<bool>,
 2971        window: &mut Window,
 2972        cx: &mut Context<Self>,
 2973    ) {
 2974        self.show_edit_predictions_override = show_edit_predictions;
 2975        self.update_edit_prediction_settings(cx);
 2976
 2977        if let Some(false) = show_edit_predictions {
 2978            self.discard_edit_prediction(false, cx);
 2979        } else {
 2980            self.refresh_edit_prediction(false, true, window, cx);
 2981        }
 2982    }
 2983
 2984    fn edit_predictions_disabled_in_scope(
 2985        &self,
 2986        buffer: &Entity<Buffer>,
 2987        buffer_position: language::Anchor,
 2988        cx: &App,
 2989    ) -> bool {
 2990        let snapshot = buffer.read(cx).snapshot();
 2991        let settings = snapshot.settings_at(buffer_position, cx);
 2992
 2993        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 2994            return false;
 2995        };
 2996
 2997        scope.override_name().is_some_and(|scope_name| {
 2998            settings
 2999                .edit_predictions_disabled_in
 3000                .iter()
 3001                .any(|s| s == scope_name)
 3002        })
 3003    }
 3004
 3005    pub fn set_use_modal_editing(&mut self, to: bool) {
 3006        self.use_modal_editing = to;
 3007    }
 3008
 3009    pub fn use_modal_editing(&self) -> bool {
 3010        self.use_modal_editing
 3011    }
 3012
 3013    fn selections_did_change(
 3014        &mut self,
 3015        local: bool,
 3016        old_cursor_position: &Anchor,
 3017        effects: SelectionEffects,
 3018        window: &mut Window,
 3019        cx: &mut Context<Self>,
 3020    ) {
 3021        window.invalidate_character_coordinates();
 3022
 3023        // Copy selections to primary selection buffer
 3024        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 3025        if local {
 3026            let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 3027            let buffer_handle = self.buffer.read(cx).read(cx);
 3028
 3029            let mut text = String::new();
 3030            for (index, selection) in selections.iter().enumerate() {
 3031                let text_for_selection = buffer_handle
 3032                    .text_for_range(selection.start..selection.end)
 3033                    .collect::<String>();
 3034
 3035                text.push_str(&text_for_selection);
 3036                if index != selections.len() - 1 {
 3037                    text.push('\n');
 3038                }
 3039            }
 3040
 3041            if !text.is_empty() {
 3042                cx.write_to_primary(ClipboardItem::new_string(text));
 3043            }
 3044        }
 3045
 3046        let selection_anchors = self.selections.disjoint_anchors_arc();
 3047
 3048        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 3049            self.buffer.update(cx, |buffer, cx| {
 3050                buffer.set_active_selections(
 3051                    &selection_anchors,
 3052                    self.selections.line_mode(),
 3053                    self.cursor_shape,
 3054                    cx,
 3055                )
 3056            });
 3057        }
 3058        let display_map = self
 3059            .display_map
 3060            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3061        let buffer = display_map.buffer_snapshot();
 3062        if self.selections.count() == 1 {
 3063            self.add_selections_state = None;
 3064        }
 3065        self.select_next_state = None;
 3066        self.select_prev_state = None;
 3067        self.select_syntax_node_history.try_clear();
 3068        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 3069        self.snippet_stack.invalidate(&selection_anchors, buffer);
 3070        self.take_rename(false, window, cx);
 3071
 3072        let newest_selection = self.selections.newest_anchor();
 3073        let new_cursor_position = newest_selection.head();
 3074        let selection_start = newest_selection.start;
 3075
 3076        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 3077            self.push_to_nav_history(
 3078                *old_cursor_position,
 3079                Some(new_cursor_position.to_point(buffer)),
 3080                false,
 3081                effects.nav_history == Some(true),
 3082                cx,
 3083            );
 3084        }
 3085
 3086        if local {
 3087            if let Some(buffer_id) = new_cursor_position.buffer_id {
 3088                self.register_buffer(buffer_id, cx);
 3089            }
 3090
 3091            let mut context_menu = self.context_menu.borrow_mut();
 3092            let completion_menu = match context_menu.as_ref() {
 3093                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3094                Some(CodeContextMenu::CodeActions(_)) => {
 3095                    *context_menu = None;
 3096                    None
 3097                }
 3098                None => None,
 3099            };
 3100            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3101            drop(context_menu);
 3102
 3103            if effects.completions
 3104                && let Some(completion_position) = completion_position
 3105            {
 3106                let start_offset = selection_start.to_offset(buffer);
 3107                let position_matches = start_offset == completion_position.to_offset(buffer);
 3108                let continue_showing = if position_matches {
 3109                    if self.snippet_stack.is_empty() {
 3110                        buffer.char_kind_before(start_offset, Some(CharScopeContext::Completion))
 3111                            == Some(CharKind::Word)
 3112                    } else {
 3113                        // Snippet choices can be shown even when the cursor is in whitespace.
 3114                        // Dismissing the menu with actions like backspace is handled by
 3115                        // invalidation regions.
 3116                        true
 3117                    }
 3118                } else {
 3119                    false
 3120                };
 3121
 3122                if continue_showing {
 3123                    self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 3124                } else {
 3125                    self.hide_context_menu(window, cx);
 3126                }
 3127            }
 3128
 3129            hide_hover(self, cx);
 3130
 3131            if old_cursor_position.to_display_point(&display_map).row()
 3132                != new_cursor_position.to_display_point(&display_map).row()
 3133            {
 3134                self.available_code_actions.take();
 3135            }
 3136            self.refresh_code_actions(window, cx);
 3137            self.refresh_document_highlights(cx);
 3138            refresh_linked_ranges(self, window, cx);
 3139
 3140            self.refresh_selected_text_highlights(false, window, cx);
 3141            self.refresh_matching_bracket_highlights(window, cx);
 3142            self.update_visible_edit_prediction(window, cx);
 3143            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3144            self.inline_blame_popover.take();
 3145            if self.git_blame_inline_enabled {
 3146                self.start_inline_blame_timer(window, cx);
 3147            }
 3148        }
 3149
 3150        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3151        cx.emit(EditorEvent::SelectionsChanged { local });
 3152
 3153        let selections = &self.selections.disjoint_anchors_arc();
 3154        if selections.len() == 1 {
 3155            cx.emit(SearchEvent::ActiveMatchChanged)
 3156        }
 3157        if local && let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3158            let inmemory_selections = selections
 3159                .iter()
 3160                .map(|s| {
 3161                    text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3162                        ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3163                })
 3164                .collect();
 3165            self.update_restoration_data(cx, |data| {
 3166                data.selections = inmemory_selections;
 3167            });
 3168
 3169            if WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
 3170                && let Some(workspace_id) =
 3171                    self.workspace.as_ref().and_then(|workspace| workspace.1)
 3172            {
 3173                let snapshot = self.buffer().read(cx).snapshot(cx);
 3174                let selections = selections.clone();
 3175                let background_executor = cx.background_executor().clone();
 3176                let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3177                self.serialize_selections = cx.background_spawn(async move {
 3178                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3179                    let db_selections = selections
 3180                        .iter()
 3181                        .map(|selection| {
 3182                            (
 3183                                selection.start.to_offset(&snapshot),
 3184                                selection.end.to_offset(&snapshot),
 3185                            )
 3186                        })
 3187                        .collect();
 3188
 3189                    DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3190                        .await
 3191                        .with_context(|| {
 3192                            format!(
 3193                                "persisting editor selections for editor {editor_id}, \
 3194                                workspace {workspace_id:?}"
 3195                            )
 3196                        })
 3197                        .log_err();
 3198                });
 3199            }
 3200        }
 3201
 3202        cx.notify();
 3203    }
 3204
 3205    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3206        use text::ToOffset as _;
 3207        use text::ToPoint as _;
 3208
 3209        if self.mode.is_minimap()
 3210            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3211        {
 3212            return;
 3213        }
 3214
 3215        if !self.buffer().read(cx).is_singleton() {
 3216            return;
 3217        }
 3218
 3219        let display_snapshot = self
 3220            .display_map
 3221            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3222        let Some((.., snapshot)) = display_snapshot.buffer_snapshot().as_singleton() else {
 3223            return;
 3224        };
 3225        let inmemory_folds = display_snapshot
 3226            .folds_in_range(0..display_snapshot.buffer_snapshot().len())
 3227            .map(|fold| {
 3228                fold.range.start.text_anchor.to_point(&snapshot)
 3229                    ..fold.range.end.text_anchor.to_point(&snapshot)
 3230            })
 3231            .collect();
 3232        self.update_restoration_data(cx, |data| {
 3233            data.folds = inmemory_folds;
 3234        });
 3235
 3236        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 3237            return;
 3238        };
 3239        let background_executor = cx.background_executor().clone();
 3240        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3241        let db_folds = display_snapshot
 3242            .folds_in_range(0..display_snapshot.buffer_snapshot().len())
 3243            .map(|fold| {
 3244                (
 3245                    fold.range.start.text_anchor.to_offset(&snapshot),
 3246                    fold.range.end.text_anchor.to_offset(&snapshot),
 3247                )
 3248            })
 3249            .collect();
 3250        self.serialize_folds = cx.background_spawn(async move {
 3251            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3252            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3253                .await
 3254                .with_context(|| {
 3255                    format!(
 3256                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3257                    )
 3258                })
 3259                .log_err();
 3260        });
 3261    }
 3262
 3263    pub fn sync_selections(
 3264        &mut self,
 3265        other: Entity<Editor>,
 3266        cx: &mut Context<Self>,
 3267    ) -> gpui::Subscription {
 3268        let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3269        if !other_selections.is_empty() {
 3270            self.selections.change_with(cx, |selections| {
 3271                selections.select_anchors(other_selections);
 3272            });
 3273        }
 3274
 3275        let other_subscription = cx.subscribe(&other, |this, other, other_evt, cx| {
 3276            if let EditorEvent::SelectionsChanged { local: true } = other_evt {
 3277                let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3278                if other_selections.is_empty() {
 3279                    return;
 3280                }
 3281                this.selections.change_with(cx, |selections| {
 3282                    selections.select_anchors(other_selections);
 3283                });
 3284            }
 3285        });
 3286
 3287        let this_subscription = cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| {
 3288            if let EditorEvent::SelectionsChanged { local: true } = this_evt {
 3289                let these_selections = this.selections.disjoint_anchors().to_vec();
 3290                if these_selections.is_empty() {
 3291                    return;
 3292                }
 3293                other.update(cx, |other_editor, cx| {
 3294                    other_editor.selections.change_with(cx, |selections| {
 3295                        selections.select_anchors(these_selections);
 3296                    })
 3297                });
 3298            }
 3299        });
 3300
 3301        Subscription::join(other_subscription, this_subscription)
 3302    }
 3303
 3304    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3305    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3306    /// effects of selection change occur at the end of the transaction.
 3307    pub fn change_selections<R>(
 3308        &mut self,
 3309        effects: SelectionEffects,
 3310        window: &mut Window,
 3311        cx: &mut Context<Self>,
 3312        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3313    ) -> R {
 3314        if let Some(state) = &mut self.deferred_selection_effects_state {
 3315            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3316            state.effects.completions = effects.completions;
 3317            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3318            let (changed, result) = self.selections.change_with(cx, change);
 3319            state.changed |= changed;
 3320            return result;
 3321        }
 3322        let mut state = DeferredSelectionEffectsState {
 3323            changed: false,
 3324            effects,
 3325            old_cursor_position: self.selections.newest_anchor().head(),
 3326            history_entry: SelectionHistoryEntry {
 3327                selections: self.selections.disjoint_anchors_arc(),
 3328                select_next_state: self.select_next_state.clone(),
 3329                select_prev_state: self.select_prev_state.clone(),
 3330                add_selections_state: self.add_selections_state.clone(),
 3331            },
 3332        };
 3333        let (changed, result) = self.selections.change_with(cx, change);
 3334        state.changed = state.changed || changed;
 3335        if self.defer_selection_effects {
 3336            self.deferred_selection_effects_state = Some(state);
 3337        } else {
 3338            self.apply_selection_effects(state, window, cx);
 3339        }
 3340        result
 3341    }
 3342
 3343    /// Defers the effects of selection change, so that the effects of multiple calls to
 3344    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3345    /// to selection history and the state of popovers based on selection position aren't
 3346    /// erroneously updated.
 3347    pub fn with_selection_effects_deferred<R>(
 3348        &mut self,
 3349        window: &mut Window,
 3350        cx: &mut Context<Self>,
 3351        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3352    ) -> R {
 3353        let already_deferred = self.defer_selection_effects;
 3354        self.defer_selection_effects = true;
 3355        let result = update(self, window, cx);
 3356        if !already_deferred {
 3357            self.defer_selection_effects = false;
 3358            if let Some(state) = self.deferred_selection_effects_state.take() {
 3359                self.apply_selection_effects(state, window, cx);
 3360            }
 3361        }
 3362        result
 3363    }
 3364
 3365    fn apply_selection_effects(
 3366        &mut self,
 3367        state: DeferredSelectionEffectsState,
 3368        window: &mut Window,
 3369        cx: &mut Context<Self>,
 3370    ) {
 3371        if state.changed {
 3372            self.selection_history.push(state.history_entry);
 3373
 3374            if let Some(autoscroll) = state.effects.scroll {
 3375                self.request_autoscroll(autoscroll, cx);
 3376            }
 3377
 3378            let old_cursor_position = &state.old_cursor_position;
 3379
 3380            self.selections_did_change(true, old_cursor_position, state.effects, window, cx);
 3381
 3382            if self.should_open_signature_help_automatically(old_cursor_position, cx) {
 3383                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3384            }
 3385        }
 3386    }
 3387
 3388    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3389    where
 3390        I: IntoIterator<Item = (Range<S>, T)>,
 3391        S: ToOffset,
 3392        T: Into<Arc<str>>,
 3393    {
 3394        if self.read_only(cx) {
 3395            return;
 3396        }
 3397
 3398        self.buffer
 3399            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3400    }
 3401
 3402    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3403    where
 3404        I: IntoIterator<Item = (Range<S>, T)>,
 3405        S: ToOffset,
 3406        T: Into<Arc<str>>,
 3407    {
 3408        if self.read_only(cx) {
 3409            return;
 3410        }
 3411
 3412        self.buffer.update(cx, |buffer, cx| {
 3413            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3414        });
 3415    }
 3416
 3417    pub fn edit_with_block_indent<I, S, T>(
 3418        &mut self,
 3419        edits: I,
 3420        original_indent_columns: Vec<Option<u32>>,
 3421        cx: &mut Context<Self>,
 3422    ) where
 3423        I: IntoIterator<Item = (Range<S>, T)>,
 3424        S: ToOffset,
 3425        T: Into<Arc<str>>,
 3426    {
 3427        if self.read_only(cx) {
 3428            return;
 3429        }
 3430
 3431        self.buffer.update(cx, |buffer, cx| {
 3432            buffer.edit(
 3433                edits,
 3434                Some(AutoindentMode::Block {
 3435                    original_indent_columns,
 3436                }),
 3437                cx,
 3438            )
 3439        });
 3440    }
 3441
 3442    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3443        self.hide_context_menu(window, cx);
 3444
 3445        match phase {
 3446            SelectPhase::Begin {
 3447                position,
 3448                add,
 3449                click_count,
 3450            } => self.begin_selection(position, add, click_count, window, cx),
 3451            SelectPhase::BeginColumnar {
 3452                position,
 3453                goal_column,
 3454                reset,
 3455                mode,
 3456            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3457            SelectPhase::Extend {
 3458                position,
 3459                click_count,
 3460            } => self.extend_selection(position, click_count, window, cx),
 3461            SelectPhase::Update {
 3462                position,
 3463                goal_column,
 3464                scroll_delta,
 3465            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3466            SelectPhase::End => self.end_selection(window, cx),
 3467        }
 3468    }
 3469
 3470    fn extend_selection(
 3471        &mut self,
 3472        position: DisplayPoint,
 3473        click_count: usize,
 3474        window: &mut Window,
 3475        cx: &mut Context<Self>,
 3476    ) {
 3477        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3478        let tail = self.selections.newest::<usize>(&display_map).tail();
 3479        let click_count = click_count.max(match self.selections.select_mode() {
 3480            SelectMode::Character => 1,
 3481            SelectMode::Word(_) => 2,
 3482            SelectMode::Line(_) => 3,
 3483            SelectMode::All => 4,
 3484        });
 3485        self.begin_selection(position, false, click_count, window, cx);
 3486
 3487        let tail_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3488
 3489        let current_selection = match self.selections.select_mode() {
 3490            SelectMode::Character | SelectMode::All => tail_anchor..tail_anchor,
 3491            SelectMode::Word(range) | SelectMode::Line(range) => range.clone(),
 3492        };
 3493
 3494        let mut pending_selection = self
 3495            .selections
 3496            .pending_anchor()
 3497            .cloned()
 3498            .expect("extend_selection not called with pending selection");
 3499
 3500        if pending_selection
 3501            .start
 3502            .cmp(¤t_selection.start, display_map.buffer_snapshot())
 3503            == Ordering::Greater
 3504        {
 3505            pending_selection.start = current_selection.start;
 3506        }
 3507        if pending_selection
 3508            .end
 3509            .cmp(¤t_selection.end, display_map.buffer_snapshot())
 3510            == Ordering::Less
 3511        {
 3512            pending_selection.end = current_selection.end;
 3513            pending_selection.reversed = true;
 3514        }
 3515
 3516        let mut pending_mode = self.selections.pending_mode().unwrap();
 3517        match &mut pending_mode {
 3518            SelectMode::Word(range) | SelectMode::Line(range) => *range = current_selection,
 3519            _ => {}
 3520        }
 3521
 3522        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3523            SelectionEffects::scroll(Autoscroll::fit())
 3524        } else {
 3525            SelectionEffects::no_scroll()
 3526        };
 3527
 3528        self.change_selections(effects, window, cx, |s| {
 3529            s.set_pending(pending_selection.clone(), pending_mode);
 3530            s.set_is_extending(true);
 3531        });
 3532    }
 3533
 3534    fn begin_selection(
 3535        &mut self,
 3536        position: DisplayPoint,
 3537        add: bool,
 3538        click_count: usize,
 3539        window: &mut Window,
 3540        cx: &mut Context<Self>,
 3541    ) {
 3542        if !self.focus_handle.is_focused(window) {
 3543            self.last_focused_descendant = None;
 3544            window.focus(&self.focus_handle);
 3545        }
 3546
 3547        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3548        let buffer = display_map.buffer_snapshot();
 3549        let position = display_map.clip_point(position, Bias::Left);
 3550
 3551        let start;
 3552        let end;
 3553        let mode;
 3554        let mut auto_scroll;
 3555        match click_count {
 3556            1 => {
 3557                start = buffer.anchor_before(position.to_point(&display_map));
 3558                end = start;
 3559                mode = SelectMode::Character;
 3560                auto_scroll = true;
 3561            }
 3562            2 => {
 3563                let position = display_map
 3564                    .clip_point(position, Bias::Left)
 3565                    .to_offset(&display_map, Bias::Left);
 3566                let (range, _) = buffer.surrounding_word(position, None);
 3567                start = buffer.anchor_before(range.start);
 3568                end = buffer.anchor_before(range.end);
 3569                mode = SelectMode::Word(start..end);
 3570                auto_scroll = true;
 3571            }
 3572            3 => {
 3573                let position = display_map
 3574                    .clip_point(position, Bias::Left)
 3575                    .to_point(&display_map);
 3576                let line_start = display_map.prev_line_boundary(position).0;
 3577                let next_line_start = buffer.clip_point(
 3578                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3579                    Bias::Left,
 3580                );
 3581                start = buffer.anchor_before(line_start);
 3582                end = buffer.anchor_before(next_line_start);
 3583                mode = SelectMode::Line(start..end);
 3584                auto_scroll = true;
 3585            }
 3586            _ => {
 3587                start = buffer.anchor_before(0);
 3588                end = buffer.anchor_before(buffer.len());
 3589                mode = SelectMode::All;
 3590                auto_scroll = false;
 3591            }
 3592        }
 3593        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3594
 3595        let point_to_delete: Option<usize> = {
 3596            let selected_points: Vec<Selection<Point>> =
 3597                self.selections.disjoint_in_range(start..end, &display_map);
 3598
 3599            if !add || click_count > 1 {
 3600                None
 3601            } else if !selected_points.is_empty() {
 3602                Some(selected_points[0].id)
 3603            } else {
 3604                let clicked_point_already_selected =
 3605                    self.selections.disjoint_anchors().iter().find(|selection| {
 3606                        selection.start.to_point(buffer) == start.to_point(buffer)
 3607                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3608                    });
 3609
 3610                clicked_point_already_selected.map(|selection| selection.id)
 3611            }
 3612        };
 3613
 3614        let selections_count = self.selections.count();
 3615        let effects = if auto_scroll {
 3616            SelectionEffects::default()
 3617        } else {
 3618            SelectionEffects::no_scroll()
 3619        };
 3620
 3621        self.change_selections(effects, window, cx, |s| {
 3622            if let Some(point_to_delete) = point_to_delete {
 3623                s.delete(point_to_delete);
 3624
 3625                if selections_count == 1 {
 3626                    s.set_pending_anchor_range(start..end, mode);
 3627                }
 3628            } else {
 3629                if !add {
 3630                    s.clear_disjoint();
 3631                }
 3632
 3633                s.set_pending_anchor_range(start..end, mode);
 3634            }
 3635        });
 3636    }
 3637
 3638    fn begin_columnar_selection(
 3639        &mut self,
 3640        position: DisplayPoint,
 3641        goal_column: u32,
 3642        reset: bool,
 3643        mode: ColumnarMode,
 3644        window: &mut Window,
 3645        cx: &mut Context<Self>,
 3646    ) {
 3647        if !self.focus_handle.is_focused(window) {
 3648            self.last_focused_descendant = None;
 3649            window.focus(&self.focus_handle);
 3650        }
 3651
 3652        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3653
 3654        if reset {
 3655            let pointer_position = display_map
 3656                .buffer_snapshot()
 3657                .anchor_before(position.to_point(&display_map));
 3658
 3659            self.change_selections(
 3660                SelectionEffects::scroll(Autoscroll::newest()),
 3661                window,
 3662                cx,
 3663                |s| {
 3664                    s.clear_disjoint();
 3665                    s.set_pending_anchor_range(
 3666                        pointer_position..pointer_position,
 3667                        SelectMode::Character,
 3668                    );
 3669                },
 3670            );
 3671        };
 3672
 3673        let tail = self.selections.newest::<Point>(&display_map).tail();
 3674        let selection_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3675        self.columnar_selection_state = match mode {
 3676            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3677                selection_tail: selection_anchor,
 3678                display_point: if reset {
 3679                    if position.column() != goal_column {
 3680                        Some(DisplayPoint::new(position.row(), goal_column))
 3681                    } else {
 3682                        None
 3683                    }
 3684                } else {
 3685                    None
 3686                },
 3687            }),
 3688            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3689                selection_tail: selection_anchor,
 3690            }),
 3691        };
 3692
 3693        if !reset {
 3694            self.select_columns(position, goal_column, &display_map, window, cx);
 3695        }
 3696    }
 3697
 3698    fn update_selection(
 3699        &mut self,
 3700        position: DisplayPoint,
 3701        goal_column: u32,
 3702        scroll_delta: gpui::Point<f32>,
 3703        window: &mut Window,
 3704        cx: &mut Context<Self>,
 3705    ) {
 3706        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3707
 3708        if self.columnar_selection_state.is_some() {
 3709            self.select_columns(position, goal_column, &display_map, window, cx);
 3710        } else if let Some(mut pending) = self.selections.pending_anchor().cloned() {
 3711            let buffer = display_map.buffer_snapshot();
 3712            let head;
 3713            let tail;
 3714            let mode = self.selections.pending_mode().unwrap();
 3715            match &mode {
 3716                SelectMode::Character => {
 3717                    head = position.to_point(&display_map);
 3718                    tail = pending.tail().to_point(buffer);
 3719                }
 3720                SelectMode::Word(original_range) => {
 3721                    let offset = display_map
 3722                        .clip_point(position, Bias::Left)
 3723                        .to_offset(&display_map, Bias::Left);
 3724                    let original_range = original_range.to_offset(buffer);
 3725
 3726                    let head_offset = if buffer.is_inside_word(offset, None)
 3727                        || original_range.contains(&offset)
 3728                    {
 3729                        let (word_range, _) = buffer.surrounding_word(offset, None);
 3730                        if word_range.start < original_range.start {
 3731                            word_range.start
 3732                        } else {
 3733                            word_range.end
 3734                        }
 3735                    } else {
 3736                        offset
 3737                    };
 3738
 3739                    head = head_offset.to_point(buffer);
 3740                    if head_offset <= original_range.start {
 3741                        tail = original_range.end.to_point(buffer);
 3742                    } else {
 3743                        tail = original_range.start.to_point(buffer);
 3744                    }
 3745                }
 3746                SelectMode::Line(original_range) => {
 3747                    let original_range = original_range.to_point(display_map.buffer_snapshot());
 3748
 3749                    let position = display_map
 3750                        .clip_point(position, Bias::Left)
 3751                        .to_point(&display_map);
 3752                    let line_start = display_map.prev_line_boundary(position).0;
 3753                    let next_line_start = buffer.clip_point(
 3754                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3755                        Bias::Left,
 3756                    );
 3757
 3758                    if line_start < original_range.start {
 3759                        head = line_start
 3760                    } else {
 3761                        head = next_line_start
 3762                    }
 3763
 3764                    if head <= original_range.start {
 3765                        tail = original_range.end;
 3766                    } else {
 3767                        tail = original_range.start;
 3768                    }
 3769                }
 3770                SelectMode::All => {
 3771                    return;
 3772                }
 3773            };
 3774
 3775            if head < tail {
 3776                pending.start = buffer.anchor_before(head);
 3777                pending.end = buffer.anchor_before(tail);
 3778                pending.reversed = true;
 3779            } else {
 3780                pending.start = buffer.anchor_before(tail);
 3781                pending.end = buffer.anchor_before(head);
 3782                pending.reversed = false;
 3783            }
 3784
 3785            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3786                s.set_pending(pending.clone(), mode);
 3787            });
 3788        } else {
 3789            log::error!("update_selection dispatched with no pending selection");
 3790            return;
 3791        }
 3792
 3793        self.apply_scroll_delta(scroll_delta, window, cx);
 3794        cx.notify();
 3795    }
 3796
 3797    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3798        self.columnar_selection_state.take();
 3799        if let Some(pending_mode) = self.selections.pending_mode() {
 3800            let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 3801            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3802                s.select(selections);
 3803                s.clear_pending();
 3804                if s.is_extending() {
 3805                    s.set_is_extending(false);
 3806                } else {
 3807                    s.set_select_mode(pending_mode);
 3808                }
 3809            });
 3810        }
 3811    }
 3812
 3813    fn select_columns(
 3814        &mut self,
 3815        head: DisplayPoint,
 3816        goal_column: u32,
 3817        display_map: &DisplaySnapshot,
 3818        window: &mut Window,
 3819        cx: &mut Context<Self>,
 3820    ) {
 3821        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 3822            return;
 3823        };
 3824
 3825        let tail = match columnar_state {
 3826            ColumnarSelectionState::FromMouse {
 3827                selection_tail,
 3828                display_point,
 3829            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(display_map)),
 3830            ColumnarSelectionState::FromSelection { selection_tail } => {
 3831                selection_tail.to_display_point(display_map)
 3832            }
 3833        };
 3834
 3835        let start_row = cmp::min(tail.row(), head.row());
 3836        let end_row = cmp::max(tail.row(), head.row());
 3837        let start_column = cmp::min(tail.column(), goal_column);
 3838        let end_column = cmp::max(tail.column(), goal_column);
 3839        let reversed = start_column < tail.column();
 3840
 3841        let selection_ranges = (start_row.0..=end_row.0)
 3842            .map(DisplayRow)
 3843            .filter_map(|row| {
 3844                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 3845                    || start_column <= display_map.line_len(row))
 3846                    && !display_map.is_block_line(row)
 3847                {
 3848                    let start = display_map
 3849                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3850                        .to_point(display_map);
 3851                    let end = display_map
 3852                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3853                        .to_point(display_map);
 3854                    if reversed {
 3855                        Some(end..start)
 3856                    } else {
 3857                        Some(start..end)
 3858                    }
 3859                } else {
 3860                    None
 3861                }
 3862            })
 3863            .collect::<Vec<_>>();
 3864        if selection_ranges.is_empty() {
 3865            return;
 3866        }
 3867
 3868        let ranges = match columnar_state {
 3869            ColumnarSelectionState::FromMouse { .. } => {
 3870                let mut non_empty_ranges = selection_ranges
 3871                    .iter()
 3872                    .filter(|selection_range| selection_range.start != selection_range.end)
 3873                    .peekable();
 3874                if non_empty_ranges.peek().is_some() {
 3875                    non_empty_ranges.cloned().collect()
 3876                } else {
 3877                    selection_ranges
 3878                }
 3879            }
 3880            _ => selection_ranges,
 3881        };
 3882
 3883        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3884            s.select_ranges(ranges);
 3885        });
 3886        cx.notify();
 3887    }
 3888
 3889    pub fn has_non_empty_selection(&self, snapshot: &DisplaySnapshot) -> bool {
 3890        self.selections
 3891            .all_adjusted(snapshot)
 3892            .iter()
 3893            .any(|selection| !selection.is_empty())
 3894    }
 3895
 3896    pub fn has_pending_nonempty_selection(&self) -> bool {
 3897        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3898            Some(Selection { start, end, .. }) => start != end,
 3899            None => false,
 3900        };
 3901
 3902        pending_nonempty_selection
 3903            || (self.columnar_selection_state.is_some()
 3904                && self.selections.disjoint_anchors().len() > 1)
 3905    }
 3906
 3907    pub fn has_pending_selection(&self) -> bool {
 3908        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 3909    }
 3910
 3911    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3912        self.selection_mark_mode = false;
 3913        self.selection_drag_state = SelectionDragState::None;
 3914
 3915        if self.clear_expanded_diff_hunks(cx) {
 3916            cx.notify();
 3917            return;
 3918        }
 3919        if self.dismiss_menus_and_popups(true, window, cx) {
 3920            return;
 3921        }
 3922
 3923        if self.mode.is_full()
 3924            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 3925        {
 3926            return;
 3927        }
 3928
 3929        cx.propagate();
 3930    }
 3931
 3932    pub fn dismiss_menus_and_popups(
 3933        &mut self,
 3934        is_user_requested: bool,
 3935        window: &mut Window,
 3936        cx: &mut Context<Self>,
 3937    ) -> bool {
 3938        if self.take_rename(false, window, cx).is_some() {
 3939            return true;
 3940        }
 3941
 3942        if self.hide_blame_popover(true, cx) {
 3943            return true;
 3944        }
 3945
 3946        if hide_hover(self, cx) {
 3947            return true;
 3948        }
 3949
 3950        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3951            return true;
 3952        }
 3953
 3954        if self.hide_context_menu(window, cx).is_some() {
 3955            return true;
 3956        }
 3957
 3958        if self.mouse_context_menu.take().is_some() {
 3959            return true;
 3960        }
 3961
 3962        if is_user_requested && self.discard_edit_prediction(true, cx) {
 3963            return true;
 3964        }
 3965
 3966        if self.snippet_stack.pop().is_some() {
 3967            return true;
 3968        }
 3969
 3970        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3971            self.dismiss_diagnostics(cx);
 3972            return true;
 3973        }
 3974
 3975        false
 3976    }
 3977
 3978    fn linked_editing_ranges_for(
 3979        &self,
 3980        selection: Range<text::Anchor>,
 3981        cx: &App,
 3982    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3983        if self.linked_edit_ranges.is_empty() {
 3984            return None;
 3985        }
 3986        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3987            selection.end.buffer_id.and_then(|end_buffer_id| {
 3988                if selection.start.buffer_id != Some(end_buffer_id) {
 3989                    return None;
 3990                }
 3991                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3992                let snapshot = buffer.read(cx).snapshot();
 3993                self.linked_edit_ranges
 3994                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3995                    .map(|ranges| (ranges, snapshot, buffer))
 3996            })?;
 3997        use text::ToOffset as TO;
 3998        // find offset from the start of current range to current cursor position
 3999        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 4000
 4001        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 4002        let start_difference = start_offset - start_byte_offset;
 4003        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 4004        let end_difference = end_offset - start_byte_offset;
 4005        // Current range has associated linked ranges.
 4006        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4007        for range in linked_ranges.iter() {
 4008            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 4009            let end_offset = start_offset + end_difference;
 4010            let start_offset = start_offset + start_difference;
 4011            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 4012                continue;
 4013            }
 4014            if self.selections.disjoint_anchor_ranges().any(|s| {
 4015                if s.start.buffer_id != selection.start.buffer_id
 4016                    || s.end.buffer_id != selection.end.buffer_id
 4017                {
 4018                    return false;
 4019                }
 4020                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 4021                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 4022            }) {
 4023                continue;
 4024            }
 4025            let start = buffer_snapshot.anchor_after(start_offset);
 4026            let end = buffer_snapshot.anchor_after(end_offset);
 4027            linked_edits
 4028                .entry(buffer.clone())
 4029                .or_default()
 4030                .push(start..end);
 4031        }
 4032        Some(linked_edits)
 4033    }
 4034
 4035    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4036        let text: Arc<str> = text.into();
 4037
 4038        if self.read_only(cx) {
 4039            return;
 4040        }
 4041
 4042        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4043
 4044        let selections = self.selections.all_adjusted(&self.display_snapshot(cx));
 4045        let mut bracket_inserted = false;
 4046        let mut edits = Vec::new();
 4047        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4048        let mut new_selections = Vec::with_capacity(selections.len());
 4049        let mut new_autoclose_regions = Vec::new();
 4050        let snapshot = self.buffer.read(cx).read(cx);
 4051        let mut clear_linked_edit_ranges = false;
 4052
 4053        for (selection, autoclose_region) in
 4054            self.selections_with_autoclose_regions(selections, &snapshot)
 4055        {
 4056            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 4057                // Determine if the inserted text matches the opening or closing
 4058                // bracket of any of this language's bracket pairs.
 4059                let mut bracket_pair = None;
 4060                let mut is_bracket_pair_start = false;
 4061                let mut is_bracket_pair_end = false;
 4062                if !text.is_empty() {
 4063                    let mut bracket_pair_matching_end = None;
 4064                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 4065                    //  and they are removing the character that triggered IME popup.
 4066                    for (pair, enabled) in scope.brackets() {
 4067                        if !pair.close && !pair.surround {
 4068                            continue;
 4069                        }
 4070
 4071                        if enabled && pair.start.ends_with(text.as_ref()) {
 4072                            let prefix_len = pair.start.len() - text.len();
 4073                            let preceding_text_matches_prefix = prefix_len == 0
 4074                                || (selection.start.column >= (prefix_len as u32)
 4075                                    && snapshot.contains_str_at(
 4076                                        Point::new(
 4077                                            selection.start.row,
 4078                                            selection.start.column - (prefix_len as u32),
 4079                                        ),
 4080                                        &pair.start[..prefix_len],
 4081                                    ));
 4082                            if preceding_text_matches_prefix {
 4083                                bracket_pair = Some(pair.clone());
 4084                                is_bracket_pair_start = true;
 4085                                break;
 4086                            }
 4087                        }
 4088                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 4089                        {
 4090                            // take first bracket pair matching end, but don't break in case a later bracket
 4091                            // pair matches start
 4092                            bracket_pair_matching_end = Some(pair.clone());
 4093                        }
 4094                    }
 4095                    if let Some(end) = bracket_pair_matching_end
 4096                        && bracket_pair.is_none()
 4097                    {
 4098                        bracket_pair = Some(end);
 4099                        is_bracket_pair_end = true;
 4100                    }
 4101                }
 4102
 4103                if let Some(bracket_pair) = bracket_pair {
 4104                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 4105                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 4106                    let auto_surround =
 4107                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 4108                    if selection.is_empty() {
 4109                        if is_bracket_pair_start {
 4110                            // If the inserted text is a suffix of an opening bracket and the
 4111                            // selection is preceded by the rest of the opening bracket, then
 4112                            // insert the closing bracket.
 4113                            let following_text_allows_autoclose = snapshot
 4114                                .chars_at(selection.start)
 4115                                .next()
 4116                                .is_none_or(|c| scope.should_autoclose_before(c));
 4117
 4118                            let preceding_text_allows_autoclose = selection.start.column == 0
 4119                                || snapshot
 4120                                    .reversed_chars_at(selection.start)
 4121                                    .next()
 4122                                    .is_none_or(|c| {
 4123                                        bracket_pair.start != bracket_pair.end
 4124                                            || !snapshot
 4125                                                .char_classifier_at(selection.start)
 4126                                                .is_word(c)
 4127                                    });
 4128
 4129                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4130                                && bracket_pair.start.len() == 1
 4131                            {
 4132                                let target = bracket_pair.start.chars().next().unwrap();
 4133                                let current_line_count = snapshot
 4134                                    .reversed_chars_at(selection.start)
 4135                                    .take_while(|&c| c != '\n')
 4136                                    .filter(|&c| c == target)
 4137                                    .count();
 4138                                current_line_count % 2 == 1
 4139                            } else {
 4140                                false
 4141                            };
 4142
 4143                            if autoclose
 4144                                && bracket_pair.close
 4145                                && following_text_allows_autoclose
 4146                                && preceding_text_allows_autoclose
 4147                                && !is_closing_quote
 4148                            {
 4149                                let anchor = snapshot.anchor_before(selection.end);
 4150                                new_selections.push((selection.map(|_| anchor), text.len()));
 4151                                new_autoclose_regions.push((
 4152                                    anchor,
 4153                                    text.len(),
 4154                                    selection.id,
 4155                                    bracket_pair.clone(),
 4156                                ));
 4157                                edits.push((
 4158                                    selection.range(),
 4159                                    format!("{}{}", text, bracket_pair.end).into(),
 4160                                ));
 4161                                bracket_inserted = true;
 4162                                continue;
 4163                            }
 4164                        }
 4165
 4166                        if let Some(region) = autoclose_region {
 4167                            // If the selection is followed by an auto-inserted closing bracket,
 4168                            // then don't insert that closing bracket again; just move the selection
 4169                            // past the closing bracket.
 4170                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4171                                && text.as_ref() == region.pair.end.as_str()
 4172                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4173                            if should_skip {
 4174                                let anchor = snapshot.anchor_after(selection.end);
 4175                                new_selections
 4176                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4177                                continue;
 4178                            }
 4179                        }
 4180
 4181                        let always_treat_brackets_as_autoclosed = snapshot
 4182                            .language_settings_at(selection.start, cx)
 4183                            .always_treat_brackets_as_autoclosed;
 4184                        if always_treat_brackets_as_autoclosed
 4185                            && is_bracket_pair_end
 4186                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4187                        {
 4188                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4189                            // and the inserted text is a closing bracket and the selection is followed
 4190                            // by the closing bracket then move the selection past the closing bracket.
 4191                            let anchor = snapshot.anchor_after(selection.end);
 4192                            new_selections.push((selection.map(|_| anchor), text.len()));
 4193                            continue;
 4194                        }
 4195                    }
 4196                    // If an opening bracket is 1 character long and is typed while
 4197                    // text is selected, then surround that text with the bracket pair.
 4198                    else if auto_surround
 4199                        && bracket_pair.surround
 4200                        && is_bracket_pair_start
 4201                        && bracket_pair.start.chars().count() == 1
 4202                    {
 4203                        edits.push((selection.start..selection.start, text.clone()));
 4204                        edits.push((
 4205                            selection.end..selection.end,
 4206                            bracket_pair.end.as_str().into(),
 4207                        ));
 4208                        bracket_inserted = true;
 4209                        new_selections.push((
 4210                            Selection {
 4211                                id: selection.id,
 4212                                start: snapshot.anchor_after(selection.start),
 4213                                end: snapshot.anchor_before(selection.end),
 4214                                reversed: selection.reversed,
 4215                                goal: selection.goal,
 4216                            },
 4217                            0,
 4218                        ));
 4219                        continue;
 4220                    }
 4221                }
 4222            }
 4223
 4224            if self.auto_replace_emoji_shortcode
 4225                && selection.is_empty()
 4226                && text.as_ref().ends_with(':')
 4227                && let Some(possible_emoji_short_code) =
 4228                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4229                && !possible_emoji_short_code.is_empty()
 4230                && let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code)
 4231            {
 4232                let emoji_shortcode_start = Point::new(
 4233                    selection.start.row,
 4234                    selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4235                );
 4236
 4237                // Remove shortcode from buffer
 4238                edits.push((
 4239                    emoji_shortcode_start..selection.start,
 4240                    "".to_string().into(),
 4241                ));
 4242                new_selections.push((
 4243                    Selection {
 4244                        id: selection.id,
 4245                        start: snapshot.anchor_after(emoji_shortcode_start),
 4246                        end: snapshot.anchor_before(selection.start),
 4247                        reversed: selection.reversed,
 4248                        goal: selection.goal,
 4249                    },
 4250                    0,
 4251                ));
 4252
 4253                // Insert emoji
 4254                let selection_start_anchor = snapshot.anchor_after(selection.start);
 4255                new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4256                edits.push((selection.start..selection.end, emoji.to_string().into()));
 4257
 4258                continue;
 4259            }
 4260
 4261            // If not handling any auto-close operation, then just replace the selected
 4262            // text with the given input and move the selection to the end of the
 4263            // newly inserted text.
 4264            let anchor = snapshot.anchor_after(selection.end);
 4265            if !self.linked_edit_ranges.is_empty() {
 4266                let start_anchor = snapshot.anchor_before(selection.start);
 4267
 4268                let is_word_char = text.chars().next().is_none_or(|char| {
 4269                    let classifier = snapshot
 4270                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4271                        .scope_context(Some(CharScopeContext::LinkedEdit));
 4272                    classifier.is_word(char)
 4273                });
 4274
 4275                if is_word_char {
 4276                    if let Some(ranges) = self
 4277                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4278                    {
 4279                        for (buffer, edits) in ranges {
 4280                            linked_edits
 4281                                .entry(buffer.clone())
 4282                                .or_default()
 4283                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4284                        }
 4285                    }
 4286                } else {
 4287                    clear_linked_edit_ranges = true;
 4288                }
 4289            }
 4290
 4291            new_selections.push((selection.map(|_| anchor), 0));
 4292            edits.push((selection.start..selection.end, text.clone()));
 4293        }
 4294
 4295        drop(snapshot);
 4296
 4297        self.transact(window, cx, |this, window, cx| {
 4298            if clear_linked_edit_ranges {
 4299                this.linked_edit_ranges.clear();
 4300            }
 4301            let initial_buffer_versions =
 4302                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4303
 4304            this.buffer.update(cx, |buffer, cx| {
 4305                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4306            });
 4307            for (buffer, edits) in linked_edits {
 4308                buffer.update(cx, |buffer, cx| {
 4309                    let snapshot = buffer.snapshot();
 4310                    let edits = edits
 4311                        .into_iter()
 4312                        .map(|(range, text)| {
 4313                            use text::ToPoint as TP;
 4314                            let end_point = TP::to_point(&range.end, &snapshot);
 4315                            let start_point = TP::to_point(&range.start, &snapshot);
 4316                            (start_point..end_point, text)
 4317                        })
 4318                        .sorted_by_key(|(range, _)| range.start);
 4319                    buffer.edit(edits, None, cx);
 4320                })
 4321            }
 4322            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4323            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4324            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4325            let new_selections =
 4326                resolve_selections_wrapping_blocks::<usize, _>(new_anchor_selections, &map)
 4327                    .zip(new_selection_deltas)
 4328                    .map(|(selection, delta)| Selection {
 4329                        id: selection.id,
 4330                        start: selection.start + delta,
 4331                        end: selection.end + delta,
 4332                        reversed: selection.reversed,
 4333                        goal: SelectionGoal::None,
 4334                    })
 4335                    .collect::<Vec<_>>();
 4336
 4337            let mut i = 0;
 4338            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4339                let position = position.to_offset(map.buffer_snapshot()) + delta;
 4340                let start = map.buffer_snapshot().anchor_before(position);
 4341                let end = map.buffer_snapshot().anchor_after(position);
 4342                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4343                    match existing_state
 4344                        .range
 4345                        .start
 4346                        .cmp(&start, map.buffer_snapshot())
 4347                    {
 4348                        Ordering::Less => i += 1,
 4349                        Ordering::Greater => break,
 4350                        Ordering::Equal => {
 4351                            match end.cmp(&existing_state.range.end, map.buffer_snapshot()) {
 4352                                Ordering::Less => i += 1,
 4353                                Ordering::Equal => break,
 4354                                Ordering::Greater => break,
 4355                            }
 4356                        }
 4357                    }
 4358                }
 4359                this.autoclose_regions.insert(
 4360                    i,
 4361                    AutocloseRegion {
 4362                        selection_id,
 4363                        range: start..end,
 4364                        pair,
 4365                    },
 4366                );
 4367            }
 4368
 4369            let had_active_edit_prediction = this.has_active_edit_prediction();
 4370            this.change_selections(
 4371                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4372                window,
 4373                cx,
 4374                |s| s.select(new_selections),
 4375            );
 4376
 4377            if !bracket_inserted
 4378                && let Some(on_type_format_task) =
 4379                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4380            {
 4381                on_type_format_task.detach_and_log_err(cx);
 4382            }
 4383
 4384            let editor_settings = EditorSettings::get_global(cx);
 4385            if bracket_inserted
 4386                && (editor_settings.auto_signature_help
 4387                    || editor_settings.show_signature_help_after_edits)
 4388            {
 4389                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4390            }
 4391
 4392            let trigger_in_words =
 4393                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 4394            if this.hard_wrap.is_some() {
 4395                let latest: Range<Point> = this.selections.newest(&map).range();
 4396                if latest.is_empty()
 4397                    && this
 4398                        .buffer()
 4399                        .read(cx)
 4400                        .snapshot(cx)
 4401                        .line_len(MultiBufferRow(latest.start.row))
 4402                        == latest.start.column
 4403                {
 4404                    this.rewrap_impl(
 4405                        RewrapOptions {
 4406                            override_language_settings: true,
 4407                            preserve_existing_whitespace: true,
 4408                        },
 4409                        cx,
 4410                    )
 4411                }
 4412            }
 4413            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4414            refresh_linked_ranges(this, window, cx);
 4415            this.refresh_edit_prediction(true, false, window, cx);
 4416            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4417        });
 4418    }
 4419
 4420    fn find_possible_emoji_shortcode_at_position(
 4421        snapshot: &MultiBufferSnapshot,
 4422        position: Point,
 4423    ) -> Option<String> {
 4424        let mut chars = Vec::new();
 4425        let mut found_colon = false;
 4426        for char in snapshot.reversed_chars_at(position).take(100) {
 4427            // Found a possible emoji shortcode in the middle of the buffer
 4428            if found_colon {
 4429                if char.is_whitespace() {
 4430                    chars.reverse();
 4431                    return Some(chars.iter().collect());
 4432                }
 4433                // If the previous character is not a whitespace, we are in the middle of a word
 4434                // and we only want to complete the shortcode if the word is made up of other emojis
 4435                let mut containing_word = String::new();
 4436                for ch in snapshot
 4437                    .reversed_chars_at(position)
 4438                    .skip(chars.len() + 1)
 4439                    .take(100)
 4440                {
 4441                    if ch.is_whitespace() {
 4442                        break;
 4443                    }
 4444                    containing_word.push(ch);
 4445                }
 4446                let containing_word = containing_word.chars().rev().collect::<String>();
 4447                if util::word_consists_of_emojis(containing_word.as_str()) {
 4448                    chars.reverse();
 4449                    return Some(chars.iter().collect());
 4450                }
 4451            }
 4452
 4453            if char.is_whitespace() || !char.is_ascii() {
 4454                return None;
 4455            }
 4456            if char == ':' {
 4457                found_colon = true;
 4458            } else {
 4459                chars.push(char);
 4460            }
 4461        }
 4462        // Found a possible emoji shortcode at the beginning of the buffer
 4463        chars.reverse();
 4464        Some(chars.iter().collect())
 4465    }
 4466
 4467    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4468        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4469        self.transact(window, cx, |this, window, cx| {
 4470            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4471                let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
 4472                let multi_buffer = this.buffer.read(cx);
 4473                let buffer = multi_buffer.snapshot(cx);
 4474                selections
 4475                    .iter()
 4476                    .map(|selection| {
 4477                        let start_point = selection.start.to_point(&buffer);
 4478                        let mut existing_indent =
 4479                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4480                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4481                        let start = selection.start;
 4482                        let end = selection.end;
 4483                        let selection_is_empty = start == end;
 4484                        let language_scope = buffer.language_scope_at(start);
 4485                        let (
 4486                            comment_delimiter,
 4487                            doc_delimiter,
 4488                            insert_extra_newline,
 4489                            indent_on_newline,
 4490                            indent_on_extra_newline,
 4491                        ) = if let Some(language) = &language_scope {
 4492                            let mut insert_extra_newline =
 4493                                insert_extra_newline_brackets(&buffer, start..end, language)
 4494                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4495
 4496                            // Comment extension on newline is allowed only for cursor selections
 4497                            let comment_delimiter = maybe!({
 4498                                if !selection_is_empty {
 4499                                    return None;
 4500                                }
 4501
 4502                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4503                                    return None;
 4504                                }
 4505
 4506                                let delimiters = language.line_comment_prefixes();
 4507                                let max_len_of_delimiter =
 4508                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4509                                let (snapshot, range) =
 4510                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4511
 4512                                let num_of_whitespaces = snapshot
 4513                                    .chars_for_range(range.clone())
 4514                                    .take_while(|c| c.is_whitespace())
 4515                                    .count();
 4516                                let comment_candidate = snapshot
 4517                                    .chars_for_range(range.clone())
 4518                                    .skip(num_of_whitespaces)
 4519                                    .take(max_len_of_delimiter)
 4520                                    .collect::<String>();
 4521                                let (delimiter, trimmed_len) = delimiters
 4522                                    .iter()
 4523                                    .filter_map(|delimiter| {
 4524                                        let prefix = delimiter.trim_end();
 4525                                        if comment_candidate.starts_with(prefix) {
 4526                                            Some((delimiter, prefix.len()))
 4527                                        } else {
 4528                                            None
 4529                                        }
 4530                                    })
 4531                                    .max_by_key(|(_, len)| *len)?;
 4532
 4533                                if let Some(BlockCommentConfig {
 4534                                    start: block_start, ..
 4535                                }) = language.block_comment()
 4536                                {
 4537                                    let block_start_trimmed = block_start.trim_end();
 4538                                    if block_start_trimmed.starts_with(delimiter.trim_end()) {
 4539                                        let line_content = snapshot
 4540                                            .chars_for_range(range)
 4541                                            .skip(num_of_whitespaces)
 4542                                            .take(block_start_trimmed.len())
 4543                                            .collect::<String>();
 4544
 4545                                        if line_content.starts_with(block_start_trimmed) {
 4546                                            return None;
 4547                                        }
 4548                                    }
 4549                                }
 4550
 4551                                let cursor_is_placed_after_comment_marker =
 4552                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4553                                if cursor_is_placed_after_comment_marker {
 4554                                    Some(delimiter.clone())
 4555                                } else {
 4556                                    None
 4557                                }
 4558                            });
 4559
 4560                            let mut indent_on_newline = IndentSize::spaces(0);
 4561                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4562
 4563                            let doc_delimiter = maybe!({
 4564                                if !selection_is_empty {
 4565                                    return None;
 4566                                }
 4567
 4568                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4569                                    return None;
 4570                                }
 4571
 4572                                let BlockCommentConfig {
 4573                                    start: start_tag,
 4574                                    end: end_tag,
 4575                                    prefix: delimiter,
 4576                                    tab_size: len,
 4577                                } = language.documentation_comment()?;
 4578                                let is_within_block_comment = buffer
 4579                                    .language_scope_at(start_point)
 4580                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4581                                if !is_within_block_comment {
 4582                                    return None;
 4583                                }
 4584
 4585                                let (snapshot, range) =
 4586                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4587
 4588                                let num_of_whitespaces = snapshot
 4589                                    .chars_for_range(range.clone())
 4590                                    .take_while(|c| c.is_whitespace())
 4591                                    .count();
 4592
 4593                                // 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.
 4594                                let column = start_point.column;
 4595                                let cursor_is_after_start_tag = {
 4596                                    let start_tag_len = start_tag.len();
 4597                                    let start_tag_line = snapshot
 4598                                        .chars_for_range(range.clone())
 4599                                        .skip(num_of_whitespaces)
 4600                                        .take(start_tag_len)
 4601                                        .collect::<String>();
 4602                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4603                                        num_of_whitespaces + start_tag_len <= column as usize
 4604                                    } else {
 4605                                        false
 4606                                    }
 4607                                };
 4608
 4609                                let cursor_is_after_delimiter = {
 4610                                    let delimiter_trim = delimiter.trim_end();
 4611                                    let delimiter_line = snapshot
 4612                                        .chars_for_range(range.clone())
 4613                                        .skip(num_of_whitespaces)
 4614                                        .take(delimiter_trim.len())
 4615                                        .collect::<String>();
 4616                                    if delimiter_line.starts_with(delimiter_trim) {
 4617                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4618                                    } else {
 4619                                        false
 4620                                    }
 4621                                };
 4622
 4623                                let cursor_is_before_end_tag_if_exists = {
 4624                                    let mut char_position = 0u32;
 4625                                    let mut end_tag_offset = None;
 4626
 4627                                    'outer: for chunk in snapshot.text_for_range(range) {
 4628                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4629                                            let chars_before_match =
 4630                                                chunk[..byte_pos].chars().count() as u32;
 4631                                            end_tag_offset =
 4632                                                Some(char_position + chars_before_match);
 4633                                            break 'outer;
 4634                                        }
 4635                                        char_position += chunk.chars().count() as u32;
 4636                                    }
 4637
 4638                                    if let Some(end_tag_offset) = end_tag_offset {
 4639                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4640                                        if cursor_is_after_start_tag {
 4641                                            if cursor_is_before_end_tag {
 4642                                                insert_extra_newline = true;
 4643                                            }
 4644                                            let cursor_is_at_start_of_end_tag =
 4645                                                column == end_tag_offset;
 4646                                            if cursor_is_at_start_of_end_tag {
 4647                                                indent_on_extra_newline.len = *len;
 4648                                            }
 4649                                        }
 4650                                        cursor_is_before_end_tag
 4651                                    } else {
 4652                                        true
 4653                                    }
 4654                                };
 4655
 4656                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4657                                    && cursor_is_before_end_tag_if_exists
 4658                                {
 4659                                    if cursor_is_after_start_tag {
 4660                                        indent_on_newline.len = *len;
 4661                                    }
 4662                                    Some(delimiter.clone())
 4663                                } else {
 4664                                    None
 4665                                }
 4666                            });
 4667
 4668                            (
 4669                                comment_delimiter,
 4670                                doc_delimiter,
 4671                                insert_extra_newline,
 4672                                indent_on_newline,
 4673                                indent_on_extra_newline,
 4674                            )
 4675                        } else {
 4676                            (
 4677                                None,
 4678                                None,
 4679                                false,
 4680                                IndentSize::default(),
 4681                                IndentSize::default(),
 4682                            )
 4683                        };
 4684
 4685                        let prevent_auto_indent = doc_delimiter.is_some();
 4686                        let delimiter = comment_delimiter.or(doc_delimiter);
 4687
 4688                        let capacity_for_delimiter =
 4689                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4690                        let mut new_text = String::with_capacity(
 4691                            1 + capacity_for_delimiter
 4692                                + existing_indent.len as usize
 4693                                + indent_on_newline.len as usize
 4694                                + indent_on_extra_newline.len as usize,
 4695                        );
 4696                        new_text.push('\n');
 4697                        new_text.extend(existing_indent.chars());
 4698                        new_text.extend(indent_on_newline.chars());
 4699
 4700                        if let Some(delimiter) = &delimiter {
 4701                            new_text.push_str(delimiter);
 4702                        }
 4703
 4704                        if insert_extra_newline {
 4705                            new_text.push('\n');
 4706                            new_text.extend(existing_indent.chars());
 4707                            new_text.extend(indent_on_extra_newline.chars());
 4708                        }
 4709
 4710                        let anchor = buffer.anchor_after(end);
 4711                        let new_selection = selection.map(|_| anchor);
 4712                        (
 4713                            ((start..end, new_text), prevent_auto_indent),
 4714                            (insert_extra_newline, new_selection),
 4715                        )
 4716                    })
 4717                    .unzip()
 4718            };
 4719
 4720            let mut auto_indent_edits = Vec::new();
 4721            let mut edits = Vec::new();
 4722            for (edit, prevent_auto_indent) in edits_with_flags {
 4723                if prevent_auto_indent {
 4724                    edits.push(edit);
 4725                } else {
 4726                    auto_indent_edits.push(edit);
 4727                }
 4728            }
 4729            if !edits.is_empty() {
 4730                this.edit(edits, cx);
 4731            }
 4732            if !auto_indent_edits.is_empty() {
 4733                this.edit_with_autoindent(auto_indent_edits, cx);
 4734            }
 4735
 4736            let buffer = this.buffer.read(cx).snapshot(cx);
 4737            let new_selections = selection_info
 4738                .into_iter()
 4739                .map(|(extra_newline_inserted, new_selection)| {
 4740                    let mut cursor = new_selection.end.to_point(&buffer);
 4741                    if extra_newline_inserted {
 4742                        cursor.row -= 1;
 4743                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4744                    }
 4745                    new_selection.map(|_| cursor)
 4746                })
 4747                .collect();
 4748
 4749            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 4750            this.refresh_edit_prediction(true, false, window, cx);
 4751        });
 4752    }
 4753
 4754    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4755        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4756
 4757        let buffer = self.buffer.read(cx);
 4758        let snapshot = buffer.snapshot(cx);
 4759
 4760        let mut edits = Vec::new();
 4761        let mut rows = Vec::new();
 4762
 4763        for (rows_inserted, selection) in self
 4764            .selections
 4765            .all_adjusted(&self.display_snapshot(cx))
 4766            .into_iter()
 4767            .enumerate()
 4768        {
 4769            let cursor = selection.head();
 4770            let row = cursor.row;
 4771
 4772            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4773
 4774            let newline = "\n".to_string();
 4775            edits.push((start_of_line..start_of_line, newline));
 4776
 4777            rows.push(row + rows_inserted as u32);
 4778        }
 4779
 4780        self.transact(window, cx, |editor, window, cx| {
 4781            editor.edit(edits, cx);
 4782
 4783            editor.change_selections(Default::default(), window, cx, |s| {
 4784                let mut index = 0;
 4785                s.move_cursors_with(|map, _, _| {
 4786                    let row = rows[index];
 4787                    index += 1;
 4788
 4789                    let point = Point::new(row, 0);
 4790                    let boundary = map.next_line_boundary(point).1;
 4791                    let clipped = map.clip_point(boundary, Bias::Left);
 4792
 4793                    (clipped, SelectionGoal::None)
 4794                });
 4795            });
 4796
 4797            let mut indent_edits = Vec::new();
 4798            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4799            for row in rows {
 4800                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4801                for (row, indent) in indents {
 4802                    if indent.len == 0 {
 4803                        continue;
 4804                    }
 4805
 4806                    let text = match indent.kind {
 4807                        IndentKind::Space => " ".repeat(indent.len as usize),
 4808                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4809                    };
 4810                    let point = Point::new(row.0, 0);
 4811                    indent_edits.push((point..point, text));
 4812                }
 4813            }
 4814            editor.edit(indent_edits, cx);
 4815        });
 4816    }
 4817
 4818    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4819        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4820
 4821        let buffer = self.buffer.read(cx);
 4822        let snapshot = buffer.snapshot(cx);
 4823
 4824        let mut edits = Vec::new();
 4825        let mut rows = Vec::new();
 4826        let mut rows_inserted = 0;
 4827
 4828        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
 4829            let cursor = selection.head();
 4830            let row = cursor.row;
 4831
 4832            let point = Point::new(row + 1, 0);
 4833            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4834
 4835            let newline = "\n".to_string();
 4836            edits.push((start_of_line..start_of_line, newline));
 4837
 4838            rows_inserted += 1;
 4839            rows.push(row + rows_inserted);
 4840        }
 4841
 4842        self.transact(window, cx, |editor, window, cx| {
 4843            editor.edit(edits, cx);
 4844
 4845            editor.change_selections(Default::default(), window, cx, |s| {
 4846                let mut index = 0;
 4847                s.move_cursors_with(|map, _, _| {
 4848                    let row = rows[index];
 4849                    index += 1;
 4850
 4851                    let point = Point::new(row, 0);
 4852                    let boundary = map.next_line_boundary(point).1;
 4853                    let clipped = map.clip_point(boundary, Bias::Left);
 4854
 4855                    (clipped, SelectionGoal::None)
 4856                });
 4857            });
 4858
 4859            let mut indent_edits = Vec::new();
 4860            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4861            for row in rows {
 4862                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4863                for (row, indent) in indents {
 4864                    if indent.len == 0 {
 4865                        continue;
 4866                    }
 4867
 4868                    let text = match indent.kind {
 4869                        IndentKind::Space => " ".repeat(indent.len as usize),
 4870                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4871                    };
 4872                    let point = Point::new(row.0, 0);
 4873                    indent_edits.push((point..point, text));
 4874                }
 4875            }
 4876            editor.edit(indent_edits, cx);
 4877        });
 4878    }
 4879
 4880    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4881        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4882            original_indent_columns: Vec::new(),
 4883        });
 4884        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4885    }
 4886
 4887    fn insert_with_autoindent_mode(
 4888        &mut self,
 4889        text: &str,
 4890        autoindent_mode: Option<AutoindentMode>,
 4891        window: &mut Window,
 4892        cx: &mut Context<Self>,
 4893    ) {
 4894        if self.read_only(cx) {
 4895            return;
 4896        }
 4897
 4898        let text: Arc<str> = text.into();
 4899        self.transact(window, cx, |this, window, cx| {
 4900            let old_selections = this.selections.all_adjusted(&this.display_snapshot(cx));
 4901            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4902                let anchors = {
 4903                    let snapshot = buffer.read(cx);
 4904                    old_selections
 4905                        .iter()
 4906                        .map(|s| {
 4907                            let anchor = snapshot.anchor_after(s.head());
 4908                            s.map(|_| anchor)
 4909                        })
 4910                        .collect::<Vec<_>>()
 4911                };
 4912                buffer.edit(
 4913                    old_selections
 4914                        .iter()
 4915                        .map(|s| (s.start..s.end, text.clone())),
 4916                    autoindent_mode,
 4917                    cx,
 4918                );
 4919                anchors
 4920            });
 4921
 4922            this.change_selections(Default::default(), window, cx, |s| {
 4923                s.select_anchors(selection_anchors);
 4924            });
 4925
 4926            cx.notify();
 4927        });
 4928    }
 4929
 4930    fn trigger_completion_on_input(
 4931        &mut self,
 4932        text: &str,
 4933        trigger_in_words: bool,
 4934        window: &mut Window,
 4935        cx: &mut Context<Self>,
 4936    ) {
 4937        let completions_source = self
 4938            .context_menu
 4939            .borrow()
 4940            .as_ref()
 4941            .and_then(|menu| match menu {
 4942                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 4943                CodeContextMenu::CodeActions(_) => None,
 4944            });
 4945
 4946        match completions_source {
 4947            Some(CompletionsMenuSource::Words { .. }) => {
 4948                self.open_or_update_completions_menu(
 4949                    Some(CompletionsMenuSource::Words {
 4950                        ignore_threshold: false,
 4951                    }),
 4952                    None,
 4953                    window,
 4954                    cx,
 4955                );
 4956            }
 4957            Some(CompletionsMenuSource::Normal)
 4958            | Some(CompletionsMenuSource::SnippetChoices)
 4959            | None
 4960                if self.is_completion_trigger(
 4961                    text,
 4962                    trigger_in_words,
 4963                    completions_source.is_some(),
 4964                    cx,
 4965                ) =>
 4966            {
 4967                self.show_completions(
 4968                    &ShowCompletions {
 4969                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4970                    },
 4971                    window,
 4972                    cx,
 4973                )
 4974            }
 4975            _ => {
 4976                self.hide_context_menu(window, cx);
 4977            }
 4978        }
 4979    }
 4980
 4981    fn is_completion_trigger(
 4982        &self,
 4983        text: &str,
 4984        trigger_in_words: bool,
 4985        menu_is_open: bool,
 4986        cx: &mut Context<Self>,
 4987    ) -> bool {
 4988        let position = self.selections.newest_anchor().head();
 4989        let Some(buffer) = self.buffer.read(cx).buffer_for_anchor(position, cx) else {
 4990            return false;
 4991        };
 4992
 4993        if let Some(completion_provider) = &self.completion_provider {
 4994            completion_provider.is_completion_trigger(
 4995                &buffer,
 4996                position.text_anchor,
 4997                text,
 4998                trigger_in_words,
 4999                menu_is_open,
 5000                cx,
 5001            )
 5002        } else {
 5003            false
 5004        }
 5005    }
 5006
 5007    /// If any empty selections is touching the start of its innermost containing autoclose
 5008    /// region, expand it to select the brackets.
 5009    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 5010        let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 5011        let buffer = self.buffer.read(cx).read(cx);
 5012        let new_selections = self
 5013            .selections_with_autoclose_regions(selections, &buffer)
 5014            .map(|(mut selection, region)| {
 5015                if !selection.is_empty() {
 5016                    return selection;
 5017                }
 5018
 5019                if let Some(region) = region {
 5020                    let mut range = region.range.to_offset(&buffer);
 5021                    if selection.start == range.start && range.start >= region.pair.start.len() {
 5022                        range.start -= region.pair.start.len();
 5023                        if buffer.contains_str_at(range.start, ®ion.pair.start)
 5024                            && buffer.contains_str_at(range.end, ®ion.pair.end)
 5025                        {
 5026                            range.end += region.pair.end.len();
 5027                            selection.start = range.start;
 5028                            selection.end = range.end;
 5029
 5030                            return selection;
 5031                        }
 5032                    }
 5033                }
 5034
 5035                let always_treat_brackets_as_autoclosed = buffer
 5036                    .language_settings_at(selection.start, cx)
 5037                    .always_treat_brackets_as_autoclosed;
 5038
 5039                if !always_treat_brackets_as_autoclosed {
 5040                    return selection;
 5041                }
 5042
 5043                if let Some(scope) = buffer.language_scope_at(selection.start) {
 5044                    for (pair, enabled) in scope.brackets() {
 5045                        if !enabled || !pair.close {
 5046                            continue;
 5047                        }
 5048
 5049                        if buffer.contains_str_at(selection.start, &pair.end) {
 5050                            let pair_start_len = pair.start.len();
 5051                            if buffer.contains_str_at(
 5052                                selection.start.saturating_sub(pair_start_len),
 5053                                &pair.start,
 5054                            ) {
 5055                                selection.start -= pair_start_len;
 5056                                selection.end += pair.end.len();
 5057
 5058                                return selection;
 5059                            }
 5060                        }
 5061                    }
 5062                }
 5063
 5064                selection
 5065            })
 5066            .collect();
 5067
 5068        drop(buffer);
 5069        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 5070            selections.select(new_selections)
 5071        });
 5072    }
 5073
 5074    /// Iterate the given selections, and for each one, find the smallest surrounding
 5075    /// autoclose region. This uses the ordering of the selections and the autoclose
 5076    /// regions to avoid repeated comparisons.
 5077    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 5078        &'a self,
 5079        selections: impl IntoIterator<Item = Selection<D>>,
 5080        buffer: &'a MultiBufferSnapshot,
 5081    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 5082        let mut i = 0;
 5083        let mut regions = self.autoclose_regions.as_slice();
 5084        selections.into_iter().map(move |selection| {
 5085            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 5086
 5087            let mut enclosing = None;
 5088            while let Some(pair_state) = regions.get(i) {
 5089                if pair_state.range.end.to_offset(buffer) < range.start {
 5090                    regions = ®ions[i + 1..];
 5091                    i = 0;
 5092                } else if pair_state.range.start.to_offset(buffer) > range.end {
 5093                    break;
 5094                } else {
 5095                    if pair_state.selection_id == selection.id {
 5096                        enclosing = Some(pair_state);
 5097                    }
 5098                    i += 1;
 5099                }
 5100            }
 5101
 5102            (selection, enclosing)
 5103        })
 5104    }
 5105
 5106    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 5107    fn invalidate_autoclose_regions(
 5108        &mut self,
 5109        mut selections: &[Selection<Anchor>],
 5110        buffer: &MultiBufferSnapshot,
 5111    ) {
 5112        self.autoclose_regions.retain(|state| {
 5113            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 5114                return false;
 5115            }
 5116
 5117            let mut i = 0;
 5118            while let Some(selection) = selections.get(i) {
 5119                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 5120                    selections = &selections[1..];
 5121                    continue;
 5122                }
 5123                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 5124                    break;
 5125                }
 5126                if selection.id == state.selection_id {
 5127                    return true;
 5128                } else {
 5129                    i += 1;
 5130                }
 5131            }
 5132            false
 5133        });
 5134    }
 5135
 5136    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5137        let offset = position.to_offset(buffer);
 5138        let (word_range, kind) =
 5139            buffer.surrounding_word(offset, Some(CharScopeContext::Completion));
 5140        if offset > word_range.start && kind == Some(CharKind::Word) {
 5141            Some(
 5142                buffer
 5143                    .text_for_range(word_range.start..offset)
 5144                    .collect::<String>(),
 5145            )
 5146        } else {
 5147            None
 5148        }
 5149    }
 5150
 5151    pub fn visible_excerpts(
 5152        &self,
 5153        cx: &mut Context<Editor>,
 5154    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5155        let Some(project) = self.project() else {
 5156            return HashMap::default();
 5157        };
 5158        let project = project.read(cx);
 5159        let multi_buffer = self.buffer().read(cx);
 5160        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5161        let multi_buffer_visible_start = self
 5162            .scroll_manager
 5163            .anchor()
 5164            .anchor
 5165            .to_point(&multi_buffer_snapshot);
 5166        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5167            multi_buffer_visible_start
 5168                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5169            Bias::Left,
 5170        );
 5171        multi_buffer_snapshot
 5172            .range_to_buffer_ranges(multi_buffer_visible_start..multi_buffer_visible_end)
 5173            .into_iter()
 5174            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5175            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5176                let buffer_file = project::File::from_dyn(buffer.file())?;
 5177                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5178                let worktree_entry = buffer_worktree
 5179                    .read(cx)
 5180                    .entry_for_id(buffer_file.project_entry_id()?)?;
 5181                if worktree_entry.is_ignored {
 5182                    None
 5183                } else {
 5184                    Some((
 5185                        excerpt_id,
 5186                        (
 5187                            multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5188                            buffer.version().clone(),
 5189                            excerpt_visible_range,
 5190                        ),
 5191                    ))
 5192                }
 5193            })
 5194            .collect()
 5195    }
 5196
 5197    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5198        TextLayoutDetails {
 5199            text_system: window.text_system().clone(),
 5200            editor_style: self.style.clone().unwrap(),
 5201            rem_size: window.rem_size(),
 5202            scroll_anchor: self.scroll_manager.anchor(),
 5203            visible_rows: self.visible_line_count(),
 5204            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5205        }
 5206    }
 5207
 5208    fn trigger_on_type_formatting(
 5209        &self,
 5210        input: String,
 5211        window: &mut Window,
 5212        cx: &mut Context<Self>,
 5213    ) -> Option<Task<Result<()>>> {
 5214        if input.len() != 1 {
 5215            return None;
 5216        }
 5217
 5218        let project = self.project()?;
 5219        let position = self.selections.newest_anchor().head();
 5220        let (buffer, buffer_position) = self
 5221            .buffer
 5222            .read(cx)
 5223            .text_anchor_for_position(position, cx)?;
 5224
 5225        let settings = language_settings::language_settings(
 5226            buffer
 5227                .read(cx)
 5228                .language_at(buffer_position)
 5229                .map(|l| l.name()),
 5230            buffer.read(cx).file(),
 5231            cx,
 5232        );
 5233        if !settings.use_on_type_format {
 5234            return None;
 5235        }
 5236
 5237        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5238        // hence we do LSP request & edit on host side only — add formats to host's history.
 5239        let push_to_lsp_host_history = true;
 5240        // If this is not the host, append its history with new edits.
 5241        let push_to_client_history = project.read(cx).is_via_collab();
 5242
 5243        let on_type_formatting = project.update(cx, |project, cx| {
 5244            project.on_type_format(
 5245                buffer.clone(),
 5246                buffer_position,
 5247                input,
 5248                push_to_lsp_host_history,
 5249                cx,
 5250            )
 5251        });
 5252        Some(cx.spawn_in(window, async move |editor, cx| {
 5253            if let Some(transaction) = on_type_formatting.await? {
 5254                if push_to_client_history {
 5255                    buffer
 5256                        .update(cx, |buffer, _| {
 5257                            buffer.push_transaction(transaction, Instant::now());
 5258                            buffer.finalize_last_transaction();
 5259                        })
 5260                        .ok();
 5261                }
 5262                editor.update(cx, |editor, cx| {
 5263                    editor.refresh_document_highlights(cx);
 5264                })?;
 5265            }
 5266            Ok(())
 5267        }))
 5268    }
 5269
 5270    pub fn show_word_completions(
 5271        &mut self,
 5272        _: &ShowWordCompletions,
 5273        window: &mut Window,
 5274        cx: &mut Context<Self>,
 5275    ) {
 5276        self.open_or_update_completions_menu(
 5277            Some(CompletionsMenuSource::Words {
 5278                ignore_threshold: true,
 5279            }),
 5280            None,
 5281            window,
 5282            cx,
 5283        );
 5284    }
 5285
 5286    pub fn show_completions(
 5287        &mut self,
 5288        options: &ShowCompletions,
 5289        window: &mut Window,
 5290        cx: &mut Context<Self>,
 5291    ) {
 5292        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5293    }
 5294
 5295    fn open_or_update_completions_menu(
 5296        &mut self,
 5297        requested_source: Option<CompletionsMenuSource>,
 5298        trigger: Option<&str>,
 5299        window: &mut Window,
 5300        cx: &mut Context<Self>,
 5301    ) {
 5302        if self.pending_rename.is_some() {
 5303            return;
 5304        }
 5305
 5306        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5307
 5308        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5309        // inserted and selected. To handle that case, the start of the selection is used so that
 5310        // the menu starts with all choices.
 5311        let position = self
 5312            .selections
 5313            .newest_anchor()
 5314            .start
 5315            .bias_right(&multibuffer_snapshot);
 5316        if position.diff_base_anchor.is_some() {
 5317            return;
 5318        }
 5319        let buffer_position = multibuffer_snapshot.anchor_before(position);
 5320        let Some(buffer) = buffer_position
 5321            .buffer_id
 5322            .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
 5323        else {
 5324            return;
 5325        };
 5326        let buffer_snapshot = buffer.read(cx).snapshot();
 5327
 5328        let query: Option<Arc<String>> =
 5329            Self::completion_query(&multibuffer_snapshot, buffer_position)
 5330                .map(|query| query.into());
 5331
 5332        drop(multibuffer_snapshot);
 5333
 5334        // Hide the current completions menu when query is empty. Without this, cached
 5335        // completions from before the trigger char may be reused (#32774).
 5336        if query.is_none() {
 5337            let menu_is_open = matches!(
 5338                self.context_menu.borrow().as_ref(),
 5339                Some(CodeContextMenu::Completions(_))
 5340            );
 5341            if menu_is_open {
 5342                self.hide_context_menu(window, cx);
 5343            }
 5344        }
 5345
 5346        let mut ignore_word_threshold = false;
 5347        let provider = match requested_source {
 5348            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5349            Some(CompletionsMenuSource::Words { ignore_threshold }) => {
 5350                ignore_word_threshold = ignore_threshold;
 5351                None
 5352            }
 5353            Some(CompletionsMenuSource::SnippetChoices) => {
 5354                log::error!("bug: SnippetChoices requested_source is not handled");
 5355                None
 5356            }
 5357        };
 5358
 5359        let sort_completions = provider
 5360            .as_ref()
 5361            .is_some_and(|provider| provider.sort_completions());
 5362
 5363        let filter_completions = provider
 5364            .as_ref()
 5365            .is_none_or(|provider| provider.filter_completions());
 5366
 5367        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5368            if filter_completions {
 5369                menu.filter(query.clone(), provider.clone(), window, cx);
 5370            }
 5371            // When `is_incomplete` is false, no need to re-query completions when the current query
 5372            // is a suffix of the initial query.
 5373            if !menu.is_incomplete {
 5374                // If the new query is a suffix of the old query (typing more characters) and
 5375                // the previous result was complete, the existing completions can be filtered.
 5376                //
 5377                // Note that this is always true for snippet completions.
 5378                let query_matches = match (&menu.initial_query, &query) {
 5379                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5380                    (None, _) => true,
 5381                    _ => false,
 5382                };
 5383                if query_matches {
 5384                    let position_matches = if menu.initial_position == position {
 5385                        true
 5386                    } else {
 5387                        let snapshot = self.buffer.read(cx).read(cx);
 5388                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5389                    };
 5390                    if position_matches {
 5391                        return;
 5392                    }
 5393                }
 5394            }
 5395        };
 5396
 5397        let trigger_kind = match trigger {
 5398            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5399                CompletionTriggerKind::TRIGGER_CHARACTER
 5400            }
 5401            _ => CompletionTriggerKind::INVOKED,
 5402        };
 5403        let completion_context = CompletionContext {
 5404            trigger_character: trigger.and_then(|trigger| {
 5405                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5406                    Some(String::from(trigger))
 5407                } else {
 5408                    None
 5409                }
 5410            }),
 5411            trigger_kind,
 5412        };
 5413
 5414        let Anchor {
 5415            excerpt_id: buffer_excerpt_id,
 5416            text_anchor: buffer_position,
 5417            ..
 5418        } = buffer_position;
 5419
 5420        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5421            buffer_snapshot.surrounding_word(buffer_position, None)
 5422        {
 5423            let word_to_exclude = buffer_snapshot
 5424                .text_for_range(word_range.clone())
 5425                .collect::<String>();
 5426            (
 5427                buffer_snapshot.anchor_before(word_range.start)
 5428                    ..buffer_snapshot.anchor_after(buffer_position),
 5429                Some(word_to_exclude),
 5430            )
 5431        } else {
 5432            (buffer_position..buffer_position, None)
 5433        };
 5434
 5435        let language = buffer_snapshot
 5436            .language_at(buffer_position)
 5437            .map(|language| language.name());
 5438
 5439        let completion_settings = language_settings(language.clone(), buffer_snapshot.file(), cx)
 5440            .completions
 5441            .clone();
 5442
 5443        let show_completion_documentation = buffer_snapshot
 5444            .settings_at(buffer_position, cx)
 5445            .show_completion_documentation;
 5446
 5447        // The document can be large, so stay in reasonable bounds when searching for words,
 5448        // otherwise completion pop-up might be slow to appear.
 5449        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5450        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5451        let min_word_search = buffer_snapshot.clip_point(
 5452            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5453            Bias::Left,
 5454        );
 5455        let max_word_search = buffer_snapshot.clip_point(
 5456            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5457            Bias::Right,
 5458        );
 5459        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5460            ..buffer_snapshot.point_to_offset(max_word_search);
 5461
 5462        let skip_digits = query
 5463            .as_ref()
 5464            .is_none_or(|query| !query.chars().any(|c| c.is_digit(10)));
 5465
 5466        let omit_word_completions = !self.word_completions_enabled
 5467            || (!ignore_word_threshold
 5468                && match &query {
 5469                    Some(query) => query.chars().count() < completion_settings.words_min_length,
 5470                    None => completion_settings.words_min_length != 0,
 5471                });
 5472
 5473        let (mut words, provider_responses) = match &provider {
 5474            Some(provider) => {
 5475                let provider_responses = provider.completions(
 5476                    buffer_excerpt_id,
 5477                    &buffer,
 5478                    buffer_position,
 5479                    completion_context,
 5480                    window,
 5481                    cx,
 5482                );
 5483
 5484                let words = match (omit_word_completions, completion_settings.words) {
 5485                    (true, _) | (_, WordsCompletionMode::Disabled) => {
 5486                        Task::ready(BTreeMap::default())
 5487                    }
 5488                    (false, WordsCompletionMode::Enabled | WordsCompletionMode::Fallback) => cx
 5489                        .background_spawn(async move {
 5490                            buffer_snapshot.words_in_range(WordsQuery {
 5491                                fuzzy_contents: None,
 5492                                range: word_search_range,
 5493                                skip_digits,
 5494                            })
 5495                        }),
 5496                };
 5497
 5498                (words, provider_responses)
 5499            }
 5500            None => {
 5501                let words = if omit_word_completions {
 5502                    Task::ready(BTreeMap::default())
 5503                } else {
 5504                    cx.background_spawn(async move {
 5505                        buffer_snapshot.words_in_range(WordsQuery {
 5506                            fuzzy_contents: None,
 5507                            range: word_search_range,
 5508                            skip_digits,
 5509                        })
 5510                    })
 5511                };
 5512                (words, Task::ready(Ok(Vec::new())))
 5513            }
 5514        };
 5515
 5516        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5517
 5518        let id = post_inc(&mut self.next_completion_id);
 5519        let task = cx.spawn_in(window, async move |editor, cx| {
 5520            let Ok(()) = editor.update(cx, |this, _| {
 5521                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5522            }) else {
 5523                return;
 5524            };
 5525
 5526            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5527            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5528            let mut completions = Vec::new();
 5529            let mut is_incomplete = false;
 5530            let mut display_options: Option<CompletionDisplayOptions> = None;
 5531            if let Some(provider_responses) = provider_responses.await.log_err()
 5532                && !provider_responses.is_empty()
 5533            {
 5534                for response in provider_responses {
 5535                    completions.extend(response.completions);
 5536                    is_incomplete = is_incomplete || response.is_incomplete;
 5537                    match display_options.as_mut() {
 5538                        None => {
 5539                            display_options = Some(response.display_options);
 5540                        }
 5541                        Some(options) => options.merge(&response.display_options),
 5542                    }
 5543                }
 5544                if completion_settings.words == WordsCompletionMode::Fallback {
 5545                    words = Task::ready(BTreeMap::default());
 5546                }
 5547            }
 5548            let display_options = display_options.unwrap_or_default();
 5549
 5550            let mut words = words.await;
 5551            if let Some(word_to_exclude) = &word_to_exclude {
 5552                words.remove(word_to_exclude);
 5553            }
 5554            for lsp_completion in &completions {
 5555                words.remove(&lsp_completion.new_text);
 5556            }
 5557            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5558                replace_range: word_replace_range.clone(),
 5559                new_text: word.clone(),
 5560                label: CodeLabel::plain(word, None),
 5561                icon_path: None,
 5562                documentation: None,
 5563                source: CompletionSource::BufferWord {
 5564                    word_range,
 5565                    resolved: false,
 5566                },
 5567                insert_text_mode: Some(InsertTextMode::AS_IS),
 5568                confirm: None,
 5569            }));
 5570
 5571            let menu = if completions.is_empty() {
 5572                None
 5573            } else {
 5574                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5575                    let languages = editor
 5576                        .workspace
 5577                        .as_ref()
 5578                        .and_then(|(workspace, _)| workspace.upgrade())
 5579                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5580                    let menu = CompletionsMenu::new(
 5581                        id,
 5582                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5583                        sort_completions,
 5584                        show_completion_documentation,
 5585                        position,
 5586                        query.clone(),
 5587                        is_incomplete,
 5588                        buffer.clone(),
 5589                        completions.into(),
 5590                        display_options,
 5591                        snippet_sort_order,
 5592                        languages,
 5593                        language,
 5594                        cx,
 5595                    );
 5596
 5597                    let query = if filter_completions { query } else { None };
 5598                    let matches_task = if let Some(query) = query {
 5599                        menu.do_async_filtering(query, cx)
 5600                    } else {
 5601                        Task::ready(menu.unfiltered_matches())
 5602                    };
 5603                    (menu, matches_task)
 5604                }) else {
 5605                    return;
 5606                };
 5607
 5608                let matches = matches_task.await;
 5609
 5610                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5611                    // Newer menu already set, so exit.
 5612                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5613                        editor.context_menu.borrow().as_ref()
 5614                        && prev_menu.id > id
 5615                    {
 5616                        return;
 5617                    };
 5618
 5619                    // Only valid to take prev_menu because it the new menu is immediately set
 5620                    // below, or the menu is hidden.
 5621                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5622                        editor.context_menu.borrow_mut().take()
 5623                    {
 5624                        let position_matches =
 5625                            if prev_menu.initial_position == menu.initial_position {
 5626                                true
 5627                            } else {
 5628                                let snapshot = editor.buffer.read(cx).read(cx);
 5629                                prev_menu.initial_position.to_offset(&snapshot)
 5630                                    == menu.initial_position.to_offset(&snapshot)
 5631                            };
 5632                        if position_matches {
 5633                            // Preserve markdown cache before `set_filter_results` because it will
 5634                            // try to populate the documentation cache.
 5635                            menu.preserve_markdown_cache(prev_menu);
 5636                        }
 5637                    };
 5638
 5639                    menu.set_filter_results(matches, provider, window, cx);
 5640                }) else {
 5641                    return;
 5642                };
 5643
 5644                menu.visible().then_some(menu)
 5645            };
 5646
 5647            editor
 5648                .update_in(cx, |editor, window, cx| {
 5649                    if editor.focus_handle.is_focused(window)
 5650                        && let Some(menu) = menu
 5651                    {
 5652                        *editor.context_menu.borrow_mut() =
 5653                            Some(CodeContextMenu::Completions(menu));
 5654
 5655                        crate::hover_popover::hide_hover(editor, cx);
 5656                        if editor.show_edit_predictions_in_menu() {
 5657                            editor.update_visible_edit_prediction(window, cx);
 5658                        } else {
 5659                            editor.discard_edit_prediction(false, cx);
 5660                        }
 5661
 5662                        cx.notify();
 5663                        return;
 5664                    }
 5665
 5666                    if editor.completion_tasks.len() <= 1 {
 5667                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5668                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5669                        // If it was already hidden and we don't show edit predictions in the menu,
 5670                        // we should also show the edit prediction when available.
 5671                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5672                            editor.update_visible_edit_prediction(window, cx);
 5673                        }
 5674                    }
 5675                })
 5676                .ok();
 5677        });
 5678
 5679        self.completion_tasks.push((id, task));
 5680    }
 5681
 5682    #[cfg(feature = "test-support")]
 5683    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5684        let menu = self.context_menu.borrow();
 5685        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5686            let completions = menu.completions.borrow();
 5687            Some(completions.to_vec())
 5688        } else {
 5689            None
 5690        }
 5691    }
 5692
 5693    pub fn with_completions_menu_matching_id<R>(
 5694        &self,
 5695        id: CompletionId,
 5696        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5697    ) -> R {
 5698        let mut context_menu = self.context_menu.borrow_mut();
 5699        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5700            return f(None);
 5701        };
 5702        if completions_menu.id != id {
 5703            return f(None);
 5704        }
 5705        f(Some(completions_menu))
 5706    }
 5707
 5708    pub fn confirm_completion(
 5709        &mut self,
 5710        action: &ConfirmCompletion,
 5711        window: &mut Window,
 5712        cx: &mut Context<Self>,
 5713    ) -> Option<Task<Result<()>>> {
 5714        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5715        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5716    }
 5717
 5718    pub fn confirm_completion_insert(
 5719        &mut self,
 5720        _: &ConfirmCompletionInsert,
 5721        window: &mut Window,
 5722        cx: &mut Context<Self>,
 5723    ) -> Option<Task<Result<()>>> {
 5724        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5725        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5726    }
 5727
 5728    pub fn confirm_completion_replace(
 5729        &mut self,
 5730        _: &ConfirmCompletionReplace,
 5731        window: &mut Window,
 5732        cx: &mut Context<Self>,
 5733    ) -> Option<Task<Result<()>>> {
 5734        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5735        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5736    }
 5737
 5738    pub fn compose_completion(
 5739        &mut self,
 5740        action: &ComposeCompletion,
 5741        window: &mut Window,
 5742        cx: &mut Context<Self>,
 5743    ) -> Option<Task<Result<()>>> {
 5744        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5745        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5746    }
 5747
 5748    fn do_completion(
 5749        &mut self,
 5750        item_ix: Option<usize>,
 5751        intent: CompletionIntent,
 5752        window: &mut Window,
 5753        cx: &mut Context<Editor>,
 5754    ) -> Option<Task<Result<()>>> {
 5755        use language::ToOffset as _;
 5756
 5757        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5758        else {
 5759            return None;
 5760        };
 5761
 5762        let candidate_id = {
 5763            let entries = completions_menu.entries.borrow();
 5764            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5765            if self.show_edit_predictions_in_menu() {
 5766                self.discard_edit_prediction(true, cx);
 5767            }
 5768            mat.candidate_id
 5769        };
 5770
 5771        let completion = completions_menu
 5772            .completions
 5773            .borrow()
 5774            .get(candidate_id)?
 5775            .clone();
 5776        cx.stop_propagation();
 5777
 5778        let buffer_handle = completions_menu.buffer.clone();
 5779
 5780        let CompletionEdit {
 5781            new_text,
 5782            snippet,
 5783            replace_range,
 5784        } = process_completion_for_edit(
 5785            &completion,
 5786            intent,
 5787            &buffer_handle,
 5788            &completions_menu.initial_position.text_anchor,
 5789            cx,
 5790        );
 5791
 5792        let buffer = buffer_handle.read(cx);
 5793        let snapshot = self.buffer.read(cx).snapshot(cx);
 5794        let newest_anchor = self.selections.newest_anchor();
 5795        let replace_range_multibuffer = {
 5796            let mut excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5797            excerpt.map_range_from_buffer(replace_range.clone())
 5798        };
 5799        if snapshot.buffer_id_for_anchor(newest_anchor.head()) != Some(buffer.remote_id()) {
 5800            return None;
 5801        }
 5802
 5803        let old_text = buffer
 5804            .text_for_range(replace_range.clone())
 5805            .collect::<String>();
 5806        let lookbehind = newest_anchor
 5807            .start
 5808            .text_anchor
 5809            .to_offset(buffer)
 5810            .saturating_sub(replace_range.start);
 5811        let lookahead = replace_range
 5812            .end
 5813            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5814        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5815        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5816
 5817        let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 5818        let mut ranges = Vec::new();
 5819        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5820
 5821        for selection in &selections {
 5822            let range = if selection.id == newest_anchor.id {
 5823                replace_range_multibuffer.clone()
 5824            } else {
 5825                let mut range = selection.range();
 5826
 5827                // if prefix is present, don't duplicate it
 5828                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5829                    range.start = range.start.saturating_sub(lookbehind);
 5830
 5831                    // if suffix is also present, mimic the newest cursor and replace it
 5832                    if selection.id != newest_anchor.id
 5833                        && snapshot.contains_str_at(range.end, suffix)
 5834                    {
 5835                        range.end += lookahead;
 5836                    }
 5837                }
 5838                range
 5839            };
 5840
 5841            ranges.push(range.clone());
 5842
 5843            if !self.linked_edit_ranges.is_empty() {
 5844                let start_anchor = snapshot.anchor_before(range.start);
 5845                let end_anchor = snapshot.anchor_after(range.end);
 5846                if let Some(ranges) = self
 5847                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 5848                {
 5849                    for (buffer, edits) in ranges {
 5850                        linked_edits
 5851                            .entry(buffer.clone())
 5852                            .or_default()
 5853                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 5854                    }
 5855                }
 5856            }
 5857        }
 5858
 5859        let common_prefix_len = old_text
 5860            .chars()
 5861            .zip(new_text.chars())
 5862            .take_while(|(a, b)| a == b)
 5863            .map(|(a, _)| a.len_utf8())
 5864            .sum::<usize>();
 5865
 5866        cx.emit(EditorEvent::InputHandled {
 5867            utf16_range_to_replace: None,
 5868            text: new_text[common_prefix_len..].into(),
 5869        });
 5870
 5871        self.transact(window, cx, |editor, window, cx| {
 5872            if let Some(mut snippet) = snippet {
 5873                snippet.text = new_text.to_string();
 5874                editor
 5875                    .insert_snippet(&ranges, snippet, window, cx)
 5876                    .log_err();
 5877            } else {
 5878                editor.buffer.update(cx, |multi_buffer, cx| {
 5879                    let auto_indent = match completion.insert_text_mode {
 5880                        Some(InsertTextMode::AS_IS) => None,
 5881                        _ => editor.autoindent_mode.clone(),
 5882                    };
 5883                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 5884                    multi_buffer.edit(edits, auto_indent, cx);
 5885                });
 5886            }
 5887            for (buffer, edits) in linked_edits {
 5888                buffer.update(cx, |buffer, cx| {
 5889                    let snapshot = buffer.snapshot();
 5890                    let edits = edits
 5891                        .into_iter()
 5892                        .map(|(range, text)| {
 5893                            use text::ToPoint as TP;
 5894                            let end_point = TP::to_point(&range.end, &snapshot);
 5895                            let start_point = TP::to_point(&range.start, &snapshot);
 5896                            (start_point..end_point, text)
 5897                        })
 5898                        .sorted_by_key(|(range, _)| range.start);
 5899                    buffer.edit(edits, None, cx);
 5900                })
 5901            }
 5902
 5903            editor.refresh_edit_prediction(true, false, window, cx);
 5904        });
 5905        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors_arc(), &snapshot);
 5906
 5907        let show_new_completions_on_confirm = completion
 5908            .confirm
 5909            .as_ref()
 5910            .is_some_and(|confirm| confirm(intent, window, cx));
 5911        if show_new_completions_on_confirm {
 5912            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 5913        }
 5914
 5915        let provider = self.completion_provider.as_ref()?;
 5916        drop(completion);
 5917        let apply_edits = provider.apply_additional_edits_for_completion(
 5918            buffer_handle,
 5919            completions_menu.completions.clone(),
 5920            candidate_id,
 5921            true,
 5922            cx,
 5923        );
 5924
 5925        let editor_settings = EditorSettings::get_global(cx);
 5926        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 5927            // After the code completion is finished, users often want to know what signatures are needed.
 5928            // so we should automatically call signature_help
 5929            self.show_signature_help(&ShowSignatureHelp, window, cx);
 5930        }
 5931
 5932        Some(cx.foreground_executor().spawn(async move {
 5933            apply_edits.await?;
 5934            Ok(())
 5935        }))
 5936    }
 5937
 5938    pub fn toggle_code_actions(
 5939        &mut self,
 5940        action: &ToggleCodeActions,
 5941        window: &mut Window,
 5942        cx: &mut Context<Self>,
 5943    ) {
 5944        let quick_launch = action.quick_launch;
 5945        let mut context_menu = self.context_menu.borrow_mut();
 5946        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 5947            if code_actions.deployed_from == action.deployed_from {
 5948                // Toggle if we're selecting the same one
 5949                *context_menu = None;
 5950                cx.notify();
 5951                return;
 5952            } else {
 5953                // Otherwise, clear it and start a new one
 5954                *context_menu = None;
 5955                cx.notify();
 5956            }
 5957        }
 5958        drop(context_menu);
 5959        let snapshot = self.snapshot(window, cx);
 5960        let deployed_from = action.deployed_from.clone();
 5961        let action = action.clone();
 5962        self.completion_tasks.clear();
 5963        self.discard_edit_prediction(false, cx);
 5964
 5965        let multibuffer_point = match &action.deployed_from {
 5966            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 5967                DisplayPoint::new(*row, 0).to_point(&snapshot)
 5968            }
 5969            _ => self
 5970                .selections
 5971                .newest::<Point>(&snapshot.display_snapshot)
 5972                .head(),
 5973        };
 5974        let Some((buffer, buffer_row)) = snapshot
 5975            .buffer_snapshot()
 5976            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 5977            .and_then(|(buffer_snapshot, range)| {
 5978                self.buffer()
 5979                    .read(cx)
 5980                    .buffer(buffer_snapshot.remote_id())
 5981                    .map(|buffer| (buffer, range.start.row))
 5982            })
 5983        else {
 5984            return;
 5985        };
 5986        let buffer_id = buffer.read(cx).remote_id();
 5987        let tasks = self
 5988            .tasks
 5989            .get(&(buffer_id, buffer_row))
 5990            .map(|t| Arc::new(t.to_owned()));
 5991
 5992        if !self.focus_handle.is_focused(window) {
 5993            return;
 5994        }
 5995        let project = self.project.clone();
 5996
 5997        let code_actions_task = match deployed_from {
 5998            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 5999            _ => self.code_actions(buffer_row, window, cx),
 6000        };
 6001
 6002        let runnable_task = match deployed_from {
 6003            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6004            _ => {
 6005                let mut task_context_task = Task::ready(None);
 6006                if let Some(tasks) = &tasks
 6007                    && let Some(project) = project
 6008                {
 6009                    task_context_task =
 6010                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6011                }
 6012
 6013                cx.spawn_in(window, {
 6014                    let buffer = buffer.clone();
 6015                    async move |editor, cx| {
 6016                        let task_context = task_context_task.await;
 6017
 6018                        let resolved_tasks =
 6019                            tasks
 6020                                .zip(task_context.clone())
 6021                                .map(|(tasks, task_context)| ResolvedTasks {
 6022                                    templates: tasks.resolve(&task_context).collect(),
 6023                                    position: snapshot.buffer_snapshot().anchor_before(Point::new(
 6024                                        multibuffer_point.row,
 6025                                        tasks.column,
 6026                                    )),
 6027                                });
 6028                        let debug_scenarios = editor
 6029                            .update(cx, |editor, cx| {
 6030                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6031                            })?
 6032                            .await;
 6033                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6034                    }
 6035                })
 6036            }
 6037        };
 6038
 6039        cx.spawn_in(window, async move |editor, cx| {
 6040            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6041            let code_actions = code_actions_task.await;
 6042            let spawn_straight_away = quick_launch
 6043                && resolved_tasks
 6044                    .as_ref()
 6045                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6046                && code_actions
 6047                    .as_ref()
 6048                    .is_none_or(|actions| actions.is_empty())
 6049                && debug_scenarios.is_empty();
 6050
 6051            editor.update_in(cx, |editor, window, cx| {
 6052                crate::hover_popover::hide_hover(editor, cx);
 6053                let actions = CodeActionContents::new(
 6054                    resolved_tasks,
 6055                    code_actions,
 6056                    debug_scenarios,
 6057                    task_context.unwrap_or_default(),
 6058                );
 6059
 6060                // Don't show the menu if there are no actions available
 6061                if actions.is_empty() {
 6062                    cx.notify();
 6063                    return Task::ready(Ok(()));
 6064                }
 6065
 6066                *editor.context_menu.borrow_mut() =
 6067                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6068                        buffer,
 6069                        actions,
 6070                        selected_item: Default::default(),
 6071                        scroll_handle: UniformListScrollHandle::default(),
 6072                        deployed_from,
 6073                    }));
 6074                cx.notify();
 6075                if spawn_straight_away
 6076                    && let Some(task) = editor.confirm_code_action(
 6077                        &ConfirmCodeAction { item_ix: Some(0) },
 6078                        window,
 6079                        cx,
 6080                    )
 6081                {
 6082                    return task;
 6083                }
 6084
 6085                Task::ready(Ok(()))
 6086            })
 6087        })
 6088        .detach_and_log_err(cx);
 6089    }
 6090
 6091    fn debug_scenarios(
 6092        &mut self,
 6093        resolved_tasks: &Option<ResolvedTasks>,
 6094        buffer: &Entity<Buffer>,
 6095        cx: &mut App,
 6096    ) -> Task<Vec<task::DebugScenario>> {
 6097        maybe!({
 6098            let project = self.project()?;
 6099            let dap_store = project.read(cx).dap_store();
 6100            let mut scenarios = vec![];
 6101            let resolved_tasks = resolved_tasks.as_ref()?;
 6102            let buffer = buffer.read(cx);
 6103            let language = buffer.language()?;
 6104            let file = buffer.file();
 6105            let debug_adapter = language_settings(language.name().into(), file, cx)
 6106                .debuggers
 6107                .first()
 6108                .map(SharedString::from)
 6109                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6110
 6111            dap_store.update(cx, |dap_store, cx| {
 6112                for (_, task) in &resolved_tasks.templates {
 6113                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6114                        task.original_task().clone(),
 6115                        debug_adapter.clone().into(),
 6116                        task.display_label().to_owned().into(),
 6117                        cx,
 6118                    );
 6119                    scenarios.push(maybe_scenario);
 6120                }
 6121            });
 6122            Some(cx.background_spawn(async move {
 6123                futures::future::join_all(scenarios)
 6124                    .await
 6125                    .into_iter()
 6126                    .flatten()
 6127                    .collect::<Vec<_>>()
 6128            }))
 6129        })
 6130        .unwrap_or_else(|| Task::ready(vec![]))
 6131    }
 6132
 6133    fn code_actions(
 6134        &mut self,
 6135        buffer_row: u32,
 6136        window: &mut Window,
 6137        cx: &mut Context<Self>,
 6138    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6139        let mut task = self.code_actions_task.take();
 6140        cx.spawn_in(window, async move |editor, cx| {
 6141            while let Some(prev_task) = task {
 6142                prev_task.await.log_err();
 6143                task = editor
 6144                    .update(cx, |this, _| this.code_actions_task.take())
 6145                    .ok()?;
 6146            }
 6147
 6148            editor
 6149                .update(cx, |editor, cx| {
 6150                    editor
 6151                        .available_code_actions
 6152                        .clone()
 6153                        .and_then(|(location, code_actions)| {
 6154                            let snapshot = location.buffer.read(cx).snapshot();
 6155                            let point_range = location.range.to_point(&snapshot);
 6156                            let point_range = point_range.start.row..=point_range.end.row;
 6157                            if point_range.contains(&buffer_row) {
 6158                                Some(code_actions)
 6159                            } else {
 6160                                None
 6161                            }
 6162                        })
 6163                })
 6164                .ok()
 6165                .flatten()
 6166        })
 6167    }
 6168
 6169    pub fn confirm_code_action(
 6170        &mut self,
 6171        action: &ConfirmCodeAction,
 6172        window: &mut Window,
 6173        cx: &mut Context<Self>,
 6174    ) -> Option<Task<Result<()>>> {
 6175        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6176
 6177        let actions_menu =
 6178            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6179                menu
 6180            } else {
 6181                return None;
 6182            };
 6183
 6184        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6185        let action = actions_menu.actions.get(action_ix)?;
 6186        let title = action.label();
 6187        let buffer = actions_menu.buffer;
 6188        let workspace = self.workspace()?;
 6189
 6190        match action {
 6191            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6192                workspace.update(cx, |workspace, cx| {
 6193                    workspace.schedule_resolved_task(
 6194                        task_source_kind,
 6195                        resolved_task,
 6196                        false,
 6197                        window,
 6198                        cx,
 6199                    );
 6200
 6201                    Some(Task::ready(Ok(())))
 6202                })
 6203            }
 6204            CodeActionsItem::CodeAction {
 6205                excerpt_id,
 6206                action,
 6207                provider,
 6208            } => {
 6209                let apply_code_action =
 6210                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6211                let workspace = workspace.downgrade();
 6212                Some(cx.spawn_in(window, async move |editor, cx| {
 6213                    let project_transaction = apply_code_action.await?;
 6214                    Self::open_project_transaction(
 6215                        &editor,
 6216                        workspace,
 6217                        project_transaction,
 6218                        title,
 6219                        cx,
 6220                    )
 6221                    .await
 6222                }))
 6223            }
 6224            CodeActionsItem::DebugScenario(scenario) => {
 6225                let context = actions_menu.actions.context;
 6226
 6227                workspace.update(cx, |workspace, cx| {
 6228                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6229                    workspace.start_debug_session(
 6230                        scenario,
 6231                        context,
 6232                        Some(buffer),
 6233                        None,
 6234                        window,
 6235                        cx,
 6236                    );
 6237                });
 6238                Some(Task::ready(Ok(())))
 6239            }
 6240        }
 6241    }
 6242
 6243    pub async fn open_project_transaction(
 6244        editor: &WeakEntity<Editor>,
 6245        workspace: WeakEntity<Workspace>,
 6246        transaction: ProjectTransaction,
 6247        title: String,
 6248        cx: &mut AsyncWindowContext,
 6249    ) -> Result<()> {
 6250        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6251        cx.update(|_, cx| {
 6252            entries.sort_unstable_by_key(|(buffer, _)| {
 6253                buffer.read(cx).file().map(|f| f.path().clone())
 6254            });
 6255        })?;
 6256        if entries.is_empty() {
 6257            return Ok(());
 6258        }
 6259
 6260        // If the project transaction's edits are all contained within this editor, then
 6261        // avoid opening a new editor to display them.
 6262
 6263        if let [(buffer, transaction)] = &*entries {
 6264            let excerpt = editor.update(cx, |editor, cx| {
 6265                editor
 6266                    .buffer()
 6267                    .read(cx)
 6268                    .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6269            })?;
 6270            if let Some((_, excerpted_buffer, excerpt_range)) = excerpt
 6271                && excerpted_buffer == *buffer
 6272            {
 6273                let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6274                    let excerpt_range = excerpt_range.to_offset(buffer);
 6275                    buffer
 6276                        .edited_ranges_for_transaction::<usize>(transaction)
 6277                        .all(|range| {
 6278                            excerpt_range.start <= range.start && excerpt_range.end >= range.end
 6279                        })
 6280                })?;
 6281
 6282                if all_edits_within_excerpt {
 6283                    return Ok(());
 6284                }
 6285            }
 6286        }
 6287
 6288        let mut ranges_to_highlight = Vec::new();
 6289        let excerpt_buffer = cx.new(|cx| {
 6290            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6291            for (buffer_handle, transaction) in &entries {
 6292                let edited_ranges = buffer_handle
 6293                    .read(cx)
 6294                    .edited_ranges_for_transaction::<Point>(transaction)
 6295                    .collect::<Vec<_>>();
 6296                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6297                    PathKey::for_buffer(buffer_handle, cx),
 6298                    buffer_handle.clone(),
 6299                    edited_ranges,
 6300                    multibuffer_context_lines(cx),
 6301                    cx,
 6302                );
 6303
 6304                ranges_to_highlight.extend(ranges);
 6305            }
 6306            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6307            multibuffer
 6308        })?;
 6309
 6310        workspace.update_in(cx, |workspace, window, cx| {
 6311            let project = workspace.project().clone();
 6312            let editor =
 6313                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6314            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6315            editor.update(cx, |editor, cx| {
 6316                editor.highlight_background::<Self>(
 6317                    &ranges_to_highlight,
 6318                    |theme| theme.colors().editor_highlighted_line_background,
 6319                    cx,
 6320                );
 6321            });
 6322        })?;
 6323
 6324        Ok(())
 6325    }
 6326
 6327    pub fn clear_code_action_providers(&mut self) {
 6328        self.code_action_providers.clear();
 6329        self.available_code_actions.take();
 6330    }
 6331
 6332    pub fn add_code_action_provider(
 6333        &mut self,
 6334        provider: Rc<dyn CodeActionProvider>,
 6335        window: &mut Window,
 6336        cx: &mut Context<Self>,
 6337    ) {
 6338        if self
 6339            .code_action_providers
 6340            .iter()
 6341            .any(|existing_provider| existing_provider.id() == provider.id())
 6342        {
 6343            return;
 6344        }
 6345
 6346        self.code_action_providers.push(provider);
 6347        self.refresh_code_actions(window, cx);
 6348    }
 6349
 6350    pub fn remove_code_action_provider(
 6351        &mut self,
 6352        id: Arc<str>,
 6353        window: &mut Window,
 6354        cx: &mut Context<Self>,
 6355    ) {
 6356        self.code_action_providers
 6357            .retain(|provider| provider.id() != id);
 6358        self.refresh_code_actions(window, cx);
 6359    }
 6360
 6361    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6362        !self.code_action_providers.is_empty()
 6363            && EditorSettings::get_global(cx).toolbar.code_actions
 6364    }
 6365
 6366    pub fn has_available_code_actions(&self) -> bool {
 6367        self.available_code_actions
 6368            .as_ref()
 6369            .is_some_and(|(_, actions)| !actions.is_empty())
 6370    }
 6371
 6372    fn render_inline_code_actions(
 6373        &self,
 6374        icon_size: ui::IconSize,
 6375        display_row: DisplayRow,
 6376        is_active: bool,
 6377        cx: &mut Context<Self>,
 6378    ) -> AnyElement {
 6379        let show_tooltip = !self.context_menu_visible();
 6380        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6381            .icon_size(icon_size)
 6382            .shape(ui::IconButtonShape::Square)
 6383            .icon_color(ui::Color::Hidden)
 6384            .toggle_state(is_active)
 6385            .when(show_tooltip, |this| {
 6386                this.tooltip({
 6387                    let focus_handle = self.focus_handle.clone();
 6388                    move |_window, cx| {
 6389                        Tooltip::for_action_in(
 6390                            "Toggle Code Actions",
 6391                            &ToggleCodeActions {
 6392                                deployed_from: None,
 6393                                quick_launch: false,
 6394                            },
 6395                            &focus_handle,
 6396                            cx,
 6397                        )
 6398                    }
 6399                })
 6400            })
 6401            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6402                window.focus(&editor.focus_handle(cx));
 6403                editor.toggle_code_actions(
 6404                    &crate::actions::ToggleCodeActions {
 6405                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6406                            display_row,
 6407                        )),
 6408                        quick_launch: false,
 6409                    },
 6410                    window,
 6411                    cx,
 6412                );
 6413            }))
 6414            .into_any_element()
 6415    }
 6416
 6417    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6418        &self.context_menu
 6419    }
 6420
 6421    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6422        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6423            cx.background_executor()
 6424                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6425                .await;
 6426
 6427            let (start_buffer, start, _, end, newest_selection) = this
 6428                .update(cx, |this, cx| {
 6429                    let newest_selection = this.selections.newest_anchor().clone();
 6430                    if newest_selection.head().diff_base_anchor.is_some() {
 6431                        return None;
 6432                    }
 6433                    let display_snapshot = this.display_snapshot(cx);
 6434                    let newest_selection_adjusted =
 6435                        this.selections.newest_adjusted(&display_snapshot);
 6436                    let buffer = this.buffer.read(cx);
 6437
 6438                    let (start_buffer, start) =
 6439                        buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6440                    let (end_buffer, end) =
 6441                        buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6442
 6443                    Some((start_buffer, start, end_buffer, end, newest_selection))
 6444                })?
 6445                .filter(|(start_buffer, _, end_buffer, _, _)| start_buffer == end_buffer)
 6446                .context(
 6447                    "Expected selection to lie in a single buffer when refreshing code actions",
 6448                )?;
 6449            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6450                let providers = this.code_action_providers.clone();
 6451                let tasks = this
 6452                    .code_action_providers
 6453                    .iter()
 6454                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6455                    .collect::<Vec<_>>();
 6456                (providers, tasks)
 6457            })?;
 6458
 6459            let mut actions = Vec::new();
 6460            for (provider, provider_actions) in
 6461                providers.into_iter().zip(future::join_all(tasks).await)
 6462            {
 6463                if let Some(provider_actions) = provider_actions.log_err() {
 6464                    actions.extend(provider_actions.into_iter().map(|action| {
 6465                        AvailableCodeAction {
 6466                            excerpt_id: newest_selection.start.excerpt_id,
 6467                            action,
 6468                            provider: provider.clone(),
 6469                        }
 6470                    }));
 6471                }
 6472            }
 6473
 6474            this.update(cx, |this, cx| {
 6475                this.available_code_actions = if actions.is_empty() {
 6476                    None
 6477                } else {
 6478                    Some((
 6479                        Location {
 6480                            buffer: start_buffer,
 6481                            range: start..end,
 6482                        },
 6483                        actions.into(),
 6484                    ))
 6485                };
 6486                cx.notify();
 6487            })
 6488        }));
 6489    }
 6490
 6491    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6492        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6493            self.show_git_blame_inline = false;
 6494
 6495            self.show_git_blame_inline_delay_task =
 6496                Some(cx.spawn_in(window, async move |this, cx| {
 6497                    cx.background_executor().timer(delay).await;
 6498
 6499                    this.update(cx, |this, cx| {
 6500                        this.show_git_blame_inline = true;
 6501                        cx.notify();
 6502                    })
 6503                    .log_err();
 6504                }));
 6505        }
 6506    }
 6507
 6508    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6509        let snapshot = self.snapshot(window, cx);
 6510        let cursor = self
 6511            .selections
 6512            .newest::<Point>(&snapshot.display_snapshot)
 6513            .head();
 6514        let Some((buffer, point, _)) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)
 6515        else {
 6516            return;
 6517        };
 6518
 6519        let Some(blame) = self.blame.as_ref() else {
 6520            return;
 6521        };
 6522
 6523        let row_info = RowInfo {
 6524            buffer_id: Some(buffer.remote_id()),
 6525            buffer_row: Some(point.row),
 6526            ..Default::default()
 6527        };
 6528        let Some((buffer, blame_entry)) = blame
 6529            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6530            .flatten()
 6531        else {
 6532            return;
 6533        };
 6534
 6535        let anchor = self.selections.newest_anchor().head();
 6536        let position = self.to_pixel_point(anchor, &snapshot, window);
 6537        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6538            self.show_blame_popover(
 6539                buffer,
 6540                &blame_entry,
 6541                position + last_bounds.origin,
 6542                true,
 6543                cx,
 6544            );
 6545        };
 6546    }
 6547
 6548    fn show_blame_popover(
 6549        &mut self,
 6550        buffer: BufferId,
 6551        blame_entry: &BlameEntry,
 6552        position: gpui::Point<Pixels>,
 6553        ignore_timeout: bool,
 6554        cx: &mut Context<Self>,
 6555    ) {
 6556        if let Some(state) = &mut self.inline_blame_popover {
 6557            state.hide_task.take();
 6558        } else {
 6559            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay.0;
 6560            let blame_entry = blame_entry.clone();
 6561            let show_task = cx.spawn(async move |editor, cx| {
 6562                if !ignore_timeout {
 6563                    cx.background_executor()
 6564                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6565                        .await;
 6566                }
 6567                editor
 6568                    .update(cx, |editor, cx| {
 6569                        editor.inline_blame_popover_show_task.take();
 6570                        let Some(blame) = editor.blame.as_ref() else {
 6571                            return;
 6572                        };
 6573                        let blame = blame.read(cx);
 6574                        let details = blame.details_for_entry(buffer, &blame_entry);
 6575                        let markdown = cx.new(|cx| {
 6576                            Markdown::new(
 6577                                details
 6578                                    .as_ref()
 6579                                    .map(|message| message.message.clone())
 6580                                    .unwrap_or_default(),
 6581                                None,
 6582                                None,
 6583                                cx,
 6584                            )
 6585                        });
 6586                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6587                            position,
 6588                            hide_task: None,
 6589                            popover_bounds: None,
 6590                            popover_state: InlineBlamePopoverState {
 6591                                scroll_handle: ScrollHandle::new(),
 6592                                commit_message: details,
 6593                                markdown,
 6594                            },
 6595                            keyboard_grace: ignore_timeout,
 6596                        });
 6597                        cx.notify();
 6598                    })
 6599                    .ok();
 6600            });
 6601            self.inline_blame_popover_show_task = Some(show_task);
 6602        }
 6603    }
 6604
 6605    fn hide_blame_popover(&mut self, ignore_timeout: bool, cx: &mut Context<Self>) -> bool {
 6606        self.inline_blame_popover_show_task.take();
 6607        if let Some(state) = &mut self.inline_blame_popover {
 6608            let hide_task = cx.spawn(async move |editor, cx| {
 6609                if !ignore_timeout {
 6610                    cx.background_executor()
 6611                        .timer(std::time::Duration::from_millis(100))
 6612                        .await;
 6613                }
 6614                editor
 6615                    .update(cx, |editor, cx| {
 6616                        editor.inline_blame_popover.take();
 6617                        cx.notify();
 6618                    })
 6619                    .ok();
 6620            });
 6621            state.hide_task = Some(hide_task);
 6622            true
 6623        } else {
 6624            false
 6625        }
 6626    }
 6627
 6628    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6629        if self.pending_rename.is_some() {
 6630            return None;
 6631        }
 6632
 6633        let provider = self.semantics_provider.clone()?;
 6634        let buffer = self.buffer.read(cx);
 6635        let newest_selection = self.selections.newest_anchor().clone();
 6636        let cursor_position = newest_selection.head();
 6637        let (cursor_buffer, cursor_buffer_position) =
 6638            buffer.text_anchor_for_position(cursor_position, cx)?;
 6639        let (tail_buffer, tail_buffer_position) =
 6640            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6641        if cursor_buffer != tail_buffer {
 6642            return None;
 6643        }
 6644
 6645        let snapshot = cursor_buffer.read(cx).snapshot();
 6646        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, None);
 6647        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, None);
 6648        if start_word_range != end_word_range {
 6649            self.document_highlights_task.take();
 6650            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6651            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6652            return None;
 6653        }
 6654
 6655        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce.0;
 6656        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6657            cx.background_executor()
 6658                .timer(Duration::from_millis(debounce))
 6659                .await;
 6660
 6661            let highlights = if let Some(highlights) = cx
 6662                .update(|cx| {
 6663                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6664                })
 6665                .ok()
 6666                .flatten()
 6667            {
 6668                highlights.await.log_err()
 6669            } else {
 6670                None
 6671            };
 6672
 6673            if let Some(highlights) = highlights {
 6674                this.update(cx, |this, cx| {
 6675                    if this.pending_rename.is_some() {
 6676                        return;
 6677                    }
 6678
 6679                    let buffer = this.buffer.read(cx);
 6680                    if buffer
 6681                        .text_anchor_for_position(cursor_position, cx)
 6682                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 6683                    {
 6684                        return;
 6685                    }
 6686
 6687                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6688                    let mut write_ranges = Vec::new();
 6689                    let mut read_ranges = Vec::new();
 6690                    for highlight in highlights {
 6691                        let buffer_id = cursor_buffer.read(cx).remote_id();
 6692                        for (excerpt_id, excerpt_range) in buffer.excerpts_for_buffer(buffer_id, cx)
 6693                        {
 6694                            let start = highlight
 6695                                .range
 6696                                .start
 6697                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6698                            let end = highlight
 6699                                .range
 6700                                .end
 6701                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6702                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6703                                continue;
 6704                            }
 6705
 6706                            let range =
 6707                                Anchor::range_in_buffer(excerpt_id, buffer_id, *start..*end);
 6708                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6709                                write_ranges.push(range);
 6710                            } else {
 6711                                read_ranges.push(range);
 6712                            }
 6713                        }
 6714                    }
 6715
 6716                    this.highlight_background::<DocumentHighlightRead>(
 6717                        &read_ranges,
 6718                        |theme| theme.colors().editor_document_highlight_read_background,
 6719                        cx,
 6720                    );
 6721                    this.highlight_background::<DocumentHighlightWrite>(
 6722                        &write_ranges,
 6723                        |theme| theme.colors().editor_document_highlight_write_background,
 6724                        cx,
 6725                    );
 6726                    cx.notify();
 6727                })
 6728                .log_err();
 6729            }
 6730        }));
 6731        None
 6732    }
 6733
 6734    fn prepare_highlight_query_from_selection(
 6735        &mut self,
 6736        window: &Window,
 6737        cx: &mut Context<Editor>,
 6738    ) -> Option<(String, Range<Anchor>)> {
 6739        if matches!(self.mode, EditorMode::SingleLine) {
 6740            return None;
 6741        }
 6742        if !EditorSettings::get_global(cx).selection_highlight {
 6743            return None;
 6744        }
 6745        if self.selections.count() != 1 || self.selections.line_mode() {
 6746            return None;
 6747        }
 6748        let snapshot = self.snapshot(window, cx);
 6749        let selection = self.selections.newest::<Point>(&snapshot);
 6750        // If the selection spans multiple rows OR it is empty
 6751        if selection.start.row != selection.end.row
 6752            || selection.start.column == selection.end.column
 6753        {
 6754            return None;
 6755        }
 6756        let selection_anchor_range = selection.range().to_anchors(snapshot.buffer_snapshot());
 6757        let query = snapshot
 6758            .buffer_snapshot()
 6759            .text_for_range(selection_anchor_range.clone())
 6760            .collect::<String>();
 6761        if query.trim().is_empty() {
 6762            return None;
 6763        }
 6764        Some((query, selection_anchor_range))
 6765    }
 6766
 6767    fn update_selection_occurrence_highlights(
 6768        &mut self,
 6769        query_text: String,
 6770        query_range: Range<Anchor>,
 6771        multi_buffer_range_to_query: Range<Point>,
 6772        use_debounce: bool,
 6773        window: &mut Window,
 6774        cx: &mut Context<Editor>,
 6775    ) -> Task<()> {
 6776        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6777        cx.spawn_in(window, async move |editor, cx| {
 6778            if use_debounce {
 6779                cx.background_executor()
 6780                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6781                    .await;
 6782            }
 6783            let match_task = cx.background_spawn(async move {
 6784                let buffer_ranges = multi_buffer_snapshot
 6785                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6786                    .into_iter()
 6787                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6788                let mut match_ranges = Vec::new();
 6789                let Ok(regex) = project::search::SearchQuery::text(
 6790                    query_text.clone(),
 6791                    false,
 6792                    false,
 6793                    false,
 6794                    Default::default(),
 6795                    Default::default(),
 6796                    false,
 6797                    None,
 6798                ) else {
 6799                    return Vec::default();
 6800                };
 6801                let query_range = query_range.to_anchors(&multi_buffer_snapshot);
 6802                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6803                    match_ranges.extend(
 6804                        regex
 6805                            .search(buffer_snapshot, Some(search_range.clone()))
 6806                            .await
 6807                            .into_iter()
 6808                            .filter_map(|match_range| {
 6809                                let match_start = buffer_snapshot
 6810                                    .anchor_after(search_range.start + match_range.start);
 6811                                let match_end = buffer_snapshot
 6812                                    .anchor_before(search_range.start + match_range.end);
 6813                                let match_anchor_range = Anchor::range_in_buffer(
 6814                                    excerpt_id,
 6815                                    buffer_snapshot.remote_id(),
 6816                                    match_start..match_end,
 6817                                );
 6818                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6819                            }),
 6820                    );
 6821                }
 6822                match_ranges
 6823            });
 6824            let match_ranges = match_task.await;
 6825            editor
 6826                .update_in(cx, |editor, _, cx| {
 6827                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6828                    if !match_ranges.is_empty() {
 6829                        editor.highlight_background::<SelectedTextHighlight>(
 6830                            &match_ranges,
 6831                            |theme| theme.colors().editor_document_highlight_bracket_background,
 6832                            cx,
 6833                        )
 6834                    }
 6835                })
 6836                .log_err();
 6837        })
 6838    }
 6839
 6840    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 6841        struct NewlineFold;
 6842        let type_id = std::any::TypeId::of::<NewlineFold>();
 6843        if !self.mode.is_single_line() {
 6844            return;
 6845        }
 6846        let snapshot = self.snapshot(window, cx);
 6847        if snapshot.buffer_snapshot().max_point().row == 0 {
 6848            return;
 6849        }
 6850        let task = cx.background_spawn(async move {
 6851            let new_newlines = snapshot
 6852                .buffer_chars_at(0)
 6853                .filter_map(|(c, i)| {
 6854                    if c == '\n' {
 6855                        Some(
 6856                            snapshot.buffer_snapshot().anchor_after(i)
 6857                                ..snapshot.buffer_snapshot().anchor_before(i + 1),
 6858                        )
 6859                    } else {
 6860                        None
 6861                    }
 6862                })
 6863                .collect::<Vec<_>>();
 6864            let existing_newlines = snapshot
 6865                .folds_in_range(0..snapshot.buffer_snapshot().len())
 6866                .filter_map(|fold| {
 6867                    if fold.placeholder.type_tag == Some(type_id) {
 6868                        Some(fold.range.start..fold.range.end)
 6869                    } else {
 6870                        None
 6871                    }
 6872                })
 6873                .collect::<Vec<_>>();
 6874
 6875            (new_newlines, existing_newlines)
 6876        });
 6877        self.folding_newlines = cx.spawn(async move |this, cx| {
 6878            let (new_newlines, existing_newlines) = task.await;
 6879            if new_newlines == existing_newlines {
 6880                return;
 6881            }
 6882            let placeholder = FoldPlaceholder {
 6883                render: Arc::new(move |_, _, cx| {
 6884                    div()
 6885                        .bg(cx.theme().status().hint_background)
 6886                        .border_b_1()
 6887                        .size_full()
 6888                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 6889                        .border_color(cx.theme().status().hint)
 6890                        .child("\\n")
 6891                        .into_any()
 6892                }),
 6893                constrain_width: false,
 6894                merge_adjacent: false,
 6895                type_tag: Some(type_id),
 6896            };
 6897            let creases = new_newlines
 6898                .into_iter()
 6899                .map(|range| Crease::simple(range, placeholder.clone()))
 6900                .collect();
 6901            this.update(cx, |this, cx| {
 6902                this.display_map.update(cx, |display_map, cx| {
 6903                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 6904                    display_map.fold(creases, cx);
 6905                });
 6906            })
 6907            .ok();
 6908        });
 6909    }
 6910
 6911    fn refresh_selected_text_highlights(
 6912        &mut self,
 6913        on_buffer_edit: bool,
 6914        window: &mut Window,
 6915        cx: &mut Context<Editor>,
 6916    ) {
 6917        let Some((query_text, query_range)) =
 6918            self.prepare_highlight_query_from_selection(window, cx)
 6919        else {
 6920            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 6921            self.quick_selection_highlight_task.take();
 6922            self.debounced_selection_highlight_task.take();
 6923            return;
 6924        };
 6925        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6926        if on_buffer_edit
 6927            || self
 6928                .quick_selection_highlight_task
 6929                .as_ref()
 6930                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 6931        {
 6932            let multi_buffer_visible_start = self
 6933                .scroll_manager
 6934                .anchor()
 6935                .anchor
 6936                .to_point(&multi_buffer_snapshot);
 6937            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 6938                multi_buffer_visible_start
 6939                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 6940                Bias::Left,
 6941            );
 6942            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 6943            self.quick_selection_highlight_task = Some((
 6944                query_range.clone(),
 6945                self.update_selection_occurrence_highlights(
 6946                    query_text.clone(),
 6947                    query_range.clone(),
 6948                    multi_buffer_visible_range,
 6949                    false,
 6950                    window,
 6951                    cx,
 6952                ),
 6953            ));
 6954        }
 6955        if on_buffer_edit
 6956            || self
 6957                .debounced_selection_highlight_task
 6958                .as_ref()
 6959                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 6960        {
 6961            let multi_buffer_start = multi_buffer_snapshot
 6962                .anchor_before(0)
 6963                .to_point(&multi_buffer_snapshot);
 6964            let multi_buffer_end = multi_buffer_snapshot
 6965                .anchor_after(multi_buffer_snapshot.len())
 6966                .to_point(&multi_buffer_snapshot);
 6967            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 6968            self.debounced_selection_highlight_task = Some((
 6969                query_range.clone(),
 6970                self.update_selection_occurrence_highlights(
 6971                    query_text,
 6972                    query_range,
 6973                    multi_buffer_full_range,
 6974                    true,
 6975                    window,
 6976                    cx,
 6977                ),
 6978            ));
 6979        }
 6980    }
 6981
 6982    pub fn refresh_edit_prediction(
 6983        &mut self,
 6984        debounce: bool,
 6985        user_requested: bool,
 6986        window: &mut Window,
 6987        cx: &mut Context<Self>,
 6988    ) -> Option<()> {
 6989        if DisableAiSettings::get_global(cx).disable_ai {
 6990            return None;
 6991        }
 6992
 6993        let provider = self.edit_prediction_provider()?;
 6994        let cursor = self.selections.newest_anchor().head();
 6995        let (buffer, cursor_buffer_position) =
 6996            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6997
 6998        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 6999            self.discard_edit_prediction(false, cx);
 7000            return None;
 7001        }
 7002
 7003        self.update_visible_edit_prediction(window, cx);
 7004
 7005        if !user_requested
 7006            && (!self.should_show_edit_predictions()
 7007                || !self.is_focused(window)
 7008                || buffer.read(cx).is_empty())
 7009        {
 7010            self.discard_edit_prediction(false, cx);
 7011            return None;
 7012        }
 7013
 7014        provider.refresh(buffer, cursor_buffer_position, debounce, cx);
 7015        Some(())
 7016    }
 7017
 7018    fn show_edit_predictions_in_menu(&self) -> bool {
 7019        match self.edit_prediction_settings {
 7020            EditPredictionSettings::Disabled => false,
 7021            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7022        }
 7023    }
 7024
 7025    pub fn edit_predictions_enabled(&self) -> bool {
 7026        match self.edit_prediction_settings {
 7027            EditPredictionSettings::Disabled => false,
 7028            EditPredictionSettings::Enabled { .. } => true,
 7029        }
 7030    }
 7031
 7032    fn edit_prediction_requires_modifier(&self) -> bool {
 7033        match self.edit_prediction_settings {
 7034            EditPredictionSettings::Disabled => false,
 7035            EditPredictionSettings::Enabled {
 7036                preview_requires_modifier,
 7037                ..
 7038            } => preview_requires_modifier,
 7039        }
 7040    }
 7041
 7042    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7043        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7044            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7045            self.discard_edit_prediction(false, cx);
 7046        } else {
 7047            let selection = self.selections.newest_anchor();
 7048            let cursor = selection.head();
 7049
 7050            if let Some((buffer, cursor_buffer_position)) =
 7051                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7052            {
 7053                self.edit_prediction_settings =
 7054                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7055            }
 7056        }
 7057    }
 7058
 7059    fn edit_prediction_settings_at_position(
 7060        &self,
 7061        buffer: &Entity<Buffer>,
 7062        buffer_position: language::Anchor,
 7063        cx: &App,
 7064    ) -> EditPredictionSettings {
 7065        if !self.mode.is_full()
 7066            || !self.show_edit_predictions_override.unwrap_or(true)
 7067            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7068        {
 7069            return EditPredictionSettings::Disabled;
 7070        }
 7071
 7072        let buffer = buffer.read(cx);
 7073
 7074        let file = buffer.file();
 7075
 7076        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7077            return EditPredictionSettings::Disabled;
 7078        };
 7079
 7080        let by_provider = matches!(
 7081            self.menu_edit_predictions_policy,
 7082            MenuEditPredictionsPolicy::ByProvider
 7083        );
 7084
 7085        let show_in_menu = by_provider
 7086            && self
 7087                .edit_prediction_provider
 7088                .as_ref()
 7089                .is_some_and(|provider| provider.provider.show_completions_in_menu());
 7090
 7091        let preview_requires_modifier =
 7092            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7093
 7094        EditPredictionSettings::Enabled {
 7095            show_in_menu,
 7096            preview_requires_modifier,
 7097        }
 7098    }
 7099
 7100    fn should_show_edit_predictions(&self) -> bool {
 7101        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7102    }
 7103
 7104    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7105        matches!(
 7106            self.edit_prediction_preview,
 7107            EditPredictionPreview::Active { .. }
 7108        )
 7109    }
 7110
 7111    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7112        let cursor = self.selections.newest_anchor().head();
 7113        if let Some((buffer, cursor_position)) =
 7114            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7115        {
 7116            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7117        } else {
 7118            false
 7119        }
 7120    }
 7121
 7122    pub fn supports_minimap(&self, cx: &App) -> bool {
 7123        !self.minimap_visibility.disabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton
 7124    }
 7125
 7126    fn edit_predictions_enabled_in_buffer(
 7127        &self,
 7128        buffer: &Entity<Buffer>,
 7129        buffer_position: language::Anchor,
 7130        cx: &App,
 7131    ) -> bool {
 7132        maybe!({
 7133            if self.read_only(cx) {
 7134                return Some(false);
 7135            }
 7136            let provider = self.edit_prediction_provider()?;
 7137            if !provider.is_enabled(buffer, buffer_position, cx) {
 7138                return Some(false);
 7139            }
 7140            let buffer = buffer.read(cx);
 7141            let Some(file) = buffer.file() else {
 7142                return Some(true);
 7143            };
 7144            let settings = all_language_settings(Some(file), cx);
 7145            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7146        })
 7147        .unwrap_or(false)
 7148    }
 7149
 7150    fn cycle_edit_prediction(
 7151        &mut self,
 7152        direction: Direction,
 7153        window: &mut Window,
 7154        cx: &mut Context<Self>,
 7155    ) -> Option<()> {
 7156        let provider = self.edit_prediction_provider()?;
 7157        let cursor = self.selections.newest_anchor().head();
 7158        let (buffer, cursor_buffer_position) =
 7159            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7160        if self.edit_predictions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7161            return None;
 7162        }
 7163
 7164        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7165        self.update_visible_edit_prediction(window, cx);
 7166
 7167        Some(())
 7168    }
 7169
 7170    pub fn show_edit_prediction(
 7171        &mut self,
 7172        _: &ShowEditPrediction,
 7173        window: &mut Window,
 7174        cx: &mut Context<Self>,
 7175    ) {
 7176        if !self.has_active_edit_prediction() {
 7177            self.refresh_edit_prediction(false, true, window, cx);
 7178            return;
 7179        }
 7180
 7181        self.update_visible_edit_prediction(window, cx);
 7182    }
 7183
 7184    pub fn display_cursor_names(
 7185        &mut self,
 7186        _: &DisplayCursorNames,
 7187        window: &mut Window,
 7188        cx: &mut Context<Self>,
 7189    ) {
 7190        self.show_cursor_names(window, cx);
 7191    }
 7192
 7193    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7194        self.show_cursor_names = true;
 7195        cx.notify();
 7196        cx.spawn_in(window, async move |this, cx| {
 7197            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7198            this.update(cx, |this, cx| {
 7199                this.show_cursor_names = false;
 7200                cx.notify()
 7201            })
 7202            .ok()
 7203        })
 7204        .detach();
 7205    }
 7206
 7207    pub fn next_edit_prediction(
 7208        &mut self,
 7209        _: &NextEditPrediction,
 7210        window: &mut Window,
 7211        cx: &mut Context<Self>,
 7212    ) {
 7213        if self.has_active_edit_prediction() {
 7214            self.cycle_edit_prediction(Direction::Next, window, cx);
 7215        } else {
 7216            let is_copilot_disabled = self
 7217                .refresh_edit_prediction(false, true, window, cx)
 7218                .is_none();
 7219            if is_copilot_disabled {
 7220                cx.propagate();
 7221            }
 7222        }
 7223    }
 7224
 7225    pub fn previous_edit_prediction(
 7226        &mut self,
 7227        _: &PreviousEditPrediction,
 7228        window: &mut Window,
 7229        cx: &mut Context<Self>,
 7230    ) {
 7231        if self.has_active_edit_prediction() {
 7232            self.cycle_edit_prediction(Direction::Prev, window, cx);
 7233        } else {
 7234            let is_copilot_disabled = self
 7235                .refresh_edit_prediction(false, true, window, cx)
 7236                .is_none();
 7237            if is_copilot_disabled {
 7238                cx.propagate();
 7239            }
 7240        }
 7241    }
 7242
 7243    pub fn accept_edit_prediction(
 7244        &mut self,
 7245        _: &AcceptEditPrediction,
 7246        window: &mut Window,
 7247        cx: &mut Context<Self>,
 7248    ) {
 7249        if self.show_edit_predictions_in_menu() {
 7250            self.hide_context_menu(window, cx);
 7251        }
 7252
 7253        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7254            return;
 7255        };
 7256
 7257        match &active_edit_prediction.completion {
 7258            EditPrediction::MoveWithin { target, .. } => {
 7259                let target = *target;
 7260
 7261                if let Some(position_map) = &self.last_position_map {
 7262                    if position_map
 7263                        .visible_row_range
 7264                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7265                        || !self.edit_prediction_requires_modifier()
 7266                    {
 7267                        self.unfold_ranges(&[target..target], true, false, cx);
 7268                        // Note that this is also done in vim's handler of the Tab action.
 7269                        self.change_selections(
 7270                            SelectionEffects::scroll(Autoscroll::newest()),
 7271                            window,
 7272                            cx,
 7273                            |selections| {
 7274                                selections.select_anchor_ranges([target..target]);
 7275                            },
 7276                        );
 7277                        self.clear_row_highlights::<EditPredictionPreview>();
 7278
 7279                        self.edit_prediction_preview
 7280                            .set_previous_scroll_position(None);
 7281                    } else {
 7282                        self.edit_prediction_preview
 7283                            .set_previous_scroll_position(Some(
 7284                                position_map.snapshot.scroll_anchor,
 7285                            ));
 7286
 7287                        self.highlight_rows::<EditPredictionPreview>(
 7288                            target..target,
 7289                            cx.theme().colors().editor_highlighted_line_background,
 7290                            RowHighlightOptions {
 7291                                autoscroll: true,
 7292                                ..Default::default()
 7293                            },
 7294                            cx,
 7295                        );
 7296                        self.request_autoscroll(Autoscroll::fit(), cx);
 7297                    }
 7298                }
 7299            }
 7300            EditPrediction::MoveOutside { snapshot, target } => {
 7301                if let Some(workspace) = self.workspace() {
 7302                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7303                        .detach_and_log_err(cx);
 7304                }
 7305            }
 7306            EditPrediction::Edit { edits, .. } => {
 7307                self.report_edit_prediction_event(
 7308                    active_edit_prediction.completion_id.clone(),
 7309                    true,
 7310                    cx,
 7311                );
 7312
 7313                if let Some(provider) = self.edit_prediction_provider() {
 7314                    provider.accept(cx);
 7315                }
 7316
 7317                // Store the transaction ID and selections before applying the edit
 7318                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7319
 7320                let snapshot = self.buffer.read(cx).snapshot(cx);
 7321                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7322
 7323                self.buffer.update(cx, |buffer, cx| {
 7324                    buffer.edit(edits.iter().cloned(), None, cx)
 7325                });
 7326
 7327                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7328                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7329                });
 7330
 7331                let selections = self.selections.disjoint_anchors_arc();
 7332                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7333                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7334                    if has_new_transaction {
 7335                        self.selection_history
 7336                            .insert_transaction(transaction_id_now, selections);
 7337                    }
 7338                }
 7339
 7340                self.update_visible_edit_prediction(window, cx);
 7341                if self.active_edit_prediction.is_none() {
 7342                    self.refresh_edit_prediction(true, true, window, cx);
 7343                }
 7344
 7345                cx.notify();
 7346            }
 7347        }
 7348
 7349        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7350    }
 7351
 7352    pub fn accept_partial_edit_prediction(
 7353        &mut self,
 7354        _: &AcceptPartialEditPrediction,
 7355        window: &mut Window,
 7356        cx: &mut Context<Self>,
 7357    ) {
 7358        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7359            return;
 7360        };
 7361        if self.selections.count() != 1 {
 7362            return;
 7363        }
 7364
 7365        match &active_edit_prediction.completion {
 7366            EditPrediction::MoveWithin { target, .. } => {
 7367                let target = *target;
 7368                self.change_selections(
 7369                    SelectionEffects::scroll(Autoscroll::newest()),
 7370                    window,
 7371                    cx,
 7372                    |selections| {
 7373                        selections.select_anchor_ranges([target..target]);
 7374                    },
 7375                );
 7376            }
 7377            EditPrediction::MoveOutside { snapshot, target } => {
 7378                if let Some(workspace) = self.workspace() {
 7379                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7380                        .detach_and_log_err(cx);
 7381                }
 7382            }
 7383            EditPrediction::Edit { edits, .. } => {
 7384                self.report_edit_prediction_event(
 7385                    active_edit_prediction.completion_id.clone(),
 7386                    true,
 7387                    cx,
 7388                );
 7389
 7390                // Find an insertion that starts at the cursor position.
 7391                let snapshot = self.buffer.read(cx).snapshot(cx);
 7392                let cursor_offset = self
 7393                    .selections
 7394                    .newest::<usize>(&self.display_snapshot(cx))
 7395                    .head();
 7396                let insertion = edits.iter().find_map(|(range, text)| {
 7397                    let range = range.to_offset(&snapshot);
 7398                    if range.is_empty() && range.start == cursor_offset {
 7399                        Some(text)
 7400                    } else {
 7401                        None
 7402                    }
 7403                });
 7404
 7405                if let Some(text) = insertion {
 7406                    let mut partial_completion = text
 7407                        .chars()
 7408                        .by_ref()
 7409                        .take_while(|c| c.is_alphabetic())
 7410                        .collect::<String>();
 7411                    if partial_completion.is_empty() {
 7412                        partial_completion = text
 7413                            .chars()
 7414                            .by_ref()
 7415                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7416                            .collect::<String>();
 7417                    }
 7418
 7419                    cx.emit(EditorEvent::InputHandled {
 7420                        utf16_range_to_replace: None,
 7421                        text: partial_completion.clone().into(),
 7422                    });
 7423
 7424                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7425
 7426                    self.refresh_edit_prediction(true, true, window, cx);
 7427                    cx.notify();
 7428                } else {
 7429                    self.accept_edit_prediction(&Default::default(), window, cx);
 7430                }
 7431            }
 7432        }
 7433    }
 7434
 7435    fn discard_edit_prediction(
 7436        &mut self,
 7437        should_report_edit_prediction_event: bool,
 7438        cx: &mut Context<Self>,
 7439    ) -> bool {
 7440        if should_report_edit_prediction_event {
 7441            let completion_id = self
 7442                .active_edit_prediction
 7443                .as_ref()
 7444                .and_then(|active_completion| active_completion.completion_id.clone());
 7445
 7446            self.report_edit_prediction_event(completion_id, false, cx);
 7447        }
 7448
 7449        if let Some(provider) = self.edit_prediction_provider() {
 7450            provider.discard(cx);
 7451        }
 7452
 7453        self.take_active_edit_prediction(cx)
 7454    }
 7455
 7456    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7457        let Some(provider) = self.edit_prediction_provider() else {
 7458            return;
 7459        };
 7460
 7461        let Some((_, buffer, _)) = self
 7462            .buffer
 7463            .read(cx)
 7464            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7465        else {
 7466            return;
 7467        };
 7468
 7469        let extension = buffer
 7470            .read(cx)
 7471            .file()
 7472            .and_then(|file| Some(file.path().extension()?.to_string()));
 7473
 7474        let event_type = match accepted {
 7475            true => "Edit Prediction Accepted",
 7476            false => "Edit Prediction Discarded",
 7477        };
 7478        telemetry::event!(
 7479            event_type,
 7480            provider = provider.name(),
 7481            prediction_id = id,
 7482            suggestion_accepted = accepted,
 7483            file_extension = extension,
 7484        );
 7485    }
 7486
 7487    fn open_editor_at_anchor(
 7488        snapshot: &language::BufferSnapshot,
 7489        target: language::Anchor,
 7490        workspace: &Entity<Workspace>,
 7491        window: &mut Window,
 7492        cx: &mut App,
 7493    ) -> Task<Result<()>> {
 7494        workspace.update(cx, |workspace, cx| {
 7495            let path = snapshot.file().map(|file| file.full_path(cx));
 7496            let Some(path) =
 7497                path.and_then(|path| workspace.project().read(cx).find_project_path(path, cx))
 7498            else {
 7499                return Task::ready(Err(anyhow::anyhow!("Project path not found")));
 7500            };
 7501            let target = text::ToPoint::to_point(&target, snapshot);
 7502            let item = workspace.open_path(path, None, true, window, cx);
 7503            window.spawn(cx, async move |cx| {
 7504                let Some(editor) = item.await?.downcast::<Editor>() else {
 7505                    return Ok(());
 7506                };
 7507                editor
 7508                    .update_in(cx, |editor, window, cx| {
 7509                        editor.go_to_singleton_buffer_point(target, window, cx);
 7510                    })
 7511                    .ok();
 7512                anyhow::Ok(())
 7513            })
 7514        })
 7515    }
 7516
 7517    pub fn has_active_edit_prediction(&self) -> bool {
 7518        self.active_edit_prediction.is_some()
 7519    }
 7520
 7521    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7522        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7523            return false;
 7524        };
 7525
 7526        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7527        self.clear_highlights::<EditPredictionHighlight>(cx);
 7528        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7529        true
 7530    }
 7531
 7532    /// Returns true when we're displaying the edit prediction popover below the cursor
 7533    /// like we are not previewing and the LSP autocomplete menu is visible
 7534    /// or we are in `when_holding_modifier` mode.
 7535    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7536        if self.edit_prediction_preview_is_active()
 7537            || !self.show_edit_predictions_in_menu()
 7538            || !self.edit_predictions_enabled()
 7539        {
 7540            return false;
 7541        }
 7542
 7543        if self.has_visible_completions_menu() {
 7544            return true;
 7545        }
 7546
 7547        has_completion && self.edit_prediction_requires_modifier()
 7548    }
 7549
 7550    fn handle_modifiers_changed(
 7551        &mut self,
 7552        modifiers: Modifiers,
 7553        position_map: &PositionMap,
 7554        window: &mut Window,
 7555        cx: &mut Context<Self>,
 7556    ) {
 7557        if self.show_edit_predictions_in_menu() {
 7558            self.update_edit_prediction_preview(&modifiers, window, cx);
 7559        }
 7560
 7561        self.update_selection_mode(&modifiers, position_map, window, cx);
 7562
 7563        let mouse_position = window.mouse_position();
 7564        if !position_map.text_hitbox.is_hovered(window) {
 7565            return;
 7566        }
 7567
 7568        self.update_hovered_link(
 7569            position_map.point_for_position(mouse_position),
 7570            &position_map.snapshot,
 7571            modifiers,
 7572            window,
 7573            cx,
 7574        )
 7575    }
 7576
 7577    fn multi_cursor_modifier(invert: bool, modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7578        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7579        if invert {
 7580            match multi_cursor_setting {
 7581                MultiCursorModifier::Alt => modifiers.alt,
 7582                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7583            }
 7584        } else {
 7585            match multi_cursor_setting {
 7586                MultiCursorModifier::Alt => modifiers.secondary(),
 7587                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7588            }
 7589        }
 7590    }
 7591
 7592    fn columnar_selection_mode(
 7593        modifiers: &Modifiers,
 7594        cx: &mut Context<Self>,
 7595    ) -> Option<ColumnarMode> {
 7596        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7597            if Self::multi_cursor_modifier(false, modifiers, cx) {
 7598                Some(ColumnarMode::FromMouse)
 7599            } else if Self::multi_cursor_modifier(true, modifiers, cx) {
 7600                Some(ColumnarMode::FromSelection)
 7601            } else {
 7602                None
 7603            }
 7604        } else {
 7605            None
 7606        }
 7607    }
 7608
 7609    fn update_selection_mode(
 7610        &mut self,
 7611        modifiers: &Modifiers,
 7612        position_map: &PositionMap,
 7613        window: &mut Window,
 7614        cx: &mut Context<Self>,
 7615    ) {
 7616        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7617            return;
 7618        };
 7619        if self.selections.pending_anchor().is_none() {
 7620            return;
 7621        }
 7622
 7623        let mouse_position = window.mouse_position();
 7624        let point_for_position = position_map.point_for_position(mouse_position);
 7625        let position = point_for_position.previous_valid;
 7626
 7627        self.select(
 7628            SelectPhase::BeginColumnar {
 7629                position,
 7630                reset: false,
 7631                mode,
 7632                goal_column: point_for_position.exact_unclipped.column(),
 7633            },
 7634            window,
 7635            cx,
 7636        );
 7637    }
 7638
 7639    fn update_edit_prediction_preview(
 7640        &mut self,
 7641        modifiers: &Modifiers,
 7642        window: &mut Window,
 7643        cx: &mut Context<Self>,
 7644    ) {
 7645        let mut modifiers_held = false;
 7646        if let Some(accept_keystroke) = self
 7647            .accept_edit_prediction_keybind(false, window, cx)
 7648            .keystroke()
 7649        {
 7650            modifiers_held = modifiers_held
 7651                || (accept_keystroke.modifiers() == modifiers
 7652                    && accept_keystroke.modifiers().modified());
 7653        };
 7654        if let Some(accept_partial_keystroke) = self
 7655            .accept_edit_prediction_keybind(true, window, cx)
 7656            .keystroke()
 7657        {
 7658            modifiers_held = modifiers_held
 7659                || (accept_partial_keystroke.modifiers() == modifiers
 7660                    && accept_partial_keystroke.modifiers().modified());
 7661        }
 7662
 7663        if modifiers_held {
 7664            if matches!(
 7665                self.edit_prediction_preview,
 7666                EditPredictionPreview::Inactive { .. }
 7667            ) {
 7668                self.edit_prediction_preview = EditPredictionPreview::Active {
 7669                    previous_scroll_position: None,
 7670                    since: Instant::now(),
 7671                };
 7672
 7673                self.update_visible_edit_prediction(window, cx);
 7674                cx.notify();
 7675            }
 7676        } else if let EditPredictionPreview::Active {
 7677            previous_scroll_position,
 7678            since,
 7679        } = self.edit_prediction_preview
 7680        {
 7681            if let (Some(previous_scroll_position), Some(position_map)) =
 7682                (previous_scroll_position, self.last_position_map.as_ref())
 7683            {
 7684                self.set_scroll_position(
 7685                    previous_scroll_position
 7686                        .scroll_position(&position_map.snapshot.display_snapshot),
 7687                    window,
 7688                    cx,
 7689                );
 7690            }
 7691
 7692            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7693                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7694            };
 7695            self.clear_row_highlights::<EditPredictionPreview>();
 7696            self.update_visible_edit_prediction(window, cx);
 7697            cx.notify();
 7698        }
 7699    }
 7700
 7701    fn update_visible_edit_prediction(
 7702        &mut self,
 7703        _window: &mut Window,
 7704        cx: &mut Context<Self>,
 7705    ) -> Option<()> {
 7706        if DisableAiSettings::get_global(cx).disable_ai {
 7707            return None;
 7708        }
 7709
 7710        if self.ime_transaction.is_some() {
 7711            self.discard_edit_prediction(false, cx);
 7712            return None;
 7713        }
 7714
 7715        let selection = self.selections.newest_anchor();
 7716        let cursor = selection.head();
 7717        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7718        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7719        let excerpt_id = cursor.excerpt_id;
 7720
 7721        let show_in_menu = self.show_edit_predictions_in_menu();
 7722        let completions_menu_has_precedence = !show_in_menu
 7723            && (self.context_menu.borrow().is_some()
 7724                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 7725
 7726        if completions_menu_has_precedence
 7727            || !offset_selection.is_empty()
 7728            || self
 7729                .active_edit_prediction
 7730                .as_ref()
 7731                .is_some_and(|completion| {
 7732                    let Some(invalidation_range) = completion.invalidation_range.as_ref() else {
 7733                        return false;
 7734                    };
 7735                    let invalidation_range = invalidation_range.to_offset(&multibuffer);
 7736                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7737                    !invalidation_range.contains(&offset_selection.head())
 7738                })
 7739        {
 7740            self.discard_edit_prediction(false, cx);
 7741            return None;
 7742        }
 7743
 7744        self.take_active_edit_prediction(cx);
 7745        let Some(provider) = self.edit_prediction_provider() else {
 7746            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7747            return None;
 7748        };
 7749
 7750        let (buffer, cursor_buffer_position) =
 7751            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7752
 7753        self.edit_prediction_settings =
 7754            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7755
 7756        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7757
 7758        if self.edit_prediction_indent_conflict {
 7759            let cursor_point = cursor.to_point(&multibuffer);
 7760
 7761            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7762
 7763            if let Some((_, indent)) = indents.iter().next()
 7764                && indent.len == cursor_point.column
 7765            {
 7766                self.edit_prediction_indent_conflict = false;
 7767            }
 7768        }
 7769
 7770        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7771
 7772        let (completion_id, edits, edit_preview) = match edit_prediction {
 7773            edit_prediction::EditPrediction::Local {
 7774                id,
 7775                edits,
 7776                edit_preview,
 7777            } => (id, edits, edit_preview),
 7778            edit_prediction::EditPrediction::Jump {
 7779                id,
 7780                snapshot,
 7781                target,
 7782            } => {
 7783                self.stale_edit_prediction_in_menu = None;
 7784                self.active_edit_prediction = Some(EditPredictionState {
 7785                    inlay_ids: vec![],
 7786                    completion: EditPrediction::MoveOutside { snapshot, target },
 7787                    completion_id: id,
 7788                    invalidation_range: None,
 7789                });
 7790                cx.notify();
 7791                return Some(());
 7792            }
 7793        };
 7794
 7795        let edits = edits
 7796            .into_iter()
 7797            .flat_map(|(range, new_text)| {
 7798                Some((
 7799                    multibuffer.anchor_range_in_excerpt(excerpt_id, range)?,
 7800                    new_text,
 7801                ))
 7802            })
 7803            .collect::<Vec<_>>();
 7804        if edits.is_empty() {
 7805            return None;
 7806        }
 7807
 7808        let first_edit_start = edits.first().unwrap().0.start;
 7809        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7810        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7811
 7812        let last_edit_end = edits.last().unwrap().0.end;
 7813        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7814        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7815
 7816        let cursor_row = cursor.to_point(&multibuffer).row;
 7817
 7818        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7819
 7820        let mut inlay_ids = Vec::new();
 7821        let invalidation_row_range;
 7822        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7823            Some(cursor_row..edit_end_row)
 7824        } else if cursor_row > edit_end_row {
 7825            Some(edit_start_row..cursor_row)
 7826        } else {
 7827            None
 7828        };
 7829        let supports_jump = self
 7830            .edit_prediction_provider
 7831            .as_ref()
 7832            .map(|provider| provider.provider.supports_jump_to_edit())
 7833            .unwrap_or(true);
 7834
 7835        let is_move = supports_jump
 7836            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 7837        let completion = if is_move {
 7838            invalidation_row_range =
 7839                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7840            let target = first_edit_start;
 7841            EditPrediction::MoveWithin { target, snapshot }
 7842        } else {
 7843            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7844                && !self.edit_predictions_hidden_for_vim_mode;
 7845
 7846            if show_completions_in_buffer {
 7847                if edits
 7848                    .iter()
 7849                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7850                {
 7851                    let mut inlays = Vec::new();
 7852                    for (range, new_text) in &edits {
 7853                        let inlay = Inlay::edit_prediction(
 7854                            post_inc(&mut self.next_inlay_id),
 7855                            range.start,
 7856                            new_text.as_str(),
 7857                        );
 7858                        inlay_ids.push(inlay.id);
 7859                        inlays.push(inlay);
 7860                    }
 7861
 7862                    self.splice_inlays(&[], inlays, cx);
 7863                } else {
 7864                    let background_color = cx.theme().status().deleted_background;
 7865                    self.highlight_text::<EditPredictionHighlight>(
 7866                        edits.iter().map(|(range, _)| range.clone()).collect(),
 7867                        HighlightStyle {
 7868                            background_color: Some(background_color),
 7869                            ..Default::default()
 7870                        },
 7871                        cx,
 7872                    );
 7873                }
 7874            }
 7875
 7876            invalidation_row_range = edit_start_row..edit_end_row;
 7877
 7878            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7879                if provider.show_tab_accept_marker() {
 7880                    EditDisplayMode::TabAccept
 7881                } else {
 7882                    EditDisplayMode::Inline
 7883                }
 7884            } else {
 7885                EditDisplayMode::DiffPopover
 7886            };
 7887
 7888            EditPrediction::Edit {
 7889                edits,
 7890                edit_preview,
 7891                display_mode,
 7892                snapshot,
 7893            }
 7894        };
 7895
 7896        let invalidation_range = multibuffer
 7897            .anchor_before(Point::new(invalidation_row_range.start, 0))
 7898            ..multibuffer.anchor_after(Point::new(
 7899                invalidation_row_range.end,
 7900                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7901            ));
 7902
 7903        self.stale_edit_prediction_in_menu = None;
 7904        self.active_edit_prediction = Some(EditPredictionState {
 7905            inlay_ids,
 7906            completion,
 7907            completion_id,
 7908            invalidation_range: Some(invalidation_range),
 7909        });
 7910
 7911        cx.notify();
 7912
 7913        Some(())
 7914    }
 7915
 7916    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionProviderHandle>> {
 7917        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 7918    }
 7919
 7920    fn clear_tasks(&mut self) {
 7921        self.tasks.clear()
 7922    }
 7923
 7924    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 7925        if self.tasks.insert(key, value).is_some() {
 7926            // This case should hopefully be rare, but just in case...
 7927            log::error!(
 7928                "multiple different run targets found on a single line, only the last target will be rendered"
 7929            )
 7930        }
 7931    }
 7932
 7933    /// Get all display points of breakpoints that will be rendered within editor
 7934    ///
 7935    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 7936    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 7937    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 7938    fn active_breakpoints(
 7939        &self,
 7940        range: Range<DisplayRow>,
 7941        window: &mut Window,
 7942        cx: &mut Context<Self>,
 7943    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 7944        let mut breakpoint_display_points = HashMap::default();
 7945
 7946        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 7947            return breakpoint_display_points;
 7948        };
 7949
 7950        let snapshot = self.snapshot(window, cx);
 7951
 7952        let multi_buffer_snapshot = snapshot.buffer_snapshot();
 7953        let Some(project) = self.project() else {
 7954            return breakpoint_display_points;
 7955        };
 7956
 7957        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 7958            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 7959
 7960        for (buffer_snapshot, range, excerpt_id) in
 7961            multi_buffer_snapshot.range_to_buffer_ranges(range)
 7962        {
 7963            let Some(buffer) = project
 7964                .read(cx)
 7965                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 7966            else {
 7967                continue;
 7968            };
 7969            let breakpoints = breakpoint_store.read(cx).breakpoints(
 7970                &buffer,
 7971                Some(
 7972                    buffer_snapshot.anchor_before(range.start)
 7973                        ..buffer_snapshot.anchor_after(range.end),
 7974                ),
 7975                buffer_snapshot,
 7976                cx,
 7977            );
 7978            for (breakpoint, state) in breakpoints {
 7979                let multi_buffer_anchor =
 7980                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 7981                let position = multi_buffer_anchor
 7982                    .to_point(&multi_buffer_snapshot)
 7983                    .to_display_point(&snapshot);
 7984
 7985                breakpoint_display_points.insert(
 7986                    position.row(),
 7987                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 7988                );
 7989            }
 7990        }
 7991
 7992        breakpoint_display_points
 7993    }
 7994
 7995    fn breakpoint_context_menu(
 7996        &self,
 7997        anchor: Anchor,
 7998        window: &mut Window,
 7999        cx: &mut Context<Self>,
 8000    ) -> Entity<ui::ContextMenu> {
 8001        let weak_editor = cx.weak_entity();
 8002        let focus_handle = self.focus_handle(cx);
 8003
 8004        let row = self
 8005            .buffer
 8006            .read(cx)
 8007            .snapshot(cx)
 8008            .summary_for_anchor::<Point>(&anchor)
 8009            .row;
 8010
 8011        let breakpoint = self
 8012            .breakpoint_at_row(row, window, cx)
 8013            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 8014
 8015        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 8016            "Edit Log Breakpoint"
 8017        } else {
 8018            "Set Log Breakpoint"
 8019        };
 8020
 8021        let condition_breakpoint_msg = if breakpoint
 8022            .as_ref()
 8023            .is_some_and(|bp| bp.1.condition.is_some())
 8024        {
 8025            "Edit Condition Breakpoint"
 8026        } else {
 8027            "Set Condition Breakpoint"
 8028        };
 8029
 8030        let hit_condition_breakpoint_msg = if breakpoint
 8031            .as_ref()
 8032            .is_some_and(|bp| bp.1.hit_condition.is_some())
 8033        {
 8034            "Edit Hit Condition Breakpoint"
 8035        } else {
 8036            "Set Hit Condition Breakpoint"
 8037        };
 8038
 8039        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 8040            "Unset Breakpoint"
 8041        } else {
 8042            "Set Breakpoint"
 8043        };
 8044
 8045        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8046
 8047        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8048            BreakpointState::Enabled => Some("Disable"),
 8049            BreakpointState::Disabled => Some("Enable"),
 8050        });
 8051
 8052        let (anchor, breakpoint) =
 8053            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8054
 8055        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8056            menu.on_blur_subscription(Subscription::new(|| {}))
 8057                .context(focus_handle)
 8058                .when(run_to_cursor, |this| {
 8059                    let weak_editor = weak_editor.clone();
 8060                    this.entry("Run to cursor", None, move |window, cx| {
 8061                        weak_editor
 8062                            .update(cx, |editor, cx| {
 8063                                editor.change_selections(
 8064                                    SelectionEffects::no_scroll(),
 8065                                    window,
 8066                                    cx,
 8067                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8068                                );
 8069                            })
 8070                            .ok();
 8071
 8072                        window.dispatch_action(Box::new(RunToCursor), cx);
 8073                    })
 8074                    .separator()
 8075                })
 8076                .when_some(toggle_state_msg, |this, msg| {
 8077                    this.entry(msg, None, {
 8078                        let weak_editor = weak_editor.clone();
 8079                        let breakpoint = breakpoint.clone();
 8080                        move |_window, cx| {
 8081                            weak_editor
 8082                                .update(cx, |this, cx| {
 8083                                    this.edit_breakpoint_at_anchor(
 8084                                        anchor,
 8085                                        breakpoint.as_ref().clone(),
 8086                                        BreakpointEditAction::InvertState,
 8087                                        cx,
 8088                                    );
 8089                                })
 8090                                .log_err();
 8091                        }
 8092                    })
 8093                })
 8094                .entry(set_breakpoint_msg, None, {
 8095                    let weak_editor = weak_editor.clone();
 8096                    let breakpoint = breakpoint.clone();
 8097                    move |_window, cx| {
 8098                        weak_editor
 8099                            .update(cx, |this, cx| {
 8100                                this.edit_breakpoint_at_anchor(
 8101                                    anchor,
 8102                                    breakpoint.as_ref().clone(),
 8103                                    BreakpointEditAction::Toggle,
 8104                                    cx,
 8105                                );
 8106                            })
 8107                            .log_err();
 8108                    }
 8109                })
 8110                .entry(log_breakpoint_msg, None, {
 8111                    let breakpoint = breakpoint.clone();
 8112                    let weak_editor = weak_editor.clone();
 8113                    move |window, cx| {
 8114                        weak_editor
 8115                            .update(cx, |this, cx| {
 8116                                this.add_edit_breakpoint_block(
 8117                                    anchor,
 8118                                    breakpoint.as_ref(),
 8119                                    BreakpointPromptEditAction::Log,
 8120                                    window,
 8121                                    cx,
 8122                                );
 8123                            })
 8124                            .log_err();
 8125                    }
 8126                })
 8127                .entry(condition_breakpoint_msg, None, {
 8128                    let breakpoint = breakpoint.clone();
 8129                    let weak_editor = weak_editor.clone();
 8130                    move |window, cx| {
 8131                        weak_editor
 8132                            .update(cx, |this, cx| {
 8133                                this.add_edit_breakpoint_block(
 8134                                    anchor,
 8135                                    breakpoint.as_ref(),
 8136                                    BreakpointPromptEditAction::Condition,
 8137                                    window,
 8138                                    cx,
 8139                                );
 8140                            })
 8141                            .log_err();
 8142                    }
 8143                })
 8144                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8145                    weak_editor
 8146                        .update(cx, |this, cx| {
 8147                            this.add_edit_breakpoint_block(
 8148                                anchor,
 8149                                breakpoint.as_ref(),
 8150                                BreakpointPromptEditAction::HitCondition,
 8151                                window,
 8152                                cx,
 8153                            );
 8154                        })
 8155                        .log_err();
 8156                })
 8157        })
 8158    }
 8159
 8160    fn render_breakpoint(
 8161        &self,
 8162        position: Anchor,
 8163        row: DisplayRow,
 8164        breakpoint: &Breakpoint,
 8165        state: Option<BreakpointSessionState>,
 8166        cx: &mut Context<Self>,
 8167    ) -> IconButton {
 8168        let is_rejected = state.is_some_and(|s| !s.verified);
 8169        // Is it a breakpoint that shows up when hovering over gutter?
 8170        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8171            (false, false),
 8172            |PhantomBreakpointIndicator {
 8173                 is_active,
 8174                 display_row,
 8175                 collides_with_existing_breakpoint,
 8176             }| {
 8177                (
 8178                    is_active && display_row == row,
 8179                    collides_with_existing_breakpoint,
 8180                )
 8181            },
 8182        );
 8183
 8184        let (color, icon) = {
 8185            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8186                (false, false) => ui::IconName::DebugBreakpoint,
 8187                (true, false) => ui::IconName::DebugLogBreakpoint,
 8188                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8189                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8190            };
 8191
 8192            let color = if is_phantom {
 8193                Color::Hint
 8194            } else if is_rejected {
 8195                Color::Disabled
 8196            } else {
 8197                Color::Debugger
 8198            };
 8199
 8200            (color, icon)
 8201        };
 8202
 8203        let breakpoint = Arc::from(breakpoint.clone());
 8204
 8205        let alt_as_text = gpui::Keystroke {
 8206            modifiers: Modifiers::secondary_key(),
 8207            ..Default::default()
 8208        };
 8209        let primary_action_text = if breakpoint.is_disabled() {
 8210            "Enable breakpoint"
 8211        } else if is_phantom && !collides_with_existing {
 8212            "Set breakpoint"
 8213        } else {
 8214            "Unset breakpoint"
 8215        };
 8216        let focus_handle = self.focus_handle.clone();
 8217
 8218        let meta = if is_rejected {
 8219            SharedString::from("No executable code is associated with this line.")
 8220        } else if collides_with_existing && !breakpoint.is_disabled() {
 8221            SharedString::from(format!(
 8222                "{alt_as_text}-click to disable,\nright-click for more options."
 8223            ))
 8224        } else {
 8225            SharedString::from("Right-click for more options.")
 8226        };
 8227        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8228            .icon_size(IconSize::XSmall)
 8229            .size(ui::ButtonSize::None)
 8230            .when(is_rejected, |this| {
 8231                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8232            })
 8233            .icon_color(color)
 8234            .style(ButtonStyle::Transparent)
 8235            .on_click(cx.listener({
 8236                move |editor, event: &ClickEvent, window, cx| {
 8237                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8238                        BreakpointEditAction::InvertState
 8239                    } else {
 8240                        BreakpointEditAction::Toggle
 8241                    };
 8242
 8243                    window.focus(&editor.focus_handle(cx));
 8244                    editor.edit_breakpoint_at_anchor(
 8245                        position,
 8246                        breakpoint.as_ref().clone(),
 8247                        edit_action,
 8248                        cx,
 8249                    );
 8250                }
 8251            }))
 8252            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8253                editor.set_breakpoint_context_menu(
 8254                    row,
 8255                    Some(position),
 8256                    event.position(),
 8257                    window,
 8258                    cx,
 8259                );
 8260            }))
 8261            .tooltip(move |_window, cx| {
 8262                Tooltip::with_meta_in(
 8263                    primary_action_text,
 8264                    Some(&ToggleBreakpoint),
 8265                    meta.clone(),
 8266                    &focus_handle,
 8267                    cx,
 8268                )
 8269            })
 8270    }
 8271
 8272    fn build_tasks_context(
 8273        project: &Entity<Project>,
 8274        buffer: &Entity<Buffer>,
 8275        buffer_row: u32,
 8276        tasks: &Arc<RunnableTasks>,
 8277        cx: &mut Context<Self>,
 8278    ) -> Task<Option<task::TaskContext>> {
 8279        let position = Point::new(buffer_row, tasks.column);
 8280        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8281        let location = Location {
 8282            buffer: buffer.clone(),
 8283            range: range_start..range_start,
 8284        };
 8285        // Fill in the environmental variables from the tree-sitter captures
 8286        let mut captured_task_variables = TaskVariables::default();
 8287        for (capture_name, value) in tasks.extra_variables.clone() {
 8288            captured_task_variables.insert(
 8289                task::VariableName::Custom(capture_name.into()),
 8290                value.clone(),
 8291            );
 8292        }
 8293        project.update(cx, |project, cx| {
 8294            project.task_store().update(cx, |task_store, cx| {
 8295                task_store.task_context_for_location(captured_task_variables, location, cx)
 8296            })
 8297        })
 8298    }
 8299
 8300    pub fn spawn_nearest_task(
 8301        &mut self,
 8302        action: &SpawnNearestTask,
 8303        window: &mut Window,
 8304        cx: &mut Context<Self>,
 8305    ) {
 8306        let Some((workspace, _)) = self.workspace.clone() else {
 8307            return;
 8308        };
 8309        let Some(project) = self.project.clone() else {
 8310            return;
 8311        };
 8312
 8313        // Try to find a closest, enclosing node using tree-sitter that has a task
 8314        let Some((buffer, buffer_row, tasks)) = self
 8315            .find_enclosing_node_task(cx)
 8316            // Or find the task that's closest in row-distance.
 8317            .or_else(|| self.find_closest_task(cx))
 8318        else {
 8319            return;
 8320        };
 8321
 8322        let reveal_strategy = action.reveal;
 8323        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8324        cx.spawn_in(window, async move |_, cx| {
 8325            let context = task_context.await?;
 8326            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8327
 8328            let resolved = &mut resolved_task.resolved;
 8329            resolved.reveal = reveal_strategy;
 8330
 8331            workspace
 8332                .update_in(cx, |workspace, window, cx| {
 8333                    workspace.schedule_resolved_task(
 8334                        task_source_kind,
 8335                        resolved_task,
 8336                        false,
 8337                        window,
 8338                        cx,
 8339                    );
 8340                })
 8341                .ok()
 8342        })
 8343        .detach();
 8344    }
 8345
 8346    fn find_closest_task(
 8347        &mut self,
 8348        cx: &mut Context<Self>,
 8349    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8350        let cursor_row = self
 8351            .selections
 8352            .newest_adjusted(&self.display_snapshot(cx))
 8353            .head()
 8354            .row;
 8355
 8356        let ((buffer_id, row), tasks) = self
 8357            .tasks
 8358            .iter()
 8359            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8360
 8361        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8362        let tasks = Arc::new(tasks.to_owned());
 8363        Some((buffer, *row, tasks))
 8364    }
 8365
 8366    fn find_enclosing_node_task(
 8367        &mut self,
 8368        cx: &mut Context<Self>,
 8369    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8370        let snapshot = self.buffer.read(cx).snapshot(cx);
 8371        let offset = self
 8372            .selections
 8373            .newest::<usize>(&self.display_snapshot(cx))
 8374            .head();
 8375        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8376        let buffer_id = excerpt.buffer().remote_id();
 8377
 8378        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8379        let mut cursor = layer.node().walk();
 8380
 8381        while cursor.goto_first_child_for_byte(offset).is_some() {
 8382            if cursor.node().end_byte() == offset {
 8383                cursor.goto_next_sibling();
 8384            }
 8385        }
 8386
 8387        // Ascend to the smallest ancestor that contains the range and has a task.
 8388        loop {
 8389            let node = cursor.node();
 8390            let node_range = node.byte_range();
 8391            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8392
 8393            // Check if this node contains our offset
 8394            if node_range.start <= offset && node_range.end >= offset {
 8395                // If it contains offset, check for task
 8396                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8397                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8398                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8399                }
 8400            }
 8401
 8402            if !cursor.goto_parent() {
 8403                break;
 8404            }
 8405        }
 8406        None
 8407    }
 8408
 8409    fn render_run_indicator(
 8410        &self,
 8411        _style: &EditorStyle,
 8412        is_active: bool,
 8413        row: DisplayRow,
 8414        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8415        cx: &mut Context<Self>,
 8416    ) -> IconButton {
 8417        let color = Color::Muted;
 8418        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8419
 8420        IconButton::new(
 8421            ("run_indicator", row.0 as usize),
 8422            ui::IconName::PlayOutlined,
 8423        )
 8424        .shape(ui::IconButtonShape::Square)
 8425        .icon_size(IconSize::XSmall)
 8426        .icon_color(color)
 8427        .toggle_state(is_active)
 8428        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8429            let quick_launch = match e {
 8430                ClickEvent::Keyboard(_) => true,
 8431                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8432            };
 8433
 8434            window.focus(&editor.focus_handle(cx));
 8435            editor.toggle_code_actions(
 8436                &ToggleCodeActions {
 8437                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8438                    quick_launch,
 8439                },
 8440                window,
 8441                cx,
 8442            );
 8443        }))
 8444        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8445            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8446        }))
 8447    }
 8448
 8449    pub fn context_menu_visible(&self) -> bool {
 8450        !self.edit_prediction_preview_is_active()
 8451            && self
 8452                .context_menu
 8453                .borrow()
 8454                .as_ref()
 8455                .is_some_and(|menu| menu.visible())
 8456    }
 8457
 8458    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8459        self.context_menu
 8460            .borrow()
 8461            .as_ref()
 8462            .map(|menu| menu.origin())
 8463    }
 8464
 8465    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8466        self.context_menu_options = Some(options);
 8467    }
 8468
 8469    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = px(24.);
 8470    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = px(2.);
 8471
 8472    fn render_edit_prediction_popover(
 8473        &mut self,
 8474        text_bounds: &Bounds<Pixels>,
 8475        content_origin: gpui::Point<Pixels>,
 8476        right_margin: Pixels,
 8477        editor_snapshot: &EditorSnapshot,
 8478        visible_row_range: Range<DisplayRow>,
 8479        scroll_top: ScrollOffset,
 8480        scroll_bottom: ScrollOffset,
 8481        line_layouts: &[LineWithInvisibles],
 8482        line_height: Pixels,
 8483        scroll_position: gpui::Point<ScrollOffset>,
 8484        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8485        newest_selection_head: Option<DisplayPoint>,
 8486        editor_width: Pixels,
 8487        style: &EditorStyle,
 8488        window: &mut Window,
 8489        cx: &mut App,
 8490    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8491        if self.mode().is_minimap() {
 8492            return None;
 8493        }
 8494        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8495
 8496        if self.edit_prediction_visible_in_cursor_popover(true) {
 8497            return None;
 8498        }
 8499
 8500        match &active_edit_prediction.completion {
 8501            EditPrediction::MoveWithin { target, .. } => {
 8502                let target_display_point = target.to_display_point(editor_snapshot);
 8503
 8504                if self.edit_prediction_requires_modifier() {
 8505                    if !self.edit_prediction_preview_is_active() {
 8506                        return None;
 8507                    }
 8508
 8509                    self.render_edit_prediction_modifier_jump_popover(
 8510                        text_bounds,
 8511                        content_origin,
 8512                        visible_row_range,
 8513                        line_layouts,
 8514                        line_height,
 8515                        scroll_pixel_position,
 8516                        newest_selection_head,
 8517                        target_display_point,
 8518                        window,
 8519                        cx,
 8520                    )
 8521                } else {
 8522                    self.render_edit_prediction_eager_jump_popover(
 8523                        text_bounds,
 8524                        content_origin,
 8525                        editor_snapshot,
 8526                        visible_row_range,
 8527                        scroll_top,
 8528                        scroll_bottom,
 8529                        line_height,
 8530                        scroll_pixel_position,
 8531                        target_display_point,
 8532                        editor_width,
 8533                        window,
 8534                        cx,
 8535                    )
 8536                }
 8537            }
 8538            EditPrediction::Edit {
 8539                display_mode: EditDisplayMode::Inline,
 8540                ..
 8541            } => None,
 8542            EditPrediction::Edit {
 8543                display_mode: EditDisplayMode::TabAccept,
 8544                edits,
 8545                ..
 8546            } => {
 8547                let range = &edits.first()?.0;
 8548                let target_display_point = range.end.to_display_point(editor_snapshot);
 8549
 8550                self.render_edit_prediction_end_of_line_popover(
 8551                    "Accept",
 8552                    editor_snapshot,
 8553                    visible_row_range,
 8554                    target_display_point,
 8555                    line_height,
 8556                    scroll_pixel_position,
 8557                    content_origin,
 8558                    editor_width,
 8559                    window,
 8560                    cx,
 8561                )
 8562            }
 8563            EditPrediction::Edit {
 8564                edits,
 8565                edit_preview,
 8566                display_mode: EditDisplayMode::DiffPopover,
 8567                snapshot,
 8568            } => self.render_edit_prediction_diff_popover(
 8569                text_bounds,
 8570                content_origin,
 8571                right_margin,
 8572                editor_snapshot,
 8573                visible_row_range,
 8574                line_layouts,
 8575                line_height,
 8576                scroll_position,
 8577                scroll_pixel_position,
 8578                newest_selection_head,
 8579                editor_width,
 8580                style,
 8581                edits,
 8582                edit_preview,
 8583                snapshot,
 8584                window,
 8585                cx,
 8586            ),
 8587            EditPrediction::MoveOutside { snapshot, .. } => {
 8588                let file_name = snapshot
 8589                    .file()
 8590                    .map(|file| file.file_name(cx))
 8591                    .unwrap_or("untitled");
 8592                let mut element = self
 8593                    .render_edit_prediction_line_popover(
 8594                        format!("Jump to {file_name}"),
 8595                        Some(IconName::ZedPredict),
 8596                        window,
 8597                        cx,
 8598                    )
 8599                    .into_any();
 8600
 8601                let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8602                let origin_x = text_bounds.size.width / 2. - size.width / 2.;
 8603                let origin_y = text_bounds.size.height - size.height - px(30.);
 8604                let origin = text_bounds.origin + gpui::Point::new(origin_x, origin_y);
 8605                element.prepaint_at(origin, window, cx);
 8606
 8607                Some((element, origin))
 8608            }
 8609        }
 8610    }
 8611
 8612    fn render_edit_prediction_modifier_jump_popover(
 8613        &mut self,
 8614        text_bounds: &Bounds<Pixels>,
 8615        content_origin: gpui::Point<Pixels>,
 8616        visible_row_range: Range<DisplayRow>,
 8617        line_layouts: &[LineWithInvisibles],
 8618        line_height: Pixels,
 8619        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8620        newest_selection_head: Option<DisplayPoint>,
 8621        target_display_point: DisplayPoint,
 8622        window: &mut Window,
 8623        cx: &mut App,
 8624    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8625        let scrolled_content_origin =
 8626            content_origin - gpui::Point::new(scroll_pixel_position.x.into(), Pixels::ZERO);
 8627
 8628        const SCROLL_PADDING_Y: Pixels = px(12.);
 8629
 8630        if target_display_point.row() < visible_row_range.start {
 8631            return self.render_edit_prediction_scroll_popover(
 8632                |_| SCROLL_PADDING_Y,
 8633                IconName::ArrowUp,
 8634                visible_row_range,
 8635                line_layouts,
 8636                newest_selection_head,
 8637                scrolled_content_origin,
 8638                window,
 8639                cx,
 8640            );
 8641        } else if target_display_point.row() >= visible_row_range.end {
 8642            return self.render_edit_prediction_scroll_popover(
 8643                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8644                IconName::ArrowDown,
 8645                visible_row_range,
 8646                line_layouts,
 8647                newest_selection_head,
 8648                scrolled_content_origin,
 8649                window,
 8650                cx,
 8651            );
 8652        }
 8653
 8654        const POLE_WIDTH: Pixels = px(2.);
 8655
 8656        let line_layout =
 8657            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8658        let target_column = target_display_point.column() as usize;
 8659
 8660        let target_x = line_layout.x_for_index(target_column);
 8661        let target_y = (target_display_point.row().as_f64() * f64::from(line_height))
 8662            - scroll_pixel_position.y;
 8663
 8664        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8665
 8666        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8667        border_color.l += 0.001;
 8668
 8669        let mut element = v_flex()
 8670            .items_end()
 8671            .when(flag_on_right, |el| el.items_start())
 8672            .child(if flag_on_right {
 8673                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8674                    .rounded_bl(px(0.))
 8675                    .rounded_tl(px(0.))
 8676                    .border_l_2()
 8677                    .border_color(border_color)
 8678            } else {
 8679                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8680                    .rounded_br(px(0.))
 8681                    .rounded_tr(px(0.))
 8682                    .border_r_2()
 8683                    .border_color(border_color)
 8684            })
 8685            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8686            .into_any();
 8687
 8688        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8689
 8690        let mut origin = scrolled_content_origin + point(target_x, target_y.into())
 8691            - point(
 8692                if flag_on_right {
 8693                    POLE_WIDTH
 8694                } else {
 8695                    size.width - POLE_WIDTH
 8696                },
 8697                size.height - line_height,
 8698            );
 8699
 8700        origin.x = origin.x.max(content_origin.x);
 8701
 8702        element.prepaint_at(origin, window, cx);
 8703
 8704        Some((element, origin))
 8705    }
 8706
 8707    fn render_edit_prediction_scroll_popover(
 8708        &mut self,
 8709        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8710        scroll_icon: IconName,
 8711        visible_row_range: Range<DisplayRow>,
 8712        line_layouts: &[LineWithInvisibles],
 8713        newest_selection_head: Option<DisplayPoint>,
 8714        scrolled_content_origin: gpui::Point<Pixels>,
 8715        window: &mut Window,
 8716        cx: &mut App,
 8717    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8718        let mut element = self
 8719            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)
 8720            .into_any();
 8721
 8722        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8723
 8724        let cursor = newest_selection_head?;
 8725        let cursor_row_layout =
 8726            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8727        let cursor_column = cursor.column() as usize;
 8728
 8729        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8730
 8731        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8732
 8733        element.prepaint_at(origin, window, cx);
 8734        Some((element, origin))
 8735    }
 8736
 8737    fn render_edit_prediction_eager_jump_popover(
 8738        &mut self,
 8739        text_bounds: &Bounds<Pixels>,
 8740        content_origin: gpui::Point<Pixels>,
 8741        editor_snapshot: &EditorSnapshot,
 8742        visible_row_range: Range<DisplayRow>,
 8743        scroll_top: ScrollOffset,
 8744        scroll_bottom: ScrollOffset,
 8745        line_height: Pixels,
 8746        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8747        target_display_point: DisplayPoint,
 8748        editor_width: Pixels,
 8749        window: &mut Window,
 8750        cx: &mut App,
 8751    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8752        if target_display_point.row().as_f64() < scroll_top {
 8753            let mut element = self
 8754                .render_edit_prediction_line_popover(
 8755                    "Jump to Edit",
 8756                    Some(IconName::ArrowUp),
 8757                    window,
 8758                    cx,
 8759                )
 8760                .into_any();
 8761
 8762            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8763            let offset = point(
 8764                (text_bounds.size.width - size.width) / 2.,
 8765                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8766            );
 8767
 8768            let origin = text_bounds.origin + offset;
 8769            element.prepaint_at(origin, window, cx);
 8770            Some((element, origin))
 8771        } else if (target_display_point.row().as_f64() + 1.) > scroll_bottom {
 8772            let mut element = self
 8773                .render_edit_prediction_line_popover(
 8774                    "Jump to Edit",
 8775                    Some(IconName::ArrowDown),
 8776                    window,
 8777                    cx,
 8778                )
 8779                .into_any();
 8780
 8781            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8782            let offset = point(
 8783                (text_bounds.size.width - size.width) / 2.,
 8784                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8785            );
 8786
 8787            let origin = text_bounds.origin + offset;
 8788            element.prepaint_at(origin, window, cx);
 8789            Some((element, origin))
 8790        } else {
 8791            self.render_edit_prediction_end_of_line_popover(
 8792                "Jump to Edit",
 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    }
 8805
 8806    fn render_edit_prediction_end_of_line_popover(
 8807        self: &mut Editor,
 8808        label: &'static str,
 8809        editor_snapshot: &EditorSnapshot,
 8810        visible_row_range: Range<DisplayRow>,
 8811        target_display_point: DisplayPoint,
 8812        line_height: Pixels,
 8813        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8814        content_origin: gpui::Point<Pixels>,
 8815        editor_width: Pixels,
 8816        window: &mut Window,
 8817        cx: &mut App,
 8818    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8819        let target_line_end = DisplayPoint::new(
 8820            target_display_point.row(),
 8821            editor_snapshot.line_len(target_display_point.row()),
 8822        );
 8823
 8824        let mut element = self
 8825            .render_edit_prediction_line_popover(label, None, window, cx)
 8826            .into_any();
 8827
 8828        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8829
 8830        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8831
 8832        let start_point = content_origin - point(scroll_pixel_position.x.into(), Pixels::ZERO);
 8833        let mut origin = start_point
 8834            + line_origin
 8835            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8836        origin.x = origin.x.max(content_origin.x);
 8837
 8838        let max_x = content_origin.x + editor_width - size.width;
 8839
 8840        if origin.x > max_x {
 8841            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8842
 8843            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8844                origin.y += offset;
 8845                IconName::ArrowUp
 8846            } else {
 8847                origin.y -= offset;
 8848                IconName::ArrowDown
 8849            };
 8850
 8851            element = self
 8852                .render_edit_prediction_line_popover(label, Some(icon), window, cx)
 8853                .into_any();
 8854
 8855            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8856
 8857            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8858        }
 8859
 8860        element.prepaint_at(origin, window, cx);
 8861        Some((element, origin))
 8862    }
 8863
 8864    fn render_edit_prediction_diff_popover(
 8865        self: &Editor,
 8866        text_bounds: &Bounds<Pixels>,
 8867        content_origin: gpui::Point<Pixels>,
 8868        right_margin: Pixels,
 8869        editor_snapshot: &EditorSnapshot,
 8870        visible_row_range: Range<DisplayRow>,
 8871        line_layouts: &[LineWithInvisibles],
 8872        line_height: Pixels,
 8873        scroll_position: gpui::Point<ScrollOffset>,
 8874        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8875        newest_selection_head: Option<DisplayPoint>,
 8876        editor_width: Pixels,
 8877        style: &EditorStyle,
 8878        edits: &Vec<(Range<Anchor>, String)>,
 8879        edit_preview: &Option<language::EditPreview>,
 8880        snapshot: &language::BufferSnapshot,
 8881        window: &mut Window,
 8882        cx: &mut App,
 8883    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8884        let edit_start = edits
 8885            .first()
 8886            .unwrap()
 8887            .0
 8888            .start
 8889            .to_display_point(editor_snapshot);
 8890        let edit_end = edits
 8891            .last()
 8892            .unwrap()
 8893            .0
 8894            .end
 8895            .to_display_point(editor_snapshot);
 8896
 8897        let is_visible = visible_row_range.contains(&edit_start.row())
 8898            || visible_row_range.contains(&edit_end.row());
 8899        if !is_visible {
 8900            return None;
 8901        }
 8902
 8903        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 8904            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 8905        } else {
 8906            // Fallback for providers without edit_preview
 8907            crate::edit_prediction_fallback_text(edits, cx)
 8908        };
 8909
 8910        let styled_text = highlighted_edits.to_styled_text(&style.text);
 8911        let line_count = highlighted_edits.text.lines().count();
 8912
 8913        const BORDER_WIDTH: Pixels = px(1.);
 8914
 8915        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8916        let has_keybind = keybind.is_some();
 8917
 8918        let mut element = h_flex()
 8919            .items_start()
 8920            .child(
 8921                h_flex()
 8922                    .bg(cx.theme().colors().editor_background)
 8923                    .border(BORDER_WIDTH)
 8924                    .shadow_xs()
 8925                    .border_color(cx.theme().colors().border)
 8926                    .rounded_l_lg()
 8927                    .when(line_count > 1, |el| el.rounded_br_lg())
 8928                    .pr_1()
 8929                    .child(styled_text),
 8930            )
 8931            .child(
 8932                h_flex()
 8933                    .h(line_height + BORDER_WIDTH * 2.)
 8934                    .px_1p5()
 8935                    .gap_1()
 8936                    // Workaround: For some reason, there's a gap if we don't do this
 8937                    .ml(-BORDER_WIDTH)
 8938                    .shadow(vec![gpui::BoxShadow {
 8939                        color: gpui::black().opacity(0.05),
 8940                        offset: point(px(1.), px(1.)),
 8941                        blur_radius: px(2.),
 8942                        spread_radius: px(0.),
 8943                    }])
 8944                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 8945                    .border(BORDER_WIDTH)
 8946                    .border_color(cx.theme().colors().border)
 8947                    .rounded_r_lg()
 8948                    .id("edit_prediction_diff_popover_keybind")
 8949                    .when(!has_keybind, |el| {
 8950                        let status_colors = cx.theme().status();
 8951
 8952                        el.bg(status_colors.error_background)
 8953                            .border_color(status_colors.error.opacity(0.6))
 8954                            .child(Icon::new(IconName::Info).color(Color::Error))
 8955                            .cursor_default()
 8956                            .hoverable_tooltip(move |_window, cx| {
 8957                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8958                            })
 8959                    })
 8960                    .children(keybind),
 8961            )
 8962            .into_any();
 8963
 8964        let longest_row =
 8965            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 8966        let longest_line_width = if visible_row_range.contains(&longest_row) {
 8967            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 8968        } else {
 8969            layout_line(
 8970                longest_row,
 8971                editor_snapshot,
 8972                style,
 8973                editor_width,
 8974                |_| false,
 8975                window,
 8976                cx,
 8977            )
 8978            .width
 8979        };
 8980
 8981        let viewport_bounds =
 8982            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 8983                right: -right_margin,
 8984                ..Default::default()
 8985            });
 8986
 8987        let x_after_longest = Pixels::from(
 8988            ScrollPixelOffset::from(
 8989                text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X,
 8990            ) - scroll_pixel_position.x,
 8991        );
 8992
 8993        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8994
 8995        // Fully visible if it can be displayed within the window (allow overlapping other
 8996        // panes). However, this is only allowed if the popover starts within text_bounds.
 8997        let can_position_to_the_right = x_after_longest < text_bounds.right()
 8998            && x_after_longest + element_bounds.width < viewport_bounds.right();
 8999
 9000        let mut origin = if can_position_to_the_right {
 9001            point(
 9002                x_after_longest,
 9003                text_bounds.origin.y
 9004                    + Pixels::from(
 9005                        edit_start.row().as_f64() * ScrollPixelOffset::from(line_height)
 9006                            - scroll_pixel_position.y,
 9007                    ),
 9008            )
 9009        } else {
 9010            let cursor_row = newest_selection_head.map(|head| head.row());
 9011            let above_edit = edit_start
 9012                .row()
 9013                .0
 9014                .checked_sub(line_count as u32)
 9015                .map(DisplayRow);
 9016            let below_edit = Some(edit_end.row() + 1);
 9017            let above_cursor =
 9018                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 9019            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 9020
 9021            // Place the edit popover adjacent to the edit if there is a location
 9022            // available that is onscreen and does not obscure the cursor. Otherwise,
 9023            // place it adjacent to the cursor.
 9024            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 9025                .into_iter()
 9026                .flatten()
 9027                .find(|&start_row| {
 9028                    let end_row = start_row + line_count as u32;
 9029                    visible_row_range.contains(&start_row)
 9030                        && visible_row_range.contains(&end_row)
 9031                        && cursor_row
 9032                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9033                })?;
 9034
 9035            content_origin
 9036                + point(
 9037                    Pixels::from(-scroll_pixel_position.x),
 9038                    Pixels::from(
 9039                        (row_target.as_f64() - scroll_position.y) * f64::from(line_height),
 9040                    ),
 9041                )
 9042        };
 9043
 9044        origin.x -= BORDER_WIDTH;
 9045
 9046        window.defer_draw(element, origin, 1);
 9047
 9048        // Do not return an element, since it will already be drawn due to defer_draw.
 9049        None
 9050    }
 9051
 9052    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9053        px(30.)
 9054    }
 9055
 9056    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9057        if self.read_only(cx) {
 9058            cx.theme().players().read_only()
 9059        } else {
 9060            self.style.as_ref().unwrap().local_player
 9061        }
 9062    }
 9063
 9064    fn render_edit_prediction_accept_keybind(
 9065        &self,
 9066        window: &mut Window,
 9067        cx: &mut App,
 9068    ) -> Option<AnyElement> {
 9069        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 9070        let accept_keystroke = accept_binding.keystroke()?;
 9071
 9072        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9073
 9074        let modifiers_color = if *accept_keystroke.modifiers() == window.modifiers() {
 9075            Color::Accent
 9076        } else {
 9077            Color::Muted
 9078        };
 9079
 9080        h_flex()
 9081            .px_0p5()
 9082            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9083            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9084            .text_size(TextSize::XSmall.rems(cx))
 9085            .child(h_flex().children(ui::render_modifiers(
 9086                accept_keystroke.modifiers(),
 9087                PlatformStyle::platform(),
 9088                Some(modifiers_color),
 9089                Some(IconSize::XSmall.rems().into()),
 9090                true,
 9091            )))
 9092            .when(is_platform_style_mac, |parent| {
 9093                parent.child(accept_keystroke.key().to_string())
 9094            })
 9095            .when(!is_platform_style_mac, |parent| {
 9096                parent.child(
 9097                    Key::new(
 9098                        util::capitalize(accept_keystroke.key()),
 9099                        Some(Color::Default),
 9100                    )
 9101                    .size(Some(IconSize::XSmall.rems().into())),
 9102                )
 9103            })
 9104            .into_any()
 9105            .into()
 9106    }
 9107
 9108    fn render_edit_prediction_line_popover(
 9109        &self,
 9110        label: impl Into<SharedString>,
 9111        icon: Option<IconName>,
 9112        window: &mut Window,
 9113        cx: &mut App,
 9114    ) -> Stateful<Div> {
 9115        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9116
 9117        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9118        let has_keybind = keybind.is_some();
 9119
 9120        h_flex()
 9121            .id("ep-line-popover")
 9122            .py_0p5()
 9123            .pl_1()
 9124            .pr(padding_right)
 9125            .gap_1()
 9126            .rounded_md()
 9127            .border_1()
 9128            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9129            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9130            .shadow_xs()
 9131            .when(!has_keybind, |el| {
 9132                let status_colors = cx.theme().status();
 9133
 9134                el.bg(status_colors.error_background)
 9135                    .border_color(status_colors.error.opacity(0.6))
 9136                    .pl_2()
 9137                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9138                    .cursor_default()
 9139                    .hoverable_tooltip(move |_window, cx| {
 9140                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9141                    })
 9142            })
 9143            .children(keybind)
 9144            .child(
 9145                Label::new(label)
 9146                    .size(LabelSize::Small)
 9147                    .when(!has_keybind, |el| {
 9148                        el.color(cx.theme().status().error.into()).strikethrough()
 9149                    }),
 9150            )
 9151            .when(!has_keybind, |el| {
 9152                el.child(
 9153                    h_flex().ml_1().child(
 9154                        Icon::new(IconName::Info)
 9155                            .size(IconSize::Small)
 9156                            .color(cx.theme().status().error.into()),
 9157                    ),
 9158                )
 9159            })
 9160            .when_some(icon, |element, icon| {
 9161                element.child(
 9162                    div()
 9163                        .mt(px(1.5))
 9164                        .child(Icon::new(icon).size(IconSize::Small)),
 9165                )
 9166            })
 9167    }
 9168
 9169    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9170        let accent_color = cx.theme().colors().text_accent;
 9171        let editor_bg_color = cx.theme().colors().editor_background;
 9172        editor_bg_color.blend(accent_color.opacity(0.1))
 9173    }
 9174
 9175    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9176        let accent_color = cx.theme().colors().text_accent;
 9177        let editor_bg_color = cx.theme().colors().editor_background;
 9178        editor_bg_color.blend(accent_color.opacity(0.6))
 9179    }
 9180    fn get_prediction_provider_icon_name(
 9181        provider: &Option<RegisteredEditPredictionProvider>,
 9182    ) -> IconName {
 9183        match provider {
 9184            Some(provider) => match provider.provider.name() {
 9185                "copilot" => IconName::Copilot,
 9186                "supermaven" => IconName::Supermaven,
 9187                _ => IconName::ZedPredict,
 9188            },
 9189            None => IconName::ZedPredict,
 9190        }
 9191    }
 9192
 9193    fn render_edit_prediction_cursor_popover(
 9194        &self,
 9195        min_width: Pixels,
 9196        max_width: Pixels,
 9197        cursor_point: Point,
 9198        style: &EditorStyle,
 9199        accept_keystroke: Option<&gpui::KeybindingKeystroke>,
 9200        _window: &Window,
 9201        cx: &mut Context<Editor>,
 9202    ) -> Option<AnyElement> {
 9203        let provider = self.edit_prediction_provider.as_ref()?;
 9204        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9205
 9206        let is_refreshing = provider.provider.is_refreshing(cx);
 9207
 9208        fn pending_completion_container(icon: IconName) -> Div {
 9209            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9210        }
 9211
 9212        let completion = match &self.active_edit_prediction {
 9213            Some(prediction) => {
 9214                if !self.has_visible_completions_menu() {
 9215                    const RADIUS: Pixels = px(6.);
 9216                    const BORDER_WIDTH: Pixels = px(1.);
 9217
 9218                    return Some(
 9219                        h_flex()
 9220                            .elevation_2(cx)
 9221                            .border(BORDER_WIDTH)
 9222                            .border_color(cx.theme().colors().border)
 9223                            .when(accept_keystroke.is_none(), |el| {
 9224                                el.border_color(cx.theme().status().error)
 9225                            })
 9226                            .rounded(RADIUS)
 9227                            .rounded_tl(px(0.))
 9228                            .overflow_hidden()
 9229                            .child(div().px_1p5().child(match &prediction.completion {
 9230                                EditPrediction::MoveWithin { target, snapshot } => {
 9231                                    use text::ToPoint as _;
 9232                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9233                                    {
 9234                                        Icon::new(IconName::ZedPredictDown)
 9235                                    } else {
 9236                                        Icon::new(IconName::ZedPredictUp)
 9237                                    }
 9238                                }
 9239                                EditPrediction::MoveOutside { .. } => {
 9240                                    // TODO [zeta2] custom icon for external jump?
 9241                                    Icon::new(provider_icon)
 9242                                }
 9243                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9244                            }))
 9245                            .child(
 9246                                h_flex()
 9247                                    .gap_1()
 9248                                    .py_1()
 9249                                    .px_2()
 9250                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9251                                    .border_l_1()
 9252                                    .border_color(cx.theme().colors().border)
 9253                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9254                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9255                                        el.child(
 9256                                            Label::new("Hold")
 9257                                                .size(LabelSize::Small)
 9258                                                .when(accept_keystroke.is_none(), |el| {
 9259                                                    el.strikethrough()
 9260                                                })
 9261                                                .line_height_style(LineHeightStyle::UiLabel),
 9262                                        )
 9263                                    })
 9264                                    .id("edit_prediction_cursor_popover_keybind")
 9265                                    .when(accept_keystroke.is_none(), |el| {
 9266                                        let status_colors = cx.theme().status();
 9267
 9268                                        el.bg(status_colors.error_background)
 9269                                            .border_color(status_colors.error.opacity(0.6))
 9270                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9271                                            .cursor_default()
 9272                                            .hoverable_tooltip(move |_window, cx| {
 9273                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9274                                                    .into()
 9275                                            })
 9276                                    })
 9277                                    .when_some(
 9278                                        accept_keystroke.as_ref(),
 9279                                        |el, accept_keystroke| {
 9280                                            el.child(h_flex().children(ui::render_modifiers(
 9281                                                accept_keystroke.modifiers(),
 9282                                                PlatformStyle::platform(),
 9283                                                Some(Color::Default),
 9284                                                Some(IconSize::XSmall.rems().into()),
 9285                                                false,
 9286                                            )))
 9287                                        },
 9288                                    ),
 9289                            )
 9290                            .into_any(),
 9291                    );
 9292                }
 9293
 9294                self.render_edit_prediction_cursor_popover_preview(
 9295                    prediction,
 9296                    cursor_point,
 9297                    style,
 9298                    cx,
 9299                )?
 9300            }
 9301
 9302            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9303                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9304                    stale_completion,
 9305                    cursor_point,
 9306                    style,
 9307                    cx,
 9308                )?,
 9309
 9310                None => pending_completion_container(provider_icon)
 9311                    .child(Label::new("...").size(LabelSize::Small)),
 9312            },
 9313
 9314            None => pending_completion_container(provider_icon)
 9315                .child(Label::new("...").size(LabelSize::Small)),
 9316        };
 9317
 9318        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9319            completion
 9320                .with_animation(
 9321                    "loading-completion",
 9322                    Animation::new(Duration::from_secs(2))
 9323                        .repeat()
 9324                        .with_easing(pulsating_between(0.4, 0.8)),
 9325                    |label, delta| label.opacity(delta),
 9326                )
 9327                .into_any_element()
 9328        } else {
 9329            completion.into_any_element()
 9330        };
 9331
 9332        let has_completion = self.active_edit_prediction.is_some();
 9333
 9334        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9335        Some(
 9336            h_flex()
 9337                .min_w(min_width)
 9338                .max_w(max_width)
 9339                .flex_1()
 9340                .elevation_2(cx)
 9341                .border_color(cx.theme().colors().border)
 9342                .child(
 9343                    div()
 9344                        .flex_1()
 9345                        .py_1()
 9346                        .px_2()
 9347                        .overflow_hidden()
 9348                        .child(completion),
 9349                )
 9350                .when_some(accept_keystroke, |el, accept_keystroke| {
 9351                    if !accept_keystroke.modifiers().modified() {
 9352                        return el;
 9353                    }
 9354
 9355                    el.child(
 9356                        h_flex()
 9357                            .h_full()
 9358                            .border_l_1()
 9359                            .rounded_r_lg()
 9360                            .border_color(cx.theme().colors().border)
 9361                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9362                            .gap_1()
 9363                            .py_1()
 9364                            .px_2()
 9365                            .child(
 9366                                h_flex()
 9367                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9368                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9369                                    .child(h_flex().children(ui::render_modifiers(
 9370                                        accept_keystroke.modifiers(),
 9371                                        PlatformStyle::platform(),
 9372                                        Some(if !has_completion {
 9373                                            Color::Muted
 9374                                        } else {
 9375                                            Color::Default
 9376                                        }),
 9377                                        None,
 9378                                        false,
 9379                                    ))),
 9380                            )
 9381                            .child(Label::new("Preview").into_any_element())
 9382                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9383                    )
 9384                })
 9385                .into_any(),
 9386        )
 9387    }
 9388
 9389    fn render_edit_prediction_cursor_popover_preview(
 9390        &self,
 9391        completion: &EditPredictionState,
 9392        cursor_point: Point,
 9393        style: &EditorStyle,
 9394        cx: &mut Context<Editor>,
 9395    ) -> Option<Div> {
 9396        use text::ToPoint as _;
 9397
 9398        fn render_relative_row_jump(
 9399            prefix: impl Into<String>,
 9400            current_row: u32,
 9401            target_row: u32,
 9402        ) -> Div {
 9403            let (row_diff, arrow) = if target_row < current_row {
 9404                (current_row - target_row, IconName::ArrowUp)
 9405            } else {
 9406                (target_row - current_row, IconName::ArrowDown)
 9407            };
 9408
 9409            h_flex()
 9410                .child(
 9411                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9412                        .color(Color::Muted)
 9413                        .size(LabelSize::Small),
 9414                )
 9415                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9416        }
 9417
 9418        let supports_jump = self
 9419            .edit_prediction_provider
 9420            .as_ref()
 9421            .map(|provider| provider.provider.supports_jump_to_edit())
 9422            .unwrap_or(true);
 9423
 9424        match &completion.completion {
 9425            EditPrediction::MoveWithin {
 9426                target, snapshot, ..
 9427            } => {
 9428                if !supports_jump {
 9429                    return None;
 9430                }
 9431
 9432                Some(
 9433                    h_flex()
 9434                        .px_2()
 9435                        .gap_2()
 9436                        .flex_1()
 9437                        .child(
 9438                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
 9439                                Icon::new(IconName::ZedPredictDown)
 9440                            } else {
 9441                                Icon::new(IconName::ZedPredictUp)
 9442                            },
 9443                        )
 9444                        .child(Label::new("Jump to Edit")),
 9445                )
 9446            }
 9447            EditPrediction::MoveOutside { snapshot, .. } => {
 9448                let file_name = snapshot
 9449                    .file()
 9450                    .map(|file| file.file_name(cx))
 9451                    .unwrap_or("untitled");
 9452                Some(
 9453                    h_flex()
 9454                        .px_2()
 9455                        .gap_2()
 9456                        .flex_1()
 9457                        .child(Icon::new(IconName::ZedPredict))
 9458                        .child(Label::new(format!("Jump to {file_name}"))),
 9459                )
 9460            }
 9461            EditPrediction::Edit {
 9462                edits,
 9463                edit_preview,
 9464                snapshot,
 9465                display_mode: _,
 9466            } => {
 9467                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
 9468
 9469                let (highlighted_edits, has_more_lines) =
 9470                    if let Some(edit_preview) = edit_preview.as_ref() {
 9471                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
 9472                            .first_line_preview()
 9473                    } else {
 9474                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
 9475                    };
 9476
 9477                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9478                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9479
 9480                let preview = h_flex()
 9481                    .gap_1()
 9482                    .min_w_16()
 9483                    .child(styled_text)
 9484                    .when(has_more_lines, |parent| parent.child("…"));
 9485
 9486                let left = if supports_jump && first_edit_row != cursor_point.row {
 9487                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9488                        .into_any_element()
 9489                } else {
 9490                    let icon_name =
 9491                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9492                    Icon::new(icon_name).into_any_element()
 9493                };
 9494
 9495                Some(
 9496                    h_flex()
 9497                        .h_full()
 9498                        .flex_1()
 9499                        .gap_2()
 9500                        .pr_1()
 9501                        .overflow_x_hidden()
 9502                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9503                        .child(left)
 9504                        .child(preview),
 9505                )
 9506            }
 9507        }
 9508    }
 9509
 9510    pub fn render_context_menu(
 9511        &self,
 9512        style: &EditorStyle,
 9513        max_height_in_lines: u32,
 9514        window: &mut Window,
 9515        cx: &mut Context<Editor>,
 9516    ) -> Option<AnyElement> {
 9517        let menu = self.context_menu.borrow();
 9518        let menu = menu.as_ref()?;
 9519        if !menu.visible() {
 9520            return None;
 9521        };
 9522        Some(menu.render(style, max_height_in_lines, window, cx))
 9523    }
 9524
 9525    fn render_context_menu_aside(
 9526        &mut self,
 9527        max_size: Size<Pixels>,
 9528        window: &mut Window,
 9529        cx: &mut Context<Editor>,
 9530    ) -> Option<AnyElement> {
 9531        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9532            if menu.visible() {
 9533                menu.render_aside(max_size, window, cx)
 9534            } else {
 9535                None
 9536            }
 9537        })
 9538    }
 9539
 9540    fn hide_context_menu(
 9541        &mut self,
 9542        window: &mut Window,
 9543        cx: &mut Context<Self>,
 9544    ) -> Option<CodeContextMenu> {
 9545        cx.notify();
 9546        self.completion_tasks.clear();
 9547        let context_menu = self.context_menu.borrow_mut().take();
 9548        self.stale_edit_prediction_in_menu.take();
 9549        self.update_visible_edit_prediction(window, cx);
 9550        if let Some(CodeContextMenu::Completions(_)) = &context_menu
 9551            && let Some(completion_provider) = &self.completion_provider
 9552        {
 9553            completion_provider.selection_changed(None, window, cx);
 9554        }
 9555        context_menu
 9556    }
 9557
 9558    fn show_snippet_choices(
 9559        &mut self,
 9560        choices: &Vec<String>,
 9561        selection: Range<Anchor>,
 9562        cx: &mut Context<Self>,
 9563    ) {
 9564        let Some((_, buffer, _)) = self
 9565            .buffer()
 9566            .read(cx)
 9567            .excerpt_containing(selection.start, cx)
 9568        else {
 9569            return;
 9570        };
 9571        let Some((_, end_buffer, _)) = self.buffer().read(cx).excerpt_containing(selection.end, cx)
 9572        else {
 9573            return;
 9574        };
 9575        if buffer != end_buffer {
 9576            log::error!("expected anchor range to have matching buffer IDs");
 9577            return;
 9578        }
 9579
 9580        let id = post_inc(&mut self.next_completion_id);
 9581        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9582        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9583            CompletionsMenu::new_snippet_choices(
 9584                id,
 9585                true,
 9586                choices,
 9587                selection,
 9588                buffer,
 9589                snippet_sort_order,
 9590            ),
 9591        ));
 9592    }
 9593
 9594    pub fn insert_snippet(
 9595        &mut self,
 9596        insertion_ranges: &[Range<usize>],
 9597        snippet: Snippet,
 9598        window: &mut Window,
 9599        cx: &mut Context<Self>,
 9600    ) -> Result<()> {
 9601        struct Tabstop<T> {
 9602            is_end_tabstop: bool,
 9603            ranges: Vec<Range<T>>,
 9604            choices: Option<Vec<String>>,
 9605        }
 9606
 9607        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9608            let snippet_text: Arc<str> = snippet.text.clone().into();
 9609            let edits = insertion_ranges
 9610                .iter()
 9611                .cloned()
 9612                .map(|range| (range, snippet_text.clone()));
 9613            let autoindent_mode = AutoindentMode::Block {
 9614                original_indent_columns: Vec::new(),
 9615            };
 9616            buffer.edit(edits, Some(autoindent_mode), cx);
 9617
 9618            let snapshot = &*buffer.read(cx);
 9619            let snippet = &snippet;
 9620            snippet
 9621                .tabstops
 9622                .iter()
 9623                .map(|tabstop| {
 9624                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
 9625                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9626                    });
 9627                    let mut tabstop_ranges = tabstop
 9628                        .ranges
 9629                        .iter()
 9630                        .flat_map(|tabstop_range| {
 9631                            let mut delta = 0_isize;
 9632                            insertion_ranges.iter().map(move |insertion_range| {
 9633                                let insertion_start = insertion_range.start as isize + delta;
 9634                                delta +=
 9635                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9636
 9637                                let start = ((insertion_start + tabstop_range.start) as usize)
 9638                                    .min(snapshot.len());
 9639                                let end = ((insertion_start + tabstop_range.end) as usize)
 9640                                    .min(snapshot.len());
 9641                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9642                            })
 9643                        })
 9644                        .collect::<Vec<_>>();
 9645                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9646
 9647                    Tabstop {
 9648                        is_end_tabstop,
 9649                        ranges: tabstop_ranges,
 9650                        choices: tabstop.choices.clone(),
 9651                    }
 9652                })
 9653                .collect::<Vec<_>>()
 9654        });
 9655        if let Some(tabstop) = tabstops.first() {
 9656            self.change_selections(Default::default(), window, cx, |s| {
 9657                // Reverse order so that the first range is the newest created selection.
 9658                // Completions will use it and autoscroll will prioritize it.
 9659                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9660            });
 9661
 9662            if let Some(choices) = &tabstop.choices
 9663                && let Some(selection) = tabstop.ranges.first()
 9664            {
 9665                self.show_snippet_choices(choices, selection.clone(), cx)
 9666            }
 9667
 9668            // If we're already at the last tabstop and it's at the end of the snippet,
 9669            // we're done, we don't need to keep the state around.
 9670            if !tabstop.is_end_tabstop {
 9671                let choices = tabstops
 9672                    .iter()
 9673                    .map(|tabstop| tabstop.choices.clone())
 9674                    .collect();
 9675
 9676                let ranges = tabstops
 9677                    .into_iter()
 9678                    .map(|tabstop| tabstop.ranges)
 9679                    .collect::<Vec<_>>();
 9680
 9681                self.snippet_stack.push(SnippetState {
 9682                    active_index: 0,
 9683                    ranges,
 9684                    choices,
 9685                });
 9686            }
 9687
 9688            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9689            if self.autoclose_regions.is_empty() {
 9690                let snapshot = self.buffer.read(cx).snapshot(cx);
 9691                for selection in &mut self.selections.all::<Point>(&self.display_snapshot(cx)) {
 9692                    let selection_head = selection.head();
 9693                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9694                        continue;
 9695                    };
 9696
 9697                    let mut bracket_pair = None;
 9698                    let max_lookup_length = scope
 9699                        .brackets()
 9700                        .map(|(pair, _)| {
 9701                            pair.start
 9702                                .as_str()
 9703                                .chars()
 9704                                .count()
 9705                                .max(pair.end.as_str().chars().count())
 9706                        })
 9707                        .max();
 9708                    if let Some(max_lookup_length) = max_lookup_length {
 9709                        let next_text = snapshot
 9710                            .chars_at(selection_head)
 9711                            .take(max_lookup_length)
 9712                            .collect::<String>();
 9713                        let prev_text = snapshot
 9714                            .reversed_chars_at(selection_head)
 9715                            .take(max_lookup_length)
 9716                            .collect::<String>();
 9717
 9718                        for (pair, enabled) in scope.brackets() {
 9719                            if enabled
 9720                                && pair.close
 9721                                && prev_text.starts_with(pair.start.as_str())
 9722                                && next_text.starts_with(pair.end.as_str())
 9723                            {
 9724                                bracket_pair = Some(pair.clone());
 9725                                break;
 9726                            }
 9727                        }
 9728                    }
 9729
 9730                    if let Some(pair) = bracket_pair {
 9731                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9732                        let autoclose_enabled =
 9733                            self.use_autoclose && snapshot_settings.use_autoclose;
 9734                        if autoclose_enabled {
 9735                            let start = snapshot.anchor_after(selection_head);
 9736                            let end = snapshot.anchor_after(selection_head);
 9737                            self.autoclose_regions.push(AutocloseRegion {
 9738                                selection_id: selection.id,
 9739                                range: start..end,
 9740                                pair,
 9741                            });
 9742                        }
 9743                    }
 9744                }
 9745            }
 9746        }
 9747        Ok(())
 9748    }
 9749
 9750    pub fn move_to_next_snippet_tabstop(
 9751        &mut self,
 9752        window: &mut Window,
 9753        cx: &mut Context<Self>,
 9754    ) -> bool {
 9755        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9756    }
 9757
 9758    pub fn move_to_prev_snippet_tabstop(
 9759        &mut self,
 9760        window: &mut Window,
 9761        cx: &mut Context<Self>,
 9762    ) -> bool {
 9763        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9764    }
 9765
 9766    pub fn move_to_snippet_tabstop(
 9767        &mut self,
 9768        bias: Bias,
 9769        window: &mut Window,
 9770        cx: &mut Context<Self>,
 9771    ) -> bool {
 9772        if let Some(mut snippet) = self.snippet_stack.pop() {
 9773            match bias {
 9774                Bias::Left => {
 9775                    if snippet.active_index > 0 {
 9776                        snippet.active_index -= 1;
 9777                    } else {
 9778                        self.snippet_stack.push(snippet);
 9779                        return false;
 9780                    }
 9781                }
 9782                Bias::Right => {
 9783                    if snippet.active_index + 1 < snippet.ranges.len() {
 9784                        snippet.active_index += 1;
 9785                    } else {
 9786                        self.snippet_stack.push(snippet);
 9787                        return false;
 9788                    }
 9789                }
 9790            }
 9791            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9792                self.change_selections(Default::default(), window, cx, |s| {
 9793                    // Reverse order so that the first range is the newest created selection.
 9794                    // Completions will use it and autoscroll will prioritize it.
 9795                    s.select_ranges(current_ranges.iter().rev().cloned())
 9796                });
 9797
 9798                if let Some(choices) = &snippet.choices[snippet.active_index]
 9799                    && let Some(selection) = current_ranges.first()
 9800                {
 9801                    self.show_snippet_choices(choices, selection.clone(), cx);
 9802                }
 9803
 9804                // If snippet state is not at the last tabstop, push it back on the stack
 9805                if snippet.active_index + 1 < snippet.ranges.len() {
 9806                    self.snippet_stack.push(snippet);
 9807                }
 9808                return true;
 9809            }
 9810        }
 9811
 9812        false
 9813    }
 9814
 9815    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9816        self.transact(window, cx, |this, window, cx| {
 9817            this.select_all(&SelectAll, window, cx);
 9818            this.insert("", window, cx);
 9819        });
 9820    }
 9821
 9822    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9823        if self.read_only(cx) {
 9824            return;
 9825        }
 9826        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9827        self.transact(window, cx, |this, window, cx| {
 9828            this.select_autoclose_pair(window, cx);
 9829
 9830            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9831
 9832            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9833            if !this.linked_edit_ranges.is_empty() {
 9834                let selections = this.selections.all::<MultiBufferPoint>(&display_map);
 9835                let snapshot = this.buffer.read(cx).snapshot(cx);
 9836
 9837                for selection in selections.iter() {
 9838                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9839                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9840                    if selection_start.buffer_id != selection_end.buffer_id {
 9841                        continue;
 9842                    }
 9843                    if let Some(ranges) =
 9844                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9845                    {
 9846                        for (buffer, entries) in ranges {
 9847                            linked_ranges.entry(buffer).or_default().extend(entries);
 9848                        }
 9849                    }
 9850                }
 9851            }
 9852
 9853            let mut selections = this.selections.all::<MultiBufferPoint>(&display_map);
 9854            for selection in &mut selections {
 9855                if selection.is_empty() {
 9856                    let old_head = selection.head();
 9857                    let mut new_head =
 9858                        movement::left(&display_map, old_head.to_display_point(&display_map))
 9859                            .to_point(&display_map);
 9860                    if let Some((buffer, line_buffer_range)) = display_map
 9861                        .buffer_snapshot()
 9862                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 9863                    {
 9864                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 9865                        let indent_len = match indent_size.kind {
 9866                            IndentKind::Space => {
 9867                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 9868                            }
 9869                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 9870                        };
 9871                        if old_head.column <= indent_size.len && old_head.column > 0 {
 9872                            let indent_len = indent_len.get();
 9873                            new_head = cmp::min(
 9874                                new_head,
 9875                                MultiBufferPoint::new(
 9876                                    old_head.row,
 9877                                    ((old_head.column - 1) / indent_len) * indent_len,
 9878                                ),
 9879                            );
 9880                        }
 9881                    }
 9882
 9883                    selection.set_head(new_head, SelectionGoal::None);
 9884                }
 9885            }
 9886
 9887            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9888            this.insert("", window, cx);
 9889            let empty_str: Arc<str> = Arc::from("");
 9890            for (buffer, edits) in linked_ranges {
 9891                let snapshot = buffer.read(cx).snapshot();
 9892                use text::ToPoint as TP;
 9893
 9894                let edits = edits
 9895                    .into_iter()
 9896                    .map(|range| {
 9897                        let end_point = TP::to_point(&range.end, &snapshot);
 9898                        let mut start_point = TP::to_point(&range.start, &snapshot);
 9899
 9900                        if end_point == start_point {
 9901                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 9902                                .saturating_sub(1);
 9903                            start_point =
 9904                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 9905                        };
 9906
 9907                        (start_point..end_point, empty_str.clone())
 9908                    })
 9909                    .sorted_by_key(|(range, _)| range.start)
 9910                    .collect::<Vec<_>>();
 9911                buffer.update(cx, |this, cx| {
 9912                    this.edit(edits, None, cx);
 9913                })
 9914            }
 9915            this.refresh_edit_prediction(true, false, window, cx);
 9916            refresh_linked_ranges(this, window, cx);
 9917        });
 9918    }
 9919
 9920    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 9921        if self.read_only(cx) {
 9922            return;
 9923        }
 9924        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9925        self.transact(window, cx, |this, window, cx| {
 9926            this.change_selections(Default::default(), window, cx, |s| {
 9927                s.move_with(|map, selection| {
 9928                    if selection.is_empty() {
 9929                        let cursor = movement::right(map, selection.head());
 9930                        selection.end = cursor;
 9931                        selection.reversed = true;
 9932                        selection.goal = SelectionGoal::None;
 9933                    }
 9934                })
 9935            });
 9936            this.insert("", window, cx);
 9937            this.refresh_edit_prediction(true, false, window, cx);
 9938        });
 9939    }
 9940
 9941    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 9942        if self.mode.is_single_line() {
 9943            cx.propagate();
 9944            return;
 9945        }
 9946
 9947        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9948        if self.move_to_prev_snippet_tabstop(window, cx) {
 9949            return;
 9950        }
 9951        self.outdent(&Outdent, window, cx);
 9952    }
 9953
 9954    pub fn next_snippet_tabstop(
 9955        &mut self,
 9956        _: &NextSnippetTabstop,
 9957        window: &mut Window,
 9958        cx: &mut Context<Self>,
 9959    ) {
 9960        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
 9961            return;
 9962        }
 9963
 9964        if self.move_to_next_snippet_tabstop(window, cx) {
 9965            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9966            return;
 9967        }
 9968    }
 9969
 9970    pub fn previous_snippet_tabstop(
 9971        &mut self,
 9972        _: &PreviousSnippetTabstop,
 9973        window: &mut Window,
 9974        cx: &mut Context<Self>,
 9975    ) {
 9976        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
 9977            return;
 9978        }
 9979
 9980        if self.move_to_prev_snippet_tabstop(window, cx) {
 9981            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9982            return;
 9983        }
 9984    }
 9985
 9986    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 9987        if self.mode.is_single_line() {
 9988            cx.propagate();
 9989            return;
 9990        }
 9991
 9992        if self.move_to_next_snippet_tabstop(window, cx) {
 9993            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9994            return;
 9995        }
 9996        if self.read_only(cx) {
 9997            return;
 9998        }
 9999        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10000        let mut selections = self.selections.all_adjusted(&self.display_snapshot(cx));
10001        let buffer = self.buffer.read(cx);
10002        let snapshot = buffer.snapshot(cx);
10003        let rows_iter = selections.iter().map(|s| s.head().row);
10004        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
10005
10006        let has_some_cursor_in_whitespace = selections
10007            .iter()
10008            .filter(|selection| selection.is_empty())
10009            .any(|selection| {
10010                let cursor = selection.head();
10011                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10012                cursor.column < current_indent.len
10013            });
10014
10015        let mut edits = Vec::new();
10016        let mut prev_edited_row = 0;
10017        let mut row_delta = 0;
10018        for selection in &mut selections {
10019            if selection.start.row != prev_edited_row {
10020                row_delta = 0;
10021            }
10022            prev_edited_row = selection.end.row;
10023
10024            // If the selection is non-empty, then increase the indentation of the selected lines.
10025            if !selection.is_empty() {
10026                row_delta =
10027                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10028                continue;
10029            }
10030
10031            let cursor = selection.head();
10032            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10033            if let Some(suggested_indent) =
10034                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
10035            {
10036                // Don't do anything if already at suggested indent
10037                // and there is any other cursor which is not
10038                if has_some_cursor_in_whitespace
10039                    && cursor.column == current_indent.len
10040                    && current_indent.len == suggested_indent.len
10041                {
10042                    continue;
10043                }
10044
10045                // Adjust line and move cursor to suggested indent
10046                // if cursor is not at suggested indent
10047                if cursor.column < suggested_indent.len
10048                    && cursor.column <= current_indent.len
10049                    && current_indent.len <= suggested_indent.len
10050                {
10051                    selection.start = Point::new(cursor.row, suggested_indent.len);
10052                    selection.end = selection.start;
10053                    if row_delta == 0 {
10054                        edits.extend(Buffer::edit_for_indent_size_adjustment(
10055                            cursor.row,
10056                            current_indent,
10057                            suggested_indent,
10058                        ));
10059                        row_delta = suggested_indent.len - current_indent.len;
10060                    }
10061                    continue;
10062                }
10063
10064                // If current indent is more than suggested indent
10065                // only move cursor to current indent and skip indent
10066                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
10067                    selection.start = Point::new(cursor.row, current_indent.len);
10068                    selection.end = selection.start;
10069                    continue;
10070                }
10071            }
10072
10073            // Otherwise, insert a hard or soft tab.
10074            let settings = buffer.language_settings_at(cursor, cx);
10075            let tab_size = if settings.hard_tabs {
10076                IndentSize::tab()
10077            } else {
10078                let tab_size = settings.tab_size.get();
10079                let indent_remainder = snapshot
10080                    .text_for_range(Point::new(cursor.row, 0)..cursor)
10081                    .flat_map(str::chars)
10082                    .fold(row_delta % tab_size, |counter: u32, c| {
10083                        if c == '\t' {
10084                            0
10085                        } else {
10086                            (counter + 1) % tab_size
10087                        }
10088                    });
10089
10090                let chars_to_next_tab_stop = tab_size - indent_remainder;
10091                IndentSize::spaces(chars_to_next_tab_stop)
10092            };
10093            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
10094            selection.end = selection.start;
10095            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
10096            row_delta += tab_size.len;
10097        }
10098
10099        self.transact(window, cx, |this, window, cx| {
10100            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10101            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10102            this.refresh_edit_prediction(true, false, window, cx);
10103        });
10104    }
10105
10106    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10107        if self.read_only(cx) {
10108            return;
10109        }
10110        if self.mode.is_single_line() {
10111            cx.propagate();
10112            return;
10113        }
10114
10115        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10116        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
10117        let mut prev_edited_row = 0;
10118        let mut row_delta = 0;
10119        let mut edits = Vec::new();
10120        let buffer = self.buffer.read(cx);
10121        let snapshot = buffer.snapshot(cx);
10122        for selection in &mut selections {
10123            if selection.start.row != prev_edited_row {
10124                row_delta = 0;
10125            }
10126            prev_edited_row = selection.end.row;
10127
10128            row_delta =
10129                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10130        }
10131
10132        self.transact(window, cx, |this, window, cx| {
10133            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10134            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10135        });
10136    }
10137
10138    fn indent_selection(
10139        buffer: &MultiBuffer,
10140        snapshot: &MultiBufferSnapshot,
10141        selection: &mut Selection<Point>,
10142        edits: &mut Vec<(Range<Point>, String)>,
10143        delta_for_start_row: u32,
10144        cx: &App,
10145    ) -> u32 {
10146        let settings = buffer.language_settings_at(selection.start, cx);
10147        let tab_size = settings.tab_size.get();
10148        let indent_kind = if settings.hard_tabs {
10149            IndentKind::Tab
10150        } else {
10151            IndentKind::Space
10152        };
10153        let mut start_row = selection.start.row;
10154        let mut end_row = selection.end.row + 1;
10155
10156        // If a selection ends at the beginning of a line, don't indent
10157        // that last line.
10158        if selection.end.column == 0 && selection.end.row > selection.start.row {
10159            end_row -= 1;
10160        }
10161
10162        // Avoid re-indenting a row that has already been indented by a
10163        // previous selection, but still update this selection's column
10164        // to reflect that indentation.
10165        if delta_for_start_row > 0 {
10166            start_row += 1;
10167            selection.start.column += delta_for_start_row;
10168            if selection.end.row == selection.start.row {
10169                selection.end.column += delta_for_start_row;
10170            }
10171        }
10172
10173        let mut delta_for_end_row = 0;
10174        let has_multiple_rows = start_row + 1 != end_row;
10175        for row in start_row..end_row {
10176            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10177            let indent_delta = match (current_indent.kind, indent_kind) {
10178                (IndentKind::Space, IndentKind::Space) => {
10179                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10180                    IndentSize::spaces(columns_to_next_tab_stop)
10181                }
10182                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10183                (_, IndentKind::Tab) => IndentSize::tab(),
10184            };
10185
10186            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10187                0
10188            } else {
10189                selection.start.column
10190            };
10191            let row_start = Point::new(row, start);
10192            edits.push((
10193                row_start..row_start,
10194                indent_delta.chars().collect::<String>(),
10195            ));
10196
10197            // Update this selection's endpoints to reflect the indentation.
10198            if row == selection.start.row {
10199                selection.start.column += indent_delta.len;
10200            }
10201            if row == selection.end.row {
10202                selection.end.column += indent_delta.len;
10203                delta_for_end_row = indent_delta.len;
10204            }
10205        }
10206
10207        if selection.start.row == selection.end.row {
10208            delta_for_start_row + delta_for_end_row
10209        } else {
10210            delta_for_end_row
10211        }
10212    }
10213
10214    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10215        if self.read_only(cx) {
10216            return;
10217        }
10218        if self.mode.is_single_line() {
10219            cx.propagate();
10220            return;
10221        }
10222
10223        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10224        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10225        let selections = self.selections.all::<Point>(&display_map);
10226        let mut deletion_ranges = Vec::new();
10227        let mut last_outdent = None;
10228        {
10229            let buffer = self.buffer.read(cx);
10230            let snapshot = buffer.snapshot(cx);
10231            for selection in &selections {
10232                let settings = buffer.language_settings_at(selection.start, cx);
10233                let tab_size = settings.tab_size.get();
10234                let mut rows = selection.spanned_rows(false, &display_map);
10235
10236                // Avoid re-outdenting a row that has already been outdented by a
10237                // previous selection.
10238                if let Some(last_row) = last_outdent
10239                    && last_row == rows.start
10240                {
10241                    rows.start = rows.start.next_row();
10242                }
10243                let has_multiple_rows = rows.len() > 1;
10244                for row in rows.iter_rows() {
10245                    let indent_size = snapshot.indent_size_for_line(row);
10246                    if indent_size.len > 0 {
10247                        let deletion_len = match indent_size.kind {
10248                            IndentKind::Space => {
10249                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10250                                if columns_to_prev_tab_stop == 0 {
10251                                    tab_size
10252                                } else {
10253                                    columns_to_prev_tab_stop
10254                                }
10255                            }
10256                            IndentKind::Tab => 1,
10257                        };
10258                        let start = if has_multiple_rows
10259                            || deletion_len > selection.start.column
10260                            || indent_size.len < selection.start.column
10261                        {
10262                            0
10263                        } else {
10264                            selection.start.column - deletion_len
10265                        };
10266                        deletion_ranges.push(
10267                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10268                        );
10269                        last_outdent = Some(row);
10270                    }
10271                }
10272            }
10273        }
10274
10275        self.transact(window, cx, |this, window, cx| {
10276            this.buffer.update(cx, |buffer, cx| {
10277                let empty_str: Arc<str> = Arc::default();
10278                buffer.edit(
10279                    deletion_ranges
10280                        .into_iter()
10281                        .map(|range| (range, empty_str.clone())),
10282                    None,
10283                    cx,
10284                );
10285            });
10286            let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
10287            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10288        });
10289    }
10290
10291    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10292        if self.read_only(cx) {
10293            return;
10294        }
10295        if self.mode.is_single_line() {
10296            cx.propagate();
10297            return;
10298        }
10299
10300        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10301        let selections = self
10302            .selections
10303            .all::<usize>(&self.display_snapshot(cx))
10304            .into_iter()
10305            .map(|s| s.range());
10306
10307        self.transact(window, cx, |this, window, cx| {
10308            this.buffer.update(cx, |buffer, cx| {
10309                buffer.autoindent_ranges(selections, cx);
10310            });
10311            let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
10312            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10313        });
10314    }
10315
10316    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10317        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10318        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10319        let selections = self.selections.all::<Point>(&display_map);
10320
10321        let mut new_cursors = Vec::new();
10322        let mut edit_ranges = Vec::new();
10323        let mut selections = selections.iter().peekable();
10324        while let Some(selection) = selections.next() {
10325            let mut rows = selection.spanned_rows(false, &display_map);
10326
10327            // Accumulate contiguous regions of rows that we want to delete.
10328            while let Some(next_selection) = selections.peek() {
10329                let next_rows = next_selection.spanned_rows(false, &display_map);
10330                if next_rows.start <= rows.end {
10331                    rows.end = next_rows.end;
10332                    selections.next().unwrap();
10333                } else {
10334                    break;
10335                }
10336            }
10337
10338            let buffer = display_map.buffer_snapshot();
10339            let mut edit_start = ToOffset::to_offset(&Point::new(rows.start.0, 0), buffer);
10340            let (edit_end, target_row) = if buffer.max_point().row >= rows.end.0 {
10341                // If there's a line after the range, delete the \n from the end of the row range
10342                (
10343                    ToOffset::to_offset(&Point::new(rows.end.0, 0), buffer),
10344                    rows.end,
10345                )
10346            } else {
10347                // If there isn't a line after the range, delete the \n from the line before the
10348                // start of the row range
10349                edit_start = edit_start.saturating_sub(1);
10350                (buffer.len(), rows.start.previous_row())
10351            };
10352
10353            let text_layout_details = self.text_layout_details(window);
10354            let x = display_map.x_for_display_point(
10355                selection.head().to_display_point(&display_map),
10356                &text_layout_details,
10357            );
10358            let row = Point::new(target_row.0, 0)
10359                .to_display_point(&display_map)
10360                .row();
10361            let column = display_map.display_column_for_x(row, x, &text_layout_details);
10362
10363            new_cursors.push((
10364                selection.id,
10365                buffer.anchor_after(DisplayPoint::new(row, column).to_point(&display_map)),
10366                SelectionGoal::None,
10367            ));
10368            edit_ranges.push(edit_start..edit_end);
10369        }
10370
10371        self.transact(window, cx, |this, window, cx| {
10372            let buffer = this.buffer.update(cx, |buffer, cx| {
10373                let empty_str: Arc<str> = Arc::default();
10374                buffer.edit(
10375                    edit_ranges
10376                        .into_iter()
10377                        .map(|range| (range, empty_str.clone())),
10378                    None,
10379                    cx,
10380                );
10381                buffer.snapshot(cx)
10382            });
10383            let new_selections = new_cursors
10384                .into_iter()
10385                .map(|(id, cursor, goal)| {
10386                    let cursor = cursor.to_point(&buffer);
10387                    Selection {
10388                        id,
10389                        start: cursor,
10390                        end: cursor,
10391                        reversed: false,
10392                        goal,
10393                    }
10394                })
10395                .collect();
10396
10397            this.change_selections(Default::default(), window, cx, |s| {
10398                s.select(new_selections);
10399            });
10400        });
10401    }
10402
10403    pub fn join_lines_impl(
10404        &mut self,
10405        insert_whitespace: bool,
10406        window: &mut Window,
10407        cx: &mut Context<Self>,
10408    ) {
10409        if self.read_only(cx) {
10410            return;
10411        }
10412        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10413        for selection in self.selections.all::<Point>(&self.display_snapshot(cx)) {
10414            let start = MultiBufferRow(selection.start.row);
10415            // Treat single line selections as if they include the next line. Otherwise this action
10416            // would do nothing for single line selections individual cursors.
10417            let end = if selection.start.row == selection.end.row {
10418                MultiBufferRow(selection.start.row + 1)
10419            } else {
10420                MultiBufferRow(selection.end.row)
10421            };
10422
10423            if let Some(last_row_range) = row_ranges.last_mut()
10424                && start <= last_row_range.end
10425            {
10426                last_row_range.end = end;
10427                continue;
10428            }
10429            row_ranges.push(start..end);
10430        }
10431
10432        let snapshot = self.buffer.read(cx).snapshot(cx);
10433        let mut cursor_positions = Vec::new();
10434        for row_range in &row_ranges {
10435            let anchor = snapshot.anchor_before(Point::new(
10436                row_range.end.previous_row().0,
10437                snapshot.line_len(row_range.end.previous_row()),
10438            ));
10439            cursor_positions.push(anchor..anchor);
10440        }
10441
10442        self.transact(window, cx, |this, window, cx| {
10443            for row_range in row_ranges.into_iter().rev() {
10444                for row in row_range.iter_rows().rev() {
10445                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10446                    let next_line_row = row.next_row();
10447                    let indent = snapshot.indent_size_for_line(next_line_row);
10448                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10449
10450                    let replace =
10451                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10452                            " "
10453                        } else {
10454                            ""
10455                        };
10456
10457                    this.buffer.update(cx, |buffer, cx| {
10458                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10459                    });
10460                }
10461            }
10462
10463            this.change_selections(Default::default(), window, cx, |s| {
10464                s.select_anchor_ranges(cursor_positions)
10465            });
10466        });
10467    }
10468
10469    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10470        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10471        self.join_lines_impl(true, window, cx);
10472    }
10473
10474    pub fn sort_lines_case_sensitive(
10475        &mut self,
10476        _: &SortLinesCaseSensitive,
10477        window: &mut Window,
10478        cx: &mut Context<Self>,
10479    ) {
10480        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10481    }
10482
10483    pub fn sort_lines_by_length(
10484        &mut self,
10485        _: &SortLinesByLength,
10486        window: &mut Window,
10487        cx: &mut Context<Self>,
10488    ) {
10489        self.manipulate_immutable_lines(window, cx, |lines| {
10490            lines.sort_by_key(|&line| line.chars().count())
10491        })
10492    }
10493
10494    pub fn sort_lines_case_insensitive(
10495        &mut self,
10496        _: &SortLinesCaseInsensitive,
10497        window: &mut Window,
10498        cx: &mut Context<Self>,
10499    ) {
10500        self.manipulate_immutable_lines(window, cx, |lines| {
10501            lines.sort_by_key(|line| line.to_lowercase())
10502        })
10503    }
10504
10505    pub fn unique_lines_case_insensitive(
10506        &mut self,
10507        _: &UniqueLinesCaseInsensitive,
10508        window: &mut Window,
10509        cx: &mut Context<Self>,
10510    ) {
10511        self.manipulate_immutable_lines(window, cx, |lines| {
10512            let mut seen = HashSet::default();
10513            lines.retain(|line| seen.insert(line.to_lowercase()));
10514        })
10515    }
10516
10517    pub fn unique_lines_case_sensitive(
10518        &mut self,
10519        _: &UniqueLinesCaseSensitive,
10520        window: &mut Window,
10521        cx: &mut Context<Self>,
10522    ) {
10523        self.manipulate_immutable_lines(window, cx, |lines| {
10524            let mut seen = HashSet::default();
10525            lines.retain(|line| seen.insert(*line));
10526        })
10527    }
10528
10529    fn enable_wrap_selections_in_tag(&self, cx: &App) -> bool {
10530        let snapshot = self.buffer.read(cx).snapshot(cx);
10531        for selection in self.selections.disjoint_anchors_arc().iter() {
10532            if snapshot
10533                .language_at(selection.start)
10534                .and_then(|lang| lang.config().wrap_characters.as_ref())
10535                .is_some()
10536            {
10537                return true;
10538            }
10539        }
10540        false
10541    }
10542
10543    fn wrap_selections_in_tag(
10544        &mut self,
10545        _: &WrapSelectionsInTag,
10546        window: &mut Window,
10547        cx: &mut Context<Self>,
10548    ) {
10549        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10550
10551        let snapshot = self.buffer.read(cx).snapshot(cx);
10552
10553        let mut edits = Vec::new();
10554        let mut boundaries = Vec::new();
10555
10556        for selection in self
10557            .selections
10558            .all_adjusted(&self.display_snapshot(cx))
10559            .iter()
10560        {
10561            let Some(wrap_config) = snapshot
10562                .language_at(selection.start)
10563                .and_then(|lang| lang.config().wrap_characters.clone())
10564            else {
10565                continue;
10566            };
10567
10568            let open_tag = format!("{}{}", wrap_config.start_prefix, wrap_config.start_suffix);
10569            let close_tag = format!("{}{}", wrap_config.end_prefix, wrap_config.end_suffix);
10570
10571            let start_before = snapshot.anchor_before(selection.start);
10572            let end_after = snapshot.anchor_after(selection.end);
10573
10574            edits.push((start_before..start_before, open_tag));
10575            edits.push((end_after..end_after, close_tag));
10576
10577            boundaries.push((
10578                start_before,
10579                end_after,
10580                wrap_config.start_prefix.len(),
10581                wrap_config.end_suffix.len(),
10582            ));
10583        }
10584
10585        if edits.is_empty() {
10586            return;
10587        }
10588
10589        self.transact(window, cx, |this, window, cx| {
10590            let buffer = this.buffer.update(cx, |buffer, cx| {
10591                buffer.edit(edits, None, cx);
10592                buffer.snapshot(cx)
10593            });
10594
10595            let mut new_selections = Vec::with_capacity(boundaries.len() * 2);
10596            for (start_before, end_after, start_prefix_len, end_suffix_len) in
10597                boundaries.into_iter()
10598            {
10599                let open_offset = start_before.to_offset(&buffer) + start_prefix_len;
10600                let close_offset = end_after.to_offset(&buffer).saturating_sub(end_suffix_len);
10601                new_selections.push(open_offset..open_offset);
10602                new_selections.push(close_offset..close_offset);
10603            }
10604
10605            this.change_selections(Default::default(), window, cx, |s| {
10606                s.select_ranges(new_selections);
10607            });
10608
10609            this.request_autoscroll(Autoscroll::fit(), cx);
10610        });
10611    }
10612
10613    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10614        let Some(project) = self.project.clone() else {
10615            return;
10616        };
10617        self.reload(project, window, cx)
10618            .detach_and_notify_err(window, cx);
10619    }
10620
10621    pub fn restore_file(
10622        &mut self,
10623        _: &::git::RestoreFile,
10624        window: &mut Window,
10625        cx: &mut Context<Self>,
10626    ) {
10627        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10628        let mut buffer_ids = HashSet::default();
10629        let snapshot = self.buffer().read(cx).snapshot(cx);
10630        for selection in self.selections.all::<usize>(&self.display_snapshot(cx)) {
10631            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10632        }
10633
10634        let buffer = self.buffer().read(cx);
10635        let ranges = buffer_ids
10636            .into_iter()
10637            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10638            .collect::<Vec<_>>();
10639
10640        self.restore_hunks_in_ranges(ranges, window, cx);
10641    }
10642
10643    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10644        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10645        let selections = self
10646            .selections
10647            .all(&self.display_snapshot(cx))
10648            .into_iter()
10649            .map(|s| s.range())
10650            .collect();
10651        self.restore_hunks_in_ranges(selections, window, cx);
10652    }
10653
10654    pub fn restore_hunks_in_ranges(
10655        &mut self,
10656        ranges: Vec<Range<Point>>,
10657        window: &mut Window,
10658        cx: &mut Context<Editor>,
10659    ) {
10660        let mut revert_changes = HashMap::default();
10661        let chunk_by = self
10662            .snapshot(window, cx)
10663            .hunks_for_ranges(ranges)
10664            .into_iter()
10665            .chunk_by(|hunk| hunk.buffer_id);
10666        for (buffer_id, hunks) in &chunk_by {
10667            let hunks = hunks.collect::<Vec<_>>();
10668            for hunk in &hunks {
10669                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10670            }
10671            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10672        }
10673        drop(chunk_by);
10674        if !revert_changes.is_empty() {
10675            self.transact(window, cx, |editor, window, cx| {
10676                editor.restore(revert_changes, window, cx);
10677            });
10678        }
10679    }
10680
10681    pub fn status_for_buffer_id(&self, buffer_id: BufferId, cx: &App) -> Option<FileStatus> {
10682        if let Some(status) = self
10683            .addons
10684            .iter()
10685            .find_map(|(_, addon)| addon.override_status_for_buffer_id(buffer_id, cx))
10686        {
10687            return Some(status);
10688        }
10689        self.project
10690            .as_ref()?
10691            .read(cx)
10692            .status_for_buffer_id(buffer_id, cx)
10693    }
10694
10695    pub fn open_active_item_in_terminal(
10696        &mut self,
10697        _: &OpenInTerminal,
10698        window: &mut Window,
10699        cx: &mut Context<Self>,
10700    ) {
10701        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10702            let project_path = buffer.read(cx).project_path(cx)?;
10703            let project = self.project()?.read(cx);
10704            let entry = project.entry_for_path(&project_path, cx)?;
10705            let parent = match &entry.canonical_path {
10706                Some(canonical_path) => canonical_path.to_path_buf(),
10707                None => project.absolute_path(&project_path, cx)?,
10708            }
10709            .parent()?
10710            .to_path_buf();
10711            Some(parent)
10712        }) {
10713            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10714        }
10715    }
10716
10717    fn set_breakpoint_context_menu(
10718        &mut self,
10719        display_row: DisplayRow,
10720        position: Option<Anchor>,
10721        clicked_point: gpui::Point<Pixels>,
10722        window: &mut Window,
10723        cx: &mut Context<Self>,
10724    ) {
10725        let source = self
10726            .buffer
10727            .read(cx)
10728            .snapshot(cx)
10729            .anchor_before(Point::new(display_row.0, 0u32));
10730
10731        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10732
10733        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10734            self,
10735            source,
10736            clicked_point,
10737            context_menu,
10738            window,
10739            cx,
10740        );
10741    }
10742
10743    fn add_edit_breakpoint_block(
10744        &mut self,
10745        anchor: Anchor,
10746        breakpoint: &Breakpoint,
10747        edit_action: BreakpointPromptEditAction,
10748        window: &mut Window,
10749        cx: &mut Context<Self>,
10750    ) {
10751        let weak_editor = cx.weak_entity();
10752        let bp_prompt = cx.new(|cx| {
10753            BreakpointPromptEditor::new(
10754                weak_editor,
10755                anchor,
10756                breakpoint.clone(),
10757                edit_action,
10758                window,
10759                cx,
10760            )
10761        });
10762
10763        let height = bp_prompt.update(cx, |this, cx| {
10764            this.prompt
10765                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10766        });
10767        let cloned_prompt = bp_prompt.clone();
10768        let blocks = vec![BlockProperties {
10769            style: BlockStyle::Sticky,
10770            placement: BlockPlacement::Above(anchor),
10771            height: Some(height),
10772            render: Arc::new(move |cx| {
10773                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10774                cloned_prompt.clone().into_any_element()
10775            }),
10776            priority: 0,
10777        }];
10778
10779        let focus_handle = bp_prompt.focus_handle(cx);
10780        window.focus(&focus_handle);
10781
10782        let block_ids = self.insert_blocks(blocks, None, cx);
10783        bp_prompt.update(cx, |prompt, _| {
10784            prompt.add_block_ids(block_ids);
10785        });
10786    }
10787
10788    pub(crate) fn breakpoint_at_row(
10789        &self,
10790        row: u32,
10791        window: &mut Window,
10792        cx: &mut Context<Self>,
10793    ) -> Option<(Anchor, Breakpoint)> {
10794        let snapshot = self.snapshot(window, cx);
10795        let breakpoint_position = snapshot.buffer_snapshot().anchor_before(Point::new(row, 0));
10796
10797        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10798    }
10799
10800    pub(crate) fn breakpoint_at_anchor(
10801        &self,
10802        breakpoint_position: Anchor,
10803        snapshot: &EditorSnapshot,
10804        cx: &mut Context<Self>,
10805    ) -> Option<(Anchor, Breakpoint)> {
10806        let buffer = self
10807            .buffer
10808            .read(cx)
10809            .buffer_for_anchor(breakpoint_position, cx)?;
10810
10811        let enclosing_excerpt = breakpoint_position.excerpt_id;
10812        let buffer_snapshot = buffer.read(cx).snapshot();
10813
10814        let row = buffer_snapshot
10815            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10816            .row;
10817
10818        let line_len = snapshot.buffer_snapshot().line_len(MultiBufferRow(row));
10819        let anchor_end = snapshot
10820            .buffer_snapshot()
10821            .anchor_after(Point::new(row, line_len));
10822
10823        self.breakpoint_store
10824            .as_ref()?
10825            .read_with(cx, |breakpoint_store, cx| {
10826                breakpoint_store
10827                    .breakpoints(
10828                        &buffer,
10829                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10830                        &buffer_snapshot,
10831                        cx,
10832                    )
10833                    .next()
10834                    .and_then(|(bp, _)| {
10835                        let breakpoint_row = buffer_snapshot
10836                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10837                            .row;
10838
10839                        if breakpoint_row == row {
10840                            snapshot
10841                                .buffer_snapshot()
10842                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10843                                .map(|position| (position, bp.bp.clone()))
10844                        } else {
10845                            None
10846                        }
10847                    })
10848            })
10849    }
10850
10851    pub fn edit_log_breakpoint(
10852        &mut self,
10853        _: &EditLogBreakpoint,
10854        window: &mut Window,
10855        cx: &mut Context<Self>,
10856    ) {
10857        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10858            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10859                message: None,
10860                state: BreakpointState::Enabled,
10861                condition: None,
10862                hit_condition: None,
10863            });
10864
10865            self.add_edit_breakpoint_block(
10866                anchor,
10867                &breakpoint,
10868                BreakpointPromptEditAction::Log,
10869                window,
10870                cx,
10871            );
10872        }
10873    }
10874
10875    fn breakpoints_at_cursors(
10876        &self,
10877        window: &mut Window,
10878        cx: &mut Context<Self>,
10879    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10880        let snapshot = self.snapshot(window, cx);
10881        let cursors = self
10882            .selections
10883            .disjoint_anchors_arc()
10884            .iter()
10885            .map(|selection| {
10886                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot());
10887
10888                let breakpoint_position = self
10889                    .breakpoint_at_row(cursor_position.row, window, cx)
10890                    .map(|bp| bp.0)
10891                    .unwrap_or_else(|| {
10892                        snapshot
10893                            .display_snapshot
10894                            .buffer_snapshot()
10895                            .anchor_after(Point::new(cursor_position.row, 0))
10896                    });
10897
10898                let breakpoint = self
10899                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10900                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
10901
10902                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
10903            })
10904            // 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.
10905            .collect::<HashMap<Anchor, _>>();
10906
10907        cursors.into_iter().collect()
10908    }
10909
10910    pub fn enable_breakpoint(
10911        &mut self,
10912        _: &crate::actions::EnableBreakpoint,
10913        window: &mut Window,
10914        cx: &mut Context<Self>,
10915    ) {
10916        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10917            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
10918                continue;
10919            };
10920            self.edit_breakpoint_at_anchor(
10921                anchor,
10922                breakpoint,
10923                BreakpointEditAction::InvertState,
10924                cx,
10925            );
10926        }
10927    }
10928
10929    pub fn disable_breakpoint(
10930        &mut self,
10931        _: &crate::actions::DisableBreakpoint,
10932        window: &mut Window,
10933        cx: &mut Context<Self>,
10934    ) {
10935        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10936            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
10937                continue;
10938            };
10939            self.edit_breakpoint_at_anchor(
10940                anchor,
10941                breakpoint,
10942                BreakpointEditAction::InvertState,
10943                cx,
10944            );
10945        }
10946    }
10947
10948    pub fn toggle_breakpoint(
10949        &mut self,
10950        _: &crate::actions::ToggleBreakpoint,
10951        window: &mut Window,
10952        cx: &mut Context<Self>,
10953    ) {
10954        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10955            if let Some(breakpoint) = breakpoint {
10956                self.edit_breakpoint_at_anchor(
10957                    anchor,
10958                    breakpoint,
10959                    BreakpointEditAction::Toggle,
10960                    cx,
10961                );
10962            } else {
10963                self.edit_breakpoint_at_anchor(
10964                    anchor,
10965                    Breakpoint::new_standard(),
10966                    BreakpointEditAction::Toggle,
10967                    cx,
10968                );
10969            }
10970        }
10971    }
10972
10973    pub fn edit_breakpoint_at_anchor(
10974        &mut self,
10975        breakpoint_position: Anchor,
10976        breakpoint: Breakpoint,
10977        edit_action: BreakpointEditAction,
10978        cx: &mut Context<Self>,
10979    ) {
10980        let Some(breakpoint_store) = &self.breakpoint_store else {
10981            return;
10982        };
10983
10984        let Some(buffer) = self
10985            .buffer
10986            .read(cx)
10987            .buffer_for_anchor(breakpoint_position, cx)
10988        else {
10989            return;
10990        };
10991
10992        breakpoint_store.update(cx, |breakpoint_store, cx| {
10993            breakpoint_store.toggle_breakpoint(
10994                buffer,
10995                BreakpointWithPosition {
10996                    position: breakpoint_position.text_anchor,
10997                    bp: breakpoint,
10998                },
10999                edit_action,
11000                cx,
11001            );
11002        });
11003
11004        cx.notify();
11005    }
11006
11007    #[cfg(any(test, feature = "test-support"))]
11008    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
11009        self.breakpoint_store.clone()
11010    }
11011
11012    pub fn prepare_restore_change(
11013        &self,
11014        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
11015        hunk: &MultiBufferDiffHunk,
11016        cx: &mut App,
11017    ) -> Option<()> {
11018        if hunk.is_created_file() {
11019            return None;
11020        }
11021        let buffer = self.buffer.read(cx);
11022        let diff = buffer.diff_for(hunk.buffer_id)?;
11023        let buffer = buffer.buffer(hunk.buffer_id)?;
11024        let buffer = buffer.read(cx);
11025        let original_text = diff
11026            .read(cx)
11027            .base_text()
11028            .as_rope()
11029            .slice(hunk.diff_base_byte_range.clone());
11030        let buffer_snapshot = buffer.snapshot();
11031        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
11032        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
11033            probe
11034                .0
11035                .start
11036                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
11037                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
11038        }) {
11039            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
11040            Some(())
11041        } else {
11042            None
11043        }
11044    }
11045
11046    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
11047        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
11048    }
11049
11050    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
11051        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut rand::rng()))
11052    }
11053
11054    fn manipulate_lines<M>(
11055        &mut self,
11056        window: &mut Window,
11057        cx: &mut Context<Self>,
11058        mut manipulate: M,
11059    ) where
11060        M: FnMut(&str) -> LineManipulationResult,
11061    {
11062        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11063
11064        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11065        let buffer = self.buffer.read(cx).snapshot(cx);
11066
11067        let mut edits = Vec::new();
11068
11069        let selections = self.selections.all::<Point>(&display_map);
11070        let mut selections = selections.iter().peekable();
11071        let mut contiguous_row_selections = Vec::new();
11072        let mut new_selections = Vec::new();
11073        let mut added_lines = 0;
11074        let mut removed_lines = 0;
11075
11076        while let Some(selection) = selections.next() {
11077            let (start_row, end_row) = consume_contiguous_rows(
11078                &mut contiguous_row_selections,
11079                selection,
11080                &display_map,
11081                &mut selections,
11082            );
11083
11084            let start_point = Point::new(start_row.0, 0);
11085            let end_point = Point::new(
11086                end_row.previous_row().0,
11087                buffer.line_len(end_row.previous_row()),
11088            );
11089            let text = buffer
11090                .text_for_range(start_point..end_point)
11091                .collect::<String>();
11092
11093            let LineManipulationResult {
11094                new_text,
11095                line_count_before,
11096                line_count_after,
11097            } = manipulate(&text);
11098
11099            edits.push((start_point..end_point, new_text));
11100
11101            // Selections must change based on added and removed line count
11102            let start_row =
11103                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
11104            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
11105            new_selections.push(Selection {
11106                id: selection.id,
11107                start: start_row,
11108                end: end_row,
11109                goal: SelectionGoal::None,
11110                reversed: selection.reversed,
11111            });
11112
11113            if line_count_after > line_count_before {
11114                added_lines += line_count_after - line_count_before;
11115            } else if line_count_before > line_count_after {
11116                removed_lines += line_count_before - line_count_after;
11117            }
11118        }
11119
11120        self.transact(window, cx, |this, window, cx| {
11121            let buffer = this.buffer.update(cx, |buffer, cx| {
11122                buffer.edit(edits, None, cx);
11123                buffer.snapshot(cx)
11124            });
11125
11126            // Recalculate offsets on newly edited buffer
11127            let new_selections = new_selections
11128                .iter()
11129                .map(|s| {
11130                    let start_point = Point::new(s.start.0, 0);
11131                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
11132                    Selection {
11133                        id: s.id,
11134                        start: buffer.point_to_offset(start_point),
11135                        end: buffer.point_to_offset(end_point),
11136                        goal: s.goal,
11137                        reversed: s.reversed,
11138                    }
11139                })
11140                .collect();
11141
11142            this.change_selections(Default::default(), window, cx, |s| {
11143                s.select(new_selections);
11144            });
11145
11146            this.request_autoscroll(Autoscroll::fit(), cx);
11147        });
11148    }
11149
11150    fn manipulate_immutable_lines<Fn>(
11151        &mut self,
11152        window: &mut Window,
11153        cx: &mut Context<Self>,
11154        mut callback: Fn,
11155    ) where
11156        Fn: FnMut(&mut Vec<&str>),
11157    {
11158        self.manipulate_lines(window, cx, |text| {
11159            let mut lines: Vec<&str> = text.split('\n').collect();
11160            let line_count_before = lines.len();
11161
11162            callback(&mut lines);
11163
11164            LineManipulationResult {
11165                new_text: lines.join("\n"),
11166                line_count_before,
11167                line_count_after: lines.len(),
11168            }
11169        });
11170    }
11171
11172    fn manipulate_mutable_lines<Fn>(
11173        &mut self,
11174        window: &mut Window,
11175        cx: &mut Context<Self>,
11176        mut callback: Fn,
11177    ) where
11178        Fn: FnMut(&mut Vec<Cow<'_, str>>),
11179    {
11180        self.manipulate_lines(window, cx, |text| {
11181            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
11182            let line_count_before = lines.len();
11183
11184            callback(&mut lines);
11185
11186            LineManipulationResult {
11187                new_text: lines.join("\n"),
11188                line_count_before,
11189                line_count_after: lines.len(),
11190            }
11191        });
11192    }
11193
11194    pub fn convert_indentation_to_spaces(
11195        &mut self,
11196        _: &ConvertIndentationToSpaces,
11197        window: &mut Window,
11198        cx: &mut Context<Self>,
11199    ) {
11200        let settings = self.buffer.read(cx).language_settings(cx);
11201        let tab_size = settings.tab_size.get() as usize;
11202
11203        self.manipulate_mutable_lines(window, cx, |lines| {
11204            // Allocates a reasonably sized scratch buffer once for the whole loop
11205            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11206            // Avoids recomputing spaces that could be inserted many times
11207            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11208                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11209                .collect();
11210
11211            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11212                let mut chars = line.as_ref().chars();
11213                let mut col = 0;
11214                let mut changed = false;
11215
11216                for ch in chars.by_ref() {
11217                    match ch {
11218                        ' ' => {
11219                            reindented_line.push(' ');
11220                            col += 1;
11221                        }
11222                        '\t' => {
11223                            // \t are converted to spaces depending on the current column
11224                            let spaces_len = tab_size - (col % tab_size);
11225                            reindented_line.extend(&space_cache[spaces_len - 1]);
11226                            col += spaces_len;
11227                            changed = true;
11228                        }
11229                        _ => {
11230                            // If we dont append before break, the character is consumed
11231                            reindented_line.push(ch);
11232                            break;
11233                        }
11234                    }
11235                }
11236
11237                if !changed {
11238                    reindented_line.clear();
11239                    continue;
11240                }
11241                // Append the rest of the line and replace old reference with new one
11242                reindented_line.extend(chars);
11243                *line = Cow::Owned(reindented_line.clone());
11244                reindented_line.clear();
11245            }
11246        });
11247    }
11248
11249    pub fn convert_indentation_to_tabs(
11250        &mut self,
11251        _: &ConvertIndentationToTabs,
11252        window: &mut Window,
11253        cx: &mut Context<Self>,
11254    ) {
11255        let settings = self.buffer.read(cx).language_settings(cx);
11256        let tab_size = settings.tab_size.get() as usize;
11257
11258        self.manipulate_mutable_lines(window, cx, |lines| {
11259            // Allocates a reasonably sized buffer once for the whole loop
11260            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11261            // Avoids recomputing spaces that could be inserted many times
11262            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11263                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11264                .collect();
11265
11266            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11267                let mut chars = line.chars();
11268                let mut spaces_count = 0;
11269                let mut first_non_indent_char = None;
11270                let mut changed = false;
11271
11272                for ch in chars.by_ref() {
11273                    match ch {
11274                        ' ' => {
11275                            // Keep track of spaces. Append \t when we reach tab_size
11276                            spaces_count += 1;
11277                            changed = true;
11278                            if spaces_count == tab_size {
11279                                reindented_line.push('\t');
11280                                spaces_count = 0;
11281                            }
11282                        }
11283                        '\t' => {
11284                            reindented_line.push('\t');
11285                            spaces_count = 0;
11286                        }
11287                        _ => {
11288                            // Dont append it yet, we might have remaining spaces
11289                            first_non_indent_char = Some(ch);
11290                            break;
11291                        }
11292                    }
11293                }
11294
11295                if !changed {
11296                    reindented_line.clear();
11297                    continue;
11298                }
11299                // Remaining spaces that didn't make a full tab stop
11300                if spaces_count > 0 {
11301                    reindented_line.extend(&space_cache[spaces_count - 1]);
11302                }
11303                // If we consume an extra character that was not indentation, add it back
11304                if let Some(extra_char) = first_non_indent_char {
11305                    reindented_line.push(extra_char);
11306                }
11307                // Append the rest of the line and replace old reference with new one
11308                reindented_line.extend(chars);
11309                *line = Cow::Owned(reindented_line.clone());
11310                reindented_line.clear();
11311            }
11312        });
11313    }
11314
11315    pub fn convert_to_upper_case(
11316        &mut self,
11317        _: &ConvertToUpperCase,
11318        window: &mut Window,
11319        cx: &mut Context<Self>,
11320    ) {
11321        self.manipulate_text(window, cx, |text| text.to_uppercase())
11322    }
11323
11324    pub fn convert_to_lower_case(
11325        &mut self,
11326        _: &ConvertToLowerCase,
11327        window: &mut Window,
11328        cx: &mut Context<Self>,
11329    ) {
11330        self.manipulate_text(window, cx, |text| text.to_lowercase())
11331    }
11332
11333    pub fn convert_to_title_case(
11334        &mut self,
11335        _: &ConvertToTitleCase,
11336        window: &mut Window,
11337        cx: &mut Context<Self>,
11338    ) {
11339        self.manipulate_text(window, cx, |text| {
11340            text.split('\n')
11341                .map(|line| line.to_case(Case::Title))
11342                .join("\n")
11343        })
11344    }
11345
11346    pub fn convert_to_snake_case(
11347        &mut self,
11348        _: &ConvertToSnakeCase,
11349        window: &mut Window,
11350        cx: &mut Context<Self>,
11351    ) {
11352        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11353    }
11354
11355    pub fn convert_to_kebab_case(
11356        &mut self,
11357        _: &ConvertToKebabCase,
11358        window: &mut Window,
11359        cx: &mut Context<Self>,
11360    ) {
11361        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11362    }
11363
11364    pub fn convert_to_upper_camel_case(
11365        &mut self,
11366        _: &ConvertToUpperCamelCase,
11367        window: &mut Window,
11368        cx: &mut Context<Self>,
11369    ) {
11370        self.manipulate_text(window, cx, |text| {
11371            text.split('\n')
11372                .map(|line| line.to_case(Case::UpperCamel))
11373                .join("\n")
11374        })
11375    }
11376
11377    pub fn convert_to_lower_camel_case(
11378        &mut self,
11379        _: &ConvertToLowerCamelCase,
11380        window: &mut Window,
11381        cx: &mut Context<Self>,
11382    ) {
11383        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11384    }
11385
11386    pub fn convert_to_opposite_case(
11387        &mut self,
11388        _: &ConvertToOppositeCase,
11389        window: &mut Window,
11390        cx: &mut Context<Self>,
11391    ) {
11392        self.manipulate_text(window, cx, |text| {
11393            text.chars()
11394                .fold(String::with_capacity(text.len()), |mut t, c| {
11395                    if c.is_uppercase() {
11396                        t.extend(c.to_lowercase());
11397                    } else {
11398                        t.extend(c.to_uppercase());
11399                    }
11400                    t
11401                })
11402        })
11403    }
11404
11405    pub fn convert_to_sentence_case(
11406        &mut self,
11407        _: &ConvertToSentenceCase,
11408        window: &mut Window,
11409        cx: &mut Context<Self>,
11410    ) {
11411        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
11412    }
11413
11414    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
11415        self.manipulate_text(window, cx, |text| {
11416            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
11417            if has_upper_case_characters {
11418                text.to_lowercase()
11419            } else {
11420                text.to_uppercase()
11421            }
11422        })
11423    }
11424
11425    pub fn convert_to_rot13(
11426        &mut self,
11427        _: &ConvertToRot13,
11428        window: &mut Window,
11429        cx: &mut Context<Self>,
11430    ) {
11431        self.manipulate_text(window, cx, |text| {
11432            text.chars()
11433                .map(|c| match c {
11434                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11435                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11436                    _ => c,
11437                })
11438                .collect()
11439        })
11440    }
11441
11442    pub fn convert_to_rot47(
11443        &mut self,
11444        _: &ConvertToRot47,
11445        window: &mut Window,
11446        cx: &mut Context<Self>,
11447    ) {
11448        self.manipulate_text(window, cx, |text| {
11449            text.chars()
11450                .map(|c| {
11451                    let code_point = c as u32;
11452                    if code_point >= 33 && code_point <= 126 {
11453                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11454                    }
11455                    c
11456                })
11457                .collect()
11458        })
11459    }
11460
11461    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11462    where
11463        Fn: FnMut(&str) -> String,
11464    {
11465        let buffer = self.buffer.read(cx).snapshot(cx);
11466
11467        let mut new_selections = Vec::new();
11468        let mut edits = Vec::new();
11469        let mut selection_adjustment = 0i32;
11470
11471        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
11472            let selection_is_empty = selection.is_empty();
11473
11474            let (start, end) = if selection_is_empty {
11475                let (word_range, _) = buffer.surrounding_word(selection.start, None);
11476                (word_range.start, word_range.end)
11477            } else {
11478                (
11479                    buffer.point_to_offset(selection.start),
11480                    buffer.point_to_offset(selection.end),
11481                )
11482            };
11483
11484            let text = buffer.text_for_range(start..end).collect::<String>();
11485            let old_length = text.len() as i32;
11486            let text = callback(&text);
11487
11488            new_selections.push(Selection {
11489                start: (start as i32 - selection_adjustment) as usize,
11490                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
11491                goal: SelectionGoal::None,
11492                id: selection.id,
11493                reversed: selection.reversed,
11494            });
11495
11496            selection_adjustment += old_length - text.len() as i32;
11497
11498            edits.push((start..end, text));
11499        }
11500
11501        self.transact(window, cx, |this, window, cx| {
11502            this.buffer.update(cx, |buffer, cx| {
11503                buffer.edit(edits, None, cx);
11504            });
11505
11506            this.change_selections(Default::default(), window, cx, |s| {
11507                s.select(new_selections);
11508            });
11509
11510            this.request_autoscroll(Autoscroll::fit(), cx);
11511        });
11512    }
11513
11514    pub fn move_selection_on_drop(
11515        &mut self,
11516        selection: &Selection<Anchor>,
11517        target: DisplayPoint,
11518        is_cut: bool,
11519        window: &mut Window,
11520        cx: &mut Context<Self>,
11521    ) {
11522        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11523        let buffer = display_map.buffer_snapshot();
11524        let mut edits = Vec::new();
11525        let insert_point = display_map
11526            .clip_point(target, Bias::Left)
11527            .to_point(&display_map);
11528        let text = buffer
11529            .text_for_range(selection.start..selection.end)
11530            .collect::<String>();
11531        if is_cut {
11532            edits.push(((selection.start..selection.end), String::new()));
11533        }
11534        let insert_anchor = buffer.anchor_before(insert_point);
11535        edits.push(((insert_anchor..insert_anchor), text));
11536        let last_edit_start = insert_anchor.bias_left(buffer);
11537        let last_edit_end = insert_anchor.bias_right(buffer);
11538        self.transact(window, cx, |this, window, cx| {
11539            this.buffer.update(cx, |buffer, cx| {
11540                buffer.edit(edits, None, cx);
11541            });
11542            this.change_selections(Default::default(), window, cx, |s| {
11543                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11544            });
11545        });
11546    }
11547
11548    pub fn clear_selection_drag_state(&mut self) {
11549        self.selection_drag_state = SelectionDragState::None;
11550    }
11551
11552    pub fn duplicate(
11553        &mut self,
11554        upwards: bool,
11555        whole_lines: bool,
11556        window: &mut Window,
11557        cx: &mut Context<Self>,
11558    ) {
11559        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11560
11561        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11562        let buffer = display_map.buffer_snapshot();
11563        let selections = self.selections.all::<Point>(&display_map);
11564
11565        let mut edits = Vec::new();
11566        let mut selections_iter = selections.iter().peekable();
11567        while let Some(selection) = selections_iter.next() {
11568            let mut rows = selection.spanned_rows(false, &display_map);
11569            // duplicate line-wise
11570            if whole_lines || selection.start == selection.end {
11571                // Avoid duplicating the same lines twice.
11572                while let Some(next_selection) = selections_iter.peek() {
11573                    let next_rows = next_selection.spanned_rows(false, &display_map);
11574                    if next_rows.start < rows.end {
11575                        rows.end = next_rows.end;
11576                        selections_iter.next().unwrap();
11577                    } else {
11578                        break;
11579                    }
11580                }
11581
11582                // Copy the text from the selected row region and splice it either at the start
11583                // or end of the region.
11584                let start = Point::new(rows.start.0, 0);
11585                let end = Point::new(
11586                    rows.end.previous_row().0,
11587                    buffer.line_len(rows.end.previous_row()),
11588                );
11589
11590                let mut text = buffer.text_for_range(start..end).collect::<String>();
11591
11592                let insert_location = if upwards {
11593                    // When duplicating upward, we need to insert before the current line.
11594                    // If we're on the last line and it doesn't end with a newline,
11595                    // we need to add a newline before the duplicated content.
11596                    let needs_leading_newline = rows.end.0 >= buffer.max_point().row
11597                        && buffer.max_point().column > 0
11598                        && !text.ends_with('\n');
11599
11600                    if needs_leading_newline {
11601                        text.insert(0, '\n');
11602                        end
11603                    } else {
11604                        text.push('\n');
11605                        Point::new(rows.start.0, 0)
11606                    }
11607                } else {
11608                    text.push('\n');
11609                    start
11610                };
11611                edits.push((insert_location..insert_location, text));
11612            } else {
11613                // duplicate character-wise
11614                let start = selection.start;
11615                let end = selection.end;
11616                let text = buffer.text_for_range(start..end).collect::<String>();
11617                edits.push((selection.end..selection.end, text));
11618            }
11619        }
11620
11621        self.transact(window, cx, |this, window, cx| {
11622            this.buffer.update(cx, |buffer, cx| {
11623                buffer.edit(edits, None, cx);
11624            });
11625
11626            // When duplicating upward with whole lines, move the cursor to the duplicated line
11627            if upwards && whole_lines {
11628                let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
11629
11630                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
11631                    let mut new_ranges = Vec::new();
11632                    let selections = s.all::<Point>(&display_map);
11633                    let mut selections_iter = selections.iter().peekable();
11634
11635                    while let Some(first_selection) = selections_iter.next() {
11636                        // Group contiguous selections together to find the total row span
11637                        let mut group_selections = vec![first_selection];
11638                        let mut rows = first_selection.spanned_rows(false, &display_map);
11639
11640                        while let Some(next_selection) = selections_iter.peek() {
11641                            let next_rows = next_selection.spanned_rows(false, &display_map);
11642                            if next_rows.start < rows.end {
11643                                rows.end = next_rows.end;
11644                                group_selections.push(selections_iter.next().unwrap());
11645                            } else {
11646                                break;
11647                            }
11648                        }
11649
11650                        let row_count = rows.end.0 - rows.start.0;
11651
11652                        // Move all selections in this group up by the total number of duplicated rows
11653                        for selection in group_selections {
11654                            let new_start = Point::new(
11655                                selection.start.row.saturating_sub(row_count),
11656                                selection.start.column,
11657                            );
11658
11659                            let new_end = Point::new(
11660                                selection.end.row.saturating_sub(row_count),
11661                                selection.end.column,
11662                            );
11663
11664                            new_ranges.push(new_start..new_end);
11665                        }
11666                    }
11667
11668                    s.select_ranges(new_ranges);
11669                });
11670            }
11671
11672            this.request_autoscroll(Autoscroll::fit(), cx);
11673        });
11674    }
11675
11676    pub fn duplicate_line_up(
11677        &mut self,
11678        _: &DuplicateLineUp,
11679        window: &mut Window,
11680        cx: &mut Context<Self>,
11681    ) {
11682        self.duplicate(true, true, window, cx);
11683    }
11684
11685    pub fn duplicate_line_down(
11686        &mut self,
11687        _: &DuplicateLineDown,
11688        window: &mut Window,
11689        cx: &mut Context<Self>,
11690    ) {
11691        self.duplicate(false, true, window, cx);
11692    }
11693
11694    pub fn duplicate_selection(
11695        &mut self,
11696        _: &DuplicateSelection,
11697        window: &mut Window,
11698        cx: &mut Context<Self>,
11699    ) {
11700        self.duplicate(false, false, window, cx);
11701    }
11702
11703    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11704        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11705        if self.mode.is_single_line() {
11706            cx.propagate();
11707            return;
11708        }
11709
11710        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11711        let buffer = self.buffer.read(cx).snapshot(cx);
11712
11713        let mut edits = Vec::new();
11714        let mut unfold_ranges = Vec::new();
11715        let mut refold_creases = Vec::new();
11716
11717        let selections = self.selections.all::<Point>(&display_map);
11718        let mut selections = selections.iter().peekable();
11719        let mut contiguous_row_selections = Vec::new();
11720        let mut new_selections = Vec::new();
11721
11722        while let Some(selection) = selections.next() {
11723            // Find all the selections that span a contiguous row range
11724            let (start_row, end_row) = consume_contiguous_rows(
11725                &mut contiguous_row_selections,
11726                selection,
11727                &display_map,
11728                &mut selections,
11729            );
11730
11731            // Move the text spanned by the row range to be before the line preceding the row range
11732            if start_row.0 > 0 {
11733                let range_to_move = Point::new(
11734                    start_row.previous_row().0,
11735                    buffer.line_len(start_row.previous_row()),
11736                )
11737                    ..Point::new(
11738                        end_row.previous_row().0,
11739                        buffer.line_len(end_row.previous_row()),
11740                    );
11741                let insertion_point = display_map
11742                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11743                    .0;
11744
11745                // Don't move lines across excerpts
11746                if buffer
11747                    .excerpt_containing(insertion_point..range_to_move.end)
11748                    .is_some()
11749                {
11750                    let text = buffer
11751                        .text_for_range(range_to_move.clone())
11752                        .flat_map(|s| s.chars())
11753                        .skip(1)
11754                        .chain(['\n'])
11755                        .collect::<String>();
11756
11757                    edits.push((
11758                        buffer.anchor_after(range_to_move.start)
11759                            ..buffer.anchor_before(range_to_move.end),
11760                        String::new(),
11761                    ));
11762                    let insertion_anchor = buffer.anchor_after(insertion_point);
11763                    edits.push((insertion_anchor..insertion_anchor, text));
11764
11765                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11766
11767                    // Move selections up
11768                    new_selections.extend(contiguous_row_selections.drain(..).map(
11769                        |mut selection| {
11770                            selection.start.row -= row_delta;
11771                            selection.end.row -= row_delta;
11772                            selection
11773                        },
11774                    ));
11775
11776                    // Move folds up
11777                    unfold_ranges.push(range_to_move.clone());
11778                    for fold in display_map.folds_in_range(
11779                        buffer.anchor_before(range_to_move.start)
11780                            ..buffer.anchor_after(range_to_move.end),
11781                    ) {
11782                        let mut start = fold.range.start.to_point(&buffer);
11783                        let mut end = fold.range.end.to_point(&buffer);
11784                        start.row -= row_delta;
11785                        end.row -= row_delta;
11786                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11787                    }
11788                }
11789            }
11790
11791            // If we didn't move line(s), preserve the existing selections
11792            new_selections.append(&mut contiguous_row_selections);
11793        }
11794
11795        self.transact(window, cx, |this, window, cx| {
11796            this.unfold_ranges(&unfold_ranges, true, true, cx);
11797            this.buffer.update(cx, |buffer, cx| {
11798                for (range, text) in edits {
11799                    buffer.edit([(range, text)], None, cx);
11800                }
11801            });
11802            this.fold_creases(refold_creases, true, window, cx);
11803            this.change_selections(Default::default(), window, cx, |s| {
11804                s.select(new_selections);
11805            })
11806        });
11807    }
11808
11809    pub fn move_line_down(
11810        &mut self,
11811        _: &MoveLineDown,
11812        window: &mut Window,
11813        cx: &mut Context<Self>,
11814    ) {
11815        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11816        if self.mode.is_single_line() {
11817            cx.propagate();
11818            return;
11819        }
11820
11821        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11822        let buffer = self.buffer.read(cx).snapshot(cx);
11823
11824        let mut edits = Vec::new();
11825        let mut unfold_ranges = Vec::new();
11826        let mut refold_creases = Vec::new();
11827
11828        let selections = self.selections.all::<Point>(&display_map);
11829        let mut selections = selections.iter().peekable();
11830        let mut contiguous_row_selections = Vec::new();
11831        let mut new_selections = Vec::new();
11832
11833        while let Some(selection) = selections.next() {
11834            // Find all the selections that span a contiguous row range
11835            let (start_row, end_row) = consume_contiguous_rows(
11836                &mut contiguous_row_selections,
11837                selection,
11838                &display_map,
11839                &mut selections,
11840            );
11841
11842            // Move the text spanned by the row range to be after the last line of the row range
11843            if end_row.0 <= buffer.max_point().row {
11844                let range_to_move =
11845                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11846                let insertion_point = display_map
11847                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11848                    .0;
11849
11850                // Don't move lines across excerpt boundaries
11851                if buffer
11852                    .excerpt_containing(range_to_move.start..insertion_point)
11853                    .is_some()
11854                {
11855                    let mut text = String::from("\n");
11856                    text.extend(buffer.text_for_range(range_to_move.clone()));
11857                    text.pop(); // Drop trailing newline
11858                    edits.push((
11859                        buffer.anchor_after(range_to_move.start)
11860                            ..buffer.anchor_before(range_to_move.end),
11861                        String::new(),
11862                    ));
11863                    let insertion_anchor = buffer.anchor_after(insertion_point);
11864                    edits.push((insertion_anchor..insertion_anchor, text));
11865
11866                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
11867
11868                    // Move selections down
11869                    new_selections.extend(contiguous_row_selections.drain(..).map(
11870                        |mut selection| {
11871                            selection.start.row += row_delta;
11872                            selection.end.row += row_delta;
11873                            selection
11874                        },
11875                    ));
11876
11877                    // Move folds down
11878                    unfold_ranges.push(range_to_move.clone());
11879                    for fold in display_map.folds_in_range(
11880                        buffer.anchor_before(range_to_move.start)
11881                            ..buffer.anchor_after(range_to_move.end),
11882                    ) {
11883                        let mut start = fold.range.start.to_point(&buffer);
11884                        let mut end = fold.range.end.to_point(&buffer);
11885                        start.row += row_delta;
11886                        end.row += row_delta;
11887                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11888                    }
11889                }
11890            }
11891
11892            // If we didn't move line(s), preserve the existing selections
11893            new_selections.append(&mut contiguous_row_selections);
11894        }
11895
11896        self.transact(window, cx, |this, window, cx| {
11897            this.unfold_ranges(&unfold_ranges, true, true, cx);
11898            this.buffer.update(cx, |buffer, cx| {
11899                for (range, text) in edits {
11900                    buffer.edit([(range, text)], None, cx);
11901                }
11902            });
11903            this.fold_creases(refold_creases, true, window, cx);
11904            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
11905        });
11906    }
11907
11908    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
11909        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11910        let text_layout_details = &self.text_layout_details(window);
11911        self.transact(window, cx, |this, window, cx| {
11912            let edits = this.change_selections(Default::default(), window, cx, |s| {
11913                let mut edits: Vec<(Range<usize>, String)> = Default::default();
11914                s.move_with(|display_map, selection| {
11915                    if !selection.is_empty() {
11916                        return;
11917                    }
11918
11919                    let mut head = selection.head();
11920                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
11921                    if head.column() == display_map.line_len(head.row()) {
11922                        transpose_offset = display_map
11923                            .buffer_snapshot()
11924                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11925                    }
11926
11927                    if transpose_offset == 0 {
11928                        return;
11929                    }
11930
11931                    *head.column_mut() += 1;
11932                    head = display_map.clip_point(head, Bias::Right);
11933                    let goal = SelectionGoal::HorizontalPosition(
11934                        display_map
11935                            .x_for_display_point(head, text_layout_details)
11936                            .into(),
11937                    );
11938                    selection.collapse_to(head, goal);
11939
11940                    let transpose_start = display_map
11941                        .buffer_snapshot()
11942                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11943                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
11944                        let transpose_end = display_map
11945                            .buffer_snapshot()
11946                            .clip_offset(transpose_offset + 1, Bias::Right);
11947                        if let Some(ch) = display_map
11948                            .buffer_snapshot()
11949                            .chars_at(transpose_start)
11950                            .next()
11951                        {
11952                            edits.push((transpose_start..transpose_offset, String::new()));
11953                            edits.push((transpose_end..transpose_end, ch.to_string()));
11954                        }
11955                    }
11956                });
11957                edits
11958            });
11959            this.buffer
11960                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11961            let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
11962            this.change_selections(Default::default(), window, cx, |s| {
11963                s.select(selections);
11964            });
11965        });
11966    }
11967
11968    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
11969        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11970        if self.mode.is_single_line() {
11971            cx.propagate();
11972            return;
11973        }
11974
11975        self.rewrap_impl(RewrapOptions::default(), cx)
11976    }
11977
11978    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
11979        let buffer = self.buffer.read(cx).snapshot(cx);
11980        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
11981
11982        #[derive(Clone, Debug, PartialEq)]
11983        enum CommentFormat {
11984            /// single line comment, with prefix for line
11985            Line(String),
11986            /// single line within a block comment, with prefix for line
11987            BlockLine(String),
11988            /// a single line of a block comment that includes the initial delimiter
11989            BlockCommentWithStart(BlockCommentConfig),
11990            /// a single line of a block comment that includes the ending delimiter
11991            BlockCommentWithEnd(BlockCommentConfig),
11992        }
11993
11994        // Split selections to respect paragraph, indent, and comment prefix boundaries.
11995        let wrap_ranges = selections.into_iter().flat_map(|selection| {
11996            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
11997                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11998                .peekable();
11999
12000            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
12001                row
12002            } else {
12003                return Vec::new();
12004            };
12005
12006            let language_settings = buffer.language_settings_at(selection.head(), cx);
12007            let language_scope = buffer.language_scope_at(selection.head());
12008
12009            let indent_and_prefix_for_row =
12010                |row: u32| -> (IndentSize, Option<CommentFormat>, Option<String>) {
12011                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
12012                    let (comment_prefix, rewrap_prefix) = if let Some(language_scope) =
12013                        &language_scope
12014                    {
12015                        let indent_end = Point::new(row, indent.len);
12016                        let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12017                        let line_text_after_indent = buffer
12018                            .text_for_range(indent_end..line_end)
12019                            .collect::<String>();
12020
12021                        let is_within_comment_override = buffer
12022                            .language_scope_at(indent_end)
12023                            .is_some_and(|scope| scope.override_name() == Some("comment"));
12024                        let comment_delimiters = if is_within_comment_override {
12025                            // we are within a comment syntax node, but we don't
12026                            // yet know what kind of comment: block, doc or line
12027                            match (
12028                                language_scope.documentation_comment(),
12029                                language_scope.block_comment(),
12030                            ) {
12031                                (Some(config), _) | (_, Some(config))
12032                                    if buffer.contains_str_at(indent_end, &config.start) =>
12033                                {
12034                                    Some(CommentFormat::BlockCommentWithStart(config.clone()))
12035                                }
12036                                (Some(config), _) | (_, Some(config))
12037                                    if line_text_after_indent.ends_with(config.end.as_ref()) =>
12038                                {
12039                                    Some(CommentFormat::BlockCommentWithEnd(config.clone()))
12040                                }
12041                                (Some(config), _) | (_, Some(config))
12042                                    if buffer.contains_str_at(indent_end, &config.prefix) =>
12043                                {
12044                                    Some(CommentFormat::BlockLine(config.prefix.to_string()))
12045                                }
12046                                (_, _) => language_scope
12047                                    .line_comment_prefixes()
12048                                    .iter()
12049                                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12050                                    .map(|prefix| CommentFormat::Line(prefix.to_string())),
12051                            }
12052                        } else {
12053                            // we not in an overridden comment node, but we may
12054                            // be within a non-overridden line comment node
12055                            language_scope
12056                                .line_comment_prefixes()
12057                                .iter()
12058                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12059                                .map(|prefix| CommentFormat::Line(prefix.to_string()))
12060                        };
12061
12062                        let rewrap_prefix = language_scope
12063                            .rewrap_prefixes()
12064                            .iter()
12065                            .find_map(|prefix_regex| {
12066                                prefix_regex.find(&line_text_after_indent).map(|mat| {
12067                                    if mat.start() == 0 {
12068                                        Some(mat.as_str().to_string())
12069                                    } else {
12070                                        None
12071                                    }
12072                                })
12073                            })
12074                            .flatten();
12075                        (comment_delimiters, rewrap_prefix)
12076                    } else {
12077                        (None, None)
12078                    };
12079                    (indent, comment_prefix, rewrap_prefix)
12080                };
12081
12082            let mut ranges = Vec::new();
12083            let from_empty_selection = selection.is_empty();
12084
12085            let mut current_range_start = first_row;
12086            let mut prev_row = first_row;
12087            let (
12088                mut current_range_indent,
12089                mut current_range_comment_delimiters,
12090                mut current_range_rewrap_prefix,
12091            ) = indent_and_prefix_for_row(first_row);
12092
12093            for row in non_blank_rows_iter.skip(1) {
12094                let has_paragraph_break = row > prev_row + 1;
12095
12096                let (row_indent, row_comment_delimiters, row_rewrap_prefix) =
12097                    indent_and_prefix_for_row(row);
12098
12099                let has_indent_change = row_indent != current_range_indent;
12100                let has_comment_change = row_comment_delimiters != current_range_comment_delimiters;
12101
12102                let has_boundary_change = has_comment_change
12103                    || row_rewrap_prefix.is_some()
12104                    || (has_indent_change && current_range_comment_delimiters.is_some());
12105
12106                if has_paragraph_break || has_boundary_change {
12107                    ranges.push((
12108                        language_settings.clone(),
12109                        Point::new(current_range_start, 0)
12110                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12111                        current_range_indent,
12112                        current_range_comment_delimiters.clone(),
12113                        current_range_rewrap_prefix.clone(),
12114                        from_empty_selection,
12115                    ));
12116                    current_range_start = row;
12117                    current_range_indent = row_indent;
12118                    current_range_comment_delimiters = row_comment_delimiters;
12119                    current_range_rewrap_prefix = row_rewrap_prefix;
12120                }
12121                prev_row = row;
12122            }
12123
12124            ranges.push((
12125                language_settings.clone(),
12126                Point::new(current_range_start, 0)
12127                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12128                current_range_indent,
12129                current_range_comment_delimiters,
12130                current_range_rewrap_prefix,
12131                from_empty_selection,
12132            ));
12133
12134            ranges
12135        });
12136
12137        let mut edits = Vec::new();
12138        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
12139
12140        for (
12141            language_settings,
12142            wrap_range,
12143            mut indent_size,
12144            comment_prefix,
12145            rewrap_prefix,
12146            from_empty_selection,
12147        ) in wrap_ranges
12148        {
12149            let mut start_row = wrap_range.start.row;
12150            let mut end_row = wrap_range.end.row;
12151
12152            // Skip selections that overlap with a range that has already been rewrapped.
12153            let selection_range = start_row..end_row;
12154            if rewrapped_row_ranges
12155                .iter()
12156                .any(|range| range.overlaps(&selection_range))
12157            {
12158                continue;
12159            }
12160
12161            let tab_size = language_settings.tab_size;
12162
12163            let (line_prefix, inside_comment) = match &comment_prefix {
12164                Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
12165                    (Some(prefix.as_str()), true)
12166                }
12167                Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig { prefix, .. })) => {
12168                    (Some(prefix.as_ref()), true)
12169                }
12170                Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12171                    start: _,
12172                    end: _,
12173                    prefix,
12174                    tab_size,
12175                })) => {
12176                    indent_size.len += tab_size;
12177                    (Some(prefix.as_ref()), true)
12178                }
12179                None => (None, false),
12180            };
12181            let indent_prefix = indent_size.chars().collect::<String>();
12182            let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
12183
12184            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
12185                RewrapBehavior::InComments => inside_comment,
12186                RewrapBehavior::InSelections => !wrap_range.is_empty(),
12187                RewrapBehavior::Anywhere => true,
12188            };
12189
12190            let should_rewrap = options.override_language_settings
12191                || allow_rewrap_based_on_language
12192                || self.hard_wrap.is_some();
12193            if !should_rewrap {
12194                continue;
12195            }
12196
12197            if from_empty_selection {
12198                'expand_upwards: while start_row > 0 {
12199                    let prev_row = start_row - 1;
12200                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
12201                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
12202                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
12203                    {
12204                        start_row = prev_row;
12205                    } else {
12206                        break 'expand_upwards;
12207                    }
12208                }
12209
12210                'expand_downwards: while end_row < buffer.max_point().row {
12211                    let next_row = end_row + 1;
12212                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
12213                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
12214                        && !buffer.is_line_blank(MultiBufferRow(next_row))
12215                    {
12216                        end_row = next_row;
12217                    } else {
12218                        break 'expand_downwards;
12219                    }
12220                }
12221            }
12222
12223            let start = Point::new(start_row, 0);
12224            let start_offset = ToOffset::to_offset(&start, &buffer);
12225            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
12226            let selection_text = buffer.text_for_range(start..end).collect::<String>();
12227            let mut first_line_delimiter = None;
12228            let mut last_line_delimiter = None;
12229            let Some(lines_without_prefixes) = selection_text
12230                .lines()
12231                .enumerate()
12232                .map(|(ix, line)| {
12233                    let line_trimmed = line.trim_start();
12234                    if rewrap_prefix.is_some() && ix > 0 {
12235                        Ok(line_trimmed)
12236                    } else if let Some(
12237                        CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12238                            start,
12239                            prefix,
12240                            end,
12241                            tab_size,
12242                        })
12243                        | CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
12244                            start,
12245                            prefix,
12246                            end,
12247                            tab_size,
12248                        }),
12249                    ) = &comment_prefix
12250                    {
12251                        let line_trimmed = line_trimmed
12252                            .strip_prefix(start.as_ref())
12253                            .map(|s| {
12254                                let mut indent_size = indent_size;
12255                                indent_size.len -= tab_size;
12256                                let indent_prefix: String = indent_size.chars().collect();
12257                                first_line_delimiter = Some((indent_prefix, start));
12258                                s.trim_start()
12259                            })
12260                            .unwrap_or(line_trimmed);
12261                        let line_trimmed = line_trimmed
12262                            .strip_suffix(end.as_ref())
12263                            .map(|s| {
12264                                last_line_delimiter = Some(end);
12265                                s.trim_end()
12266                            })
12267                            .unwrap_or(line_trimmed);
12268                        let line_trimmed = line_trimmed
12269                            .strip_prefix(prefix.as_ref())
12270                            .unwrap_or(line_trimmed);
12271                        Ok(line_trimmed)
12272                    } else if let Some(CommentFormat::BlockLine(prefix)) = &comment_prefix {
12273                        line_trimmed.strip_prefix(prefix).with_context(|| {
12274                            format!("line did not start with prefix {prefix:?}: {line:?}")
12275                        })
12276                    } else {
12277                        line_trimmed
12278                            .strip_prefix(&line_prefix.trim_start())
12279                            .with_context(|| {
12280                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
12281                            })
12282                    }
12283                })
12284                .collect::<Result<Vec<_>, _>>()
12285                .log_err()
12286            else {
12287                continue;
12288            };
12289
12290            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
12291                buffer
12292                    .language_settings_at(Point::new(start_row, 0), cx)
12293                    .preferred_line_length as usize
12294            });
12295
12296            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
12297                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
12298            } else {
12299                line_prefix.clone()
12300            };
12301
12302            let wrapped_text = {
12303                let mut wrapped_text = wrap_with_prefix(
12304                    line_prefix,
12305                    subsequent_lines_prefix,
12306                    lines_without_prefixes.join("\n"),
12307                    wrap_column,
12308                    tab_size,
12309                    options.preserve_existing_whitespace,
12310                );
12311
12312                if let Some((indent, delimiter)) = first_line_delimiter {
12313                    wrapped_text = format!("{indent}{delimiter}\n{wrapped_text}");
12314                }
12315                if let Some(last_line) = last_line_delimiter {
12316                    wrapped_text = format!("{wrapped_text}\n{indent_prefix}{last_line}");
12317                }
12318
12319                wrapped_text
12320            };
12321
12322            // TODO: should always use char-based diff while still supporting cursor behavior that
12323            // matches vim.
12324            let mut diff_options = DiffOptions::default();
12325            if options.override_language_settings {
12326                diff_options.max_word_diff_len = 0;
12327                diff_options.max_word_diff_line_count = 0;
12328            } else {
12329                diff_options.max_word_diff_len = usize::MAX;
12330                diff_options.max_word_diff_line_count = usize::MAX;
12331            }
12332
12333            for (old_range, new_text) in
12334                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
12335            {
12336                let edit_start = buffer.anchor_after(start_offset + old_range.start);
12337                let edit_end = buffer.anchor_after(start_offset + old_range.end);
12338                edits.push((edit_start..edit_end, new_text));
12339            }
12340
12341            rewrapped_row_ranges.push(start_row..=end_row);
12342        }
12343
12344        self.buffer
12345            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12346    }
12347
12348    pub fn cut_common(
12349        &mut self,
12350        cut_no_selection_line: bool,
12351        window: &mut Window,
12352        cx: &mut Context<Self>,
12353    ) -> ClipboardItem {
12354        let mut text = String::new();
12355        let buffer = self.buffer.read(cx).snapshot(cx);
12356        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12357        let mut clipboard_selections = Vec::with_capacity(selections.len());
12358        {
12359            let max_point = buffer.max_point();
12360            let mut is_first = true;
12361            for selection in &mut selections {
12362                let is_entire_line =
12363                    (selection.is_empty() && cut_no_selection_line) || self.selections.line_mode();
12364                if is_entire_line {
12365                    selection.start = Point::new(selection.start.row, 0);
12366                    if !selection.is_empty() && selection.end.column == 0 {
12367                        selection.end = cmp::min(max_point, selection.end);
12368                    } else {
12369                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
12370                    }
12371                    selection.goal = SelectionGoal::None;
12372                }
12373                if is_first {
12374                    is_first = false;
12375                } else {
12376                    text += "\n";
12377                }
12378                let mut len = 0;
12379                for chunk in buffer.text_for_range(selection.start..selection.end) {
12380                    text.push_str(chunk);
12381                    len += chunk.len();
12382                }
12383                clipboard_selections.push(ClipboardSelection {
12384                    len,
12385                    is_entire_line,
12386                    first_line_indent: buffer
12387                        .indent_size_for_line(MultiBufferRow(selection.start.row))
12388                        .len,
12389                });
12390            }
12391        }
12392
12393        self.transact(window, cx, |this, window, cx| {
12394            this.change_selections(Default::default(), window, cx, |s| {
12395                s.select(selections);
12396            });
12397            this.insert("", window, cx);
12398        });
12399        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
12400    }
12401
12402    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
12403        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12404        let item = self.cut_common(true, window, cx);
12405        cx.write_to_clipboard(item);
12406    }
12407
12408    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
12409        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12410        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12411            s.move_with(|snapshot, sel| {
12412                if sel.is_empty() {
12413                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()));
12414                }
12415                if sel.is_empty() {
12416                    sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
12417                }
12418            });
12419        });
12420        let item = self.cut_common(false, window, cx);
12421        cx.set_global(KillRing(item))
12422    }
12423
12424    pub fn kill_ring_yank(
12425        &mut self,
12426        _: &KillRingYank,
12427        window: &mut Window,
12428        cx: &mut Context<Self>,
12429    ) {
12430        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12431        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
12432            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
12433                (kill_ring.text().to_string(), kill_ring.metadata_json())
12434            } else {
12435                return;
12436            }
12437        } else {
12438            return;
12439        };
12440        self.do_paste(&text, metadata, false, window, cx);
12441    }
12442
12443    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
12444        self.do_copy(true, cx);
12445    }
12446
12447    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
12448        self.do_copy(false, cx);
12449    }
12450
12451    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
12452        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12453        let buffer = self.buffer.read(cx).read(cx);
12454        let mut text = String::new();
12455
12456        let mut clipboard_selections = Vec::with_capacity(selections.len());
12457        {
12458            let max_point = buffer.max_point();
12459            let mut is_first = true;
12460            for selection in &selections {
12461                let mut start = selection.start;
12462                let mut end = selection.end;
12463                let is_entire_line = selection.is_empty() || self.selections.line_mode();
12464                let mut add_trailing_newline = false;
12465                if is_entire_line {
12466                    start = Point::new(start.row, 0);
12467                    let next_line_start = Point::new(end.row + 1, 0);
12468                    if next_line_start <= max_point {
12469                        end = next_line_start;
12470                    } else {
12471                        // We're on the last line without a trailing newline.
12472                        // Copy to the end of the line and add a newline afterwards.
12473                        end = Point::new(end.row, buffer.line_len(MultiBufferRow(end.row)));
12474                        add_trailing_newline = true;
12475                    }
12476                }
12477
12478                let mut trimmed_selections = Vec::new();
12479                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
12480                    let row = MultiBufferRow(start.row);
12481                    let first_indent = buffer.indent_size_for_line(row);
12482                    if first_indent.len == 0 || start.column > first_indent.len {
12483                        trimmed_selections.push(start..end);
12484                    } else {
12485                        trimmed_selections.push(
12486                            Point::new(row.0, first_indent.len)
12487                                ..Point::new(row.0, buffer.line_len(row)),
12488                        );
12489                        for row in start.row + 1..=end.row {
12490                            let mut line_len = buffer.line_len(MultiBufferRow(row));
12491                            if row == end.row {
12492                                line_len = end.column;
12493                            }
12494                            if line_len == 0 {
12495                                trimmed_selections
12496                                    .push(Point::new(row, 0)..Point::new(row, line_len));
12497                                continue;
12498                            }
12499                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
12500                            if row_indent_size.len >= first_indent.len {
12501                                trimmed_selections.push(
12502                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
12503                                );
12504                            } else {
12505                                trimmed_selections.clear();
12506                                trimmed_selections.push(start..end);
12507                                break;
12508                            }
12509                        }
12510                    }
12511                } else {
12512                    trimmed_selections.push(start..end);
12513                }
12514
12515                for trimmed_range in trimmed_selections {
12516                    if is_first {
12517                        is_first = false;
12518                    } else {
12519                        text += "\n";
12520                    }
12521                    let mut len = 0;
12522                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12523                        text.push_str(chunk);
12524                        len += chunk.len();
12525                    }
12526                    if add_trailing_newline {
12527                        text.push('\n');
12528                        len += 1;
12529                    }
12530                    clipboard_selections.push(ClipboardSelection {
12531                        len,
12532                        is_entire_line,
12533                        first_line_indent: buffer
12534                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12535                            .len,
12536                    });
12537                }
12538            }
12539        }
12540
12541        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12542            text,
12543            clipboard_selections,
12544        ));
12545    }
12546
12547    pub fn do_paste(
12548        &mut self,
12549        text: &String,
12550        clipboard_selections: Option<Vec<ClipboardSelection>>,
12551        handle_entire_lines: bool,
12552        window: &mut Window,
12553        cx: &mut Context<Self>,
12554    ) {
12555        if self.read_only(cx) {
12556            return;
12557        }
12558
12559        let clipboard_text = Cow::Borrowed(text.as_str());
12560
12561        self.transact(window, cx, |this, window, cx| {
12562            let had_active_edit_prediction = this.has_active_edit_prediction();
12563            let display_map = this.display_snapshot(cx);
12564            let old_selections = this.selections.all::<usize>(&display_map);
12565            let cursor_offset = this.selections.last::<usize>(&display_map).head();
12566
12567            if let Some(mut clipboard_selections) = clipboard_selections {
12568                let all_selections_were_entire_line =
12569                    clipboard_selections.iter().all(|s| s.is_entire_line);
12570                let first_selection_indent_column =
12571                    clipboard_selections.first().map(|s| s.first_line_indent);
12572                if clipboard_selections.len() != old_selections.len() {
12573                    clipboard_selections.drain(..);
12574                }
12575                let mut auto_indent_on_paste = true;
12576
12577                this.buffer.update(cx, |buffer, cx| {
12578                    let snapshot = buffer.read(cx);
12579                    auto_indent_on_paste = snapshot
12580                        .language_settings_at(cursor_offset, cx)
12581                        .auto_indent_on_paste;
12582
12583                    let mut start_offset = 0;
12584                    let mut edits = Vec::new();
12585                    let mut original_indent_columns = Vec::new();
12586                    for (ix, selection) in old_selections.iter().enumerate() {
12587                        let to_insert;
12588                        let entire_line;
12589                        let original_indent_column;
12590                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12591                            let end_offset = start_offset + clipboard_selection.len;
12592                            to_insert = &clipboard_text[start_offset..end_offset];
12593                            entire_line = clipboard_selection.is_entire_line;
12594                            start_offset = end_offset + 1;
12595                            original_indent_column = Some(clipboard_selection.first_line_indent);
12596                        } else {
12597                            to_insert = &*clipboard_text;
12598                            entire_line = all_selections_were_entire_line;
12599                            original_indent_column = first_selection_indent_column
12600                        }
12601
12602                        let (range, to_insert) =
12603                            if selection.is_empty() && handle_entire_lines && entire_line {
12604                                // If the corresponding selection was empty when this slice of the
12605                                // clipboard text was written, then the entire line containing the
12606                                // selection was copied. If this selection is also currently empty,
12607                                // then paste the line before the current line of the buffer.
12608                                let column = selection.start.to_point(&snapshot).column as usize;
12609                                let line_start = selection.start - column;
12610                                (line_start..line_start, Cow::Borrowed(to_insert))
12611                            } else {
12612                                let language = snapshot.language_at(selection.head());
12613                                let range = selection.range();
12614                                if let Some(language) = language
12615                                    && language.name() == "Markdown".into()
12616                                {
12617                                    edit_for_markdown_paste(
12618                                        &snapshot,
12619                                        range,
12620                                        to_insert,
12621                                        url::Url::parse(to_insert).ok(),
12622                                    )
12623                                } else {
12624                                    (range, Cow::Borrowed(to_insert))
12625                                }
12626                            };
12627
12628                        edits.push((range, to_insert));
12629                        original_indent_columns.push(original_indent_column);
12630                    }
12631                    drop(snapshot);
12632
12633                    buffer.edit(
12634                        edits,
12635                        if auto_indent_on_paste {
12636                            Some(AutoindentMode::Block {
12637                                original_indent_columns,
12638                            })
12639                        } else {
12640                            None
12641                        },
12642                        cx,
12643                    );
12644                });
12645
12646                let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
12647                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12648            } else {
12649                let url = url::Url::parse(&clipboard_text).ok();
12650
12651                let auto_indent_mode = if !clipboard_text.is_empty() {
12652                    Some(AutoindentMode::Block {
12653                        original_indent_columns: Vec::new(),
12654                    })
12655                } else {
12656                    None
12657                };
12658
12659                let selection_anchors = this.buffer.update(cx, |buffer, cx| {
12660                    let snapshot = buffer.snapshot(cx);
12661
12662                    let anchors = old_selections
12663                        .iter()
12664                        .map(|s| {
12665                            let anchor = snapshot.anchor_after(s.head());
12666                            s.map(|_| anchor)
12667                        })
12668                        .collect::<Vec<_>>();
12669
12670                    let mut edits = Vec::new();
12671
12672                    for selection in old_selections.iter() {
12673                        let language = snapshot.language_at(selection.head());
12674                        let range = selection.range();
12675
12676                        let (edit_range, edit_text) = if let Some(language) = language
12677                            && language.name() == "Markdown".into()
12678                        {
12679                            edit_for_markdown_paste(&snapshot, range, &clipboard_text, url.clone())
12680                        } else {
12681                            (range, clipboard_text.clone())
12682                        };
12683
12684                        edits.push((edit_range, edit_text));
12685                    }
12686
12687                    drop(snapshot);
12688                    buffer.edit(edits, auto_indent_mode, cx);
12689
12690                    anchors
12691                });
12692
12693                this.change_selections(Default::default(), window, cx, |s| {
12694                    s.select_anchors(selection_anchors);
12695                });
12696            }
12697
12698            let trigger_in_words =
12699                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
12700
12701            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
12702        });
12703    }
12704
12705    pub fn diff_clipboard_with_selection(
12706        &mut self,
12707        _: &DiffClipboardWithSelection,
12708        window: &mut Window,
12709        cx: &mut Context<Self>,
12710    ) {
12711        let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
12712
12713        if selections.is_empty() {
12714            log::warn!("There should always be at least one selection in Zed. This is a bug.");
12715            return;
12716        };
12717
12718        let clipboard_text = match cx.read_from_clipboard() {
12719            Some(item) => match item.entries().first() {
12720                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
12721                _ => None,
12722            },
12723            None => None,
12724        };
12725
12726        let Some(clipboard_text) = clipboard_text else {
12727            log::warn!("Clipboard doesn't contain text.");
12728            return;
12729        };
12730
12731        window.dispatch_action(
12732            Box::new(DiffClipboardWithSelectionData {
12733                clipboard_text,
12734                editor: cx.entity(),
12735            }),
12736            cx,
12737        );
12738    }
12739
12740    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
12741        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12742        if let Some(item) = cx.read_from_clipboard() {
12743            let entries = item.entries();
12744
12745            match entries.first() {
12746                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
12747                // of all the pasted entries.
12748                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
12749                    .do_paste(
12750                        clipboard_string.text(),
12751                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
12752                        true,
12753                        window,
12754                        cx,
12755                    ),
12756                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
12757            }
12758        }
12759    }
12760
12761    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
12762        if self.read_only(cx) {
12763            return;
12764        }
12765
12766        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12767
12768        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
12769            if let Some((selections, _)) =
12770                self.selection_history.transaction(transaction_id).cloned()
12771            {
12772                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12773                    s.select_anchors(selections.to_vec());
12774                });
12775            } else {
12776                log::error!(
12777                    "No entry in selection_history found for undo. \
12778                     This may correspond to a bug where undo does not update the selection. \
12779                     If this is occurring, please add details to \
12780                     https://github.com/zed-industries/zed/issues/22692"
12781                );
12782            }
12783            self.request_autoscroll(Autoscroll::fit(), cx);
12784            self.unmark_text(window, cx);
12785            self.refresh_edit_prediction(true, false, window, cx);
12786            cx.emit(EditorEvent::Edited { transaction_id });
12787            cx.emit(EditorEvent::TransactionUndone { transaction_id });
12788        }
12789    }
12790
12791    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
12792        if self.read_only(cx) {
12793            return;
12794        }
12795
12796        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12797
12798        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
12799            if let Some((_, Some(selections))) =
12800                self.selection_history.transaction(transaction_id).cloned()
12801            {
12802                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12803                    s.select_anchors(selections.to_vec());
12804                });
12805            } else {
12806                log::error!(
12807                    "No entry in selection_history found for redo. \
12808                     This may correspond to a bug where undo does not update the selection. \
12809                     If this is occurring, please add details to \
12810                     https://github.com/zed-industries/zed/issues/22692"
12811                );
12812            }
12813            self.request_autoscroll(Autoscroll::fit(), cx);
12814            self.unmark_text(window, cx);
12815            self.refresh_edit_prediction(true, false, window, cx);
12816            cx.emit(EditorEvent::Edited { transaction_id });
12817        }
12818    }
12819
12820    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
12821        self.buffer
12822            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
12823    }
12824
12825    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
12826        self.buffer
12827            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
12828    }
12829
12830    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
12831        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12832        self.change_selections(Default::default(), window, cx, |s| {
12833            s.move_with(|map, selection| {
12834                let cursor = if selection.is_empty() {
12835                    movement::left(map, selection.start)
12836                } else {
12837                    selection.start
12838                };
12839                selection.collapse_to(cursor, SelectionGoal::None);
12840            });
12841        })
12842    }
12843
12844    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
12845        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12846        self.change_selections(Default::default(), window, cx, |s| {
12847            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
12848        })
12849    }
12850
12851    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
12852        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12853        self.change_selections(Default::default(), window, cx, |s| {
12854            s.move_with(|map, selection| {
12855                let cursor = if selection.is_empty() {
12856                    movement::right(map, selection.end)
12857                } else {
12858                    selection.end
12859                };
12860                selection.collapse_to(cursor, SelectionGoal::None)
12861            });
12862        })
12863    }
12864
12865    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
12866        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12867        self.change_selections(Default::default(), window, cx, |s| {
12868            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
12869        });
12870    }
12871
12872    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
12873        if self.take_rename(true, window, cx).is_some() {
12874            return;
12875        }
12876
12877        if self.mode.is_single_line() {
12878            cx.propagate();
12879            return;
12880        }
12881
12882        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12883
12884        let text_layout_details = &self.text_layout_details(window);
12885        let selection_count = self.selections.count();
12886        let first_selection = self.selections.first_anchor();
12887
12888        self.change_selections(Default::default(), window, cx, |s| {
12889            s.move_with(|map, selection| {
12890                if !selection.is_empty() {
12891                    selection.goal = SelectionGoal::None;
12892                }
12893                let (cursor, goal) = movement::up(
12894                    map,
12895                    selection.start,
12896                    selection.goal,
12897                    false,
12898                    text_layout_details,
12899                );
12900                selection.collapse_to(cursor, goal);
12901            });
12902        });
12903
12904        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12905        {
12906            cx.propagate();
12907        }
12908    }
12909
12910    pub fn move_up_by_lines(
12911        &mut self,
12912        action: &MoveUpByLines,
12913        window: &mut Window,
12914        cx: &mut Context<Self>,
12915    ) {
12916        if self.take_rename(true, window, cx).is_some() {
12917            return;
12918        }
12919
12920        if self.mode.is_single_line() {
12921            cx.propagate();
12922            return;
12923        }
12924
12925        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12926
12927        let text_layout_details = &self.text_layout_details(window);
12928
12929        self.change_selections(Default::default(), window, cx, |s| {
12930            s.move_with(|map, selection| {
12931                if !selection.is_empty() {
12932                    selection.goal = SelectionGoal::None;
12933                }
12934                let (cursor, goal) = movement::up_by_rows(
12935                    map,
12936                    selection.start,
12937                    action.lines,
12938                    selection.goal,
12939                    false,
12940                    text_layout_details,
12941                );
12942                selection.collapse_to(cursor, goal);
12943            });
12944        })
12945    }
12946
12947    pub fn move_down_by_lines(
12948        &mut self,
12949        action: &MoveDownByLines,
12950        window: &mut Window,
12951        cx: &mut Context<Self>,
12952    ) {
12953        if self.take_rename(true, window, cx).is_some() {
12954            return;
12955        }
12956
12957        if self.mode.is_single_line() {
12958            cx.propagate();
12959            return;
12960        }
12961
12962        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12963
12964        let text_layout_details = &self.text_layout_details(window);
12965
12966        self.change_selections(Default::default(), window, cx, |s| {
12967            s.move_with(|map, selection| {
12968                if !selection.is_empty() {
12969                    selection.goal = SelectionGoal::None;
12970                }
12971                let (cursor, goal) = movement::down_by_rows(
12972                    map,
12973                    selection.start,
12974                    action.lines,
12975                    selection.goal,
12976                    false,
12977                    text_layout_details,
12978                );
12979                selection.collapse_to(cursor, goal);
12980            });
12981        })
12982    }
12983
12984    pub fn select_down_by_lines(
12985        &mut self,
12986        action: &SelectDownByLines,
12987        window: &mut Window,
12988        cx: &mut Context<Self>,
12989    ) {
12990        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12991        let text_layout_details = &self.text_layout_details(window);
12992        self.change_selections(Default::default(), window, cx, |s| {
12993            s.move_heads_with(|map, head, goal| {
12994                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
12995            })
12996        })
12997    }
12998
12999    pub fn select_up_by_lines(
13000        &mut self,
13001        action: &SelectUpByLines,
13002        window: &mut Window,
13003        cx: &mut Context<Self>,
13004    ) {
13005        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13006        let text_layout_details = &self.text_layout_details(window);
13007        self.change_selections(Default::default(), window, cx, |s| {
13008            s.move_heads_with(|map, head, goal| {
13009                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
13010            })
13011        })
13012    }
13013
13014    pub fn select_page_up(
13015        &mut self,
13016        _: &SelectPageUp,
13017        window: &mut Window,
13018        cx: &mut Context<Self>,
13019    ) {
13020        let Some(row_count) = self.visible_row_count() else {
13021            return;
13022        };
13023
13024        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13025
13026        let text_layout_details = &self.text_layout_details(window);
13027
13028        self.change_selections(Default::default(), window, cx, |s| {
13029            s.move_heads_with(|map, head, goal| {
13030                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
13031            })
13032        })
13033    }
13034
13035    pub fn move_page_up(
13036        &mut self,
13037        action: &MovePageUp,
13038        window: &mut Window,
13039        cx: &mut Context<Self>,
13040    ) {
13041        if self.take_rename(true, window, cx).is_some() {
13042            return;
13043        }
13044
13045        if self
13046            .context_menu
13047            .borrow_mut()
13048            .as_mut()
13049            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
13050            .unwrap_or(false)
13051        {
13052            return;
13053        }
13054
13055        if matches!(self.mode, EditorMode::SingleLine) {
13056            cx.propagate();
13057            return;
13058        }
13059
13060        let Some(row_count) = self.visible_row_count() else {
13061            return;
13062        };
13063
13064        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13065
13066        let effects = if action.center_cursor {
13067            SelectionEffects::scroll(Autoscroll::center())
13068        } else {
13069            SelectionEffects::default()
13070        };
13071
13072        let text_layout_details = &self.text_layout_details(window);
13073
13074        self.change_selections(effects, window, cx, |s| {
13075            s.move_with(|map, selection| {
13076                if !selection.is_empty() {
13077                    selection.goal = SelectionGoal::None;
13078                }
13079                let (cursor, goal) = movement::up_by_rows(
13080                    map,
13081                    selection.end,
13082                    row_count,
13083                    selection.goal,
13084                    false,
13085                    text_layout_details,
13086                );
13087                selection.collapse_to(cursor, goal);
13088            });
13089        });
13090    }
13091
13092    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
13093        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13094        let text_layout_details = &self.text_layout_details(window);
13095        self.change_selections(Default::default(), window, cx, |s| {
13096            s.move_heads_with(|map, head, goal| {
13097                movement::up(map, head, goal, false, text_layout_details)
13098            })
13099        })
13100    }
13101
13102    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
13103        self.take_rename(true, window, cx);
13104
13105        if self.mode.is_single_line() {
13106            cx.propagate();
13107            return;
13108        }
13109
13110        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13111
13112        let text_layout_details = &self.text_layout_details(window);
13113        let selection_count = self.selections.count();
13114        let first_selection = self.selections.first_anchor();
13115
13116        self.change_selections(Default::default(), window, cx, |s| {
13117            s.move_with(|map, selection| {
13118                if !selection.is_empty() {
13119                    selection.goal = SelectionGoal::None;
13120                }
13121                let (cursor, goal) = movement::down(
13122                    map,
13123                    selection.end,
13124                    selection.goal,
13125                    false,
13126                    text_layout_details,
13127                );
13128                selection.collapse_to(cursor, goal);
13129            });
13130        });
13131
13132        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13133        {
13134            cx.propagate();
13135        }
13136    }
13137
13138    pub fn select_page_down(
13139        &mut self,
13140        _: &SelectPageDown,
13141        window: &mut Window,
13142        cx: &mut Context<Self>,
13143    ) {
13144        let Some(row_count) = self.visible_row_count() else {
13145            return;
13146        };
13147
13148        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13149
13150        let text_layout_details = &self.text_layout_details(window);
13151
13152        self.change_selections(Default::default(), window, cx, |s| {
13153            s.move_heads_with(|map, head, goal| {
13154                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
13155            })
13156        })
13157    }
13158
13159    pub fn move_page_down(
13160        &mut self,
13161        action: &MovePageDown,
13162        window: &mut Window,
13163        cx: &mut Context<Self>,
13164    ) {
13165        if self.take_rename(true, window, cx).is_some() {
13166            return;
13167        }
13168
13169        if self
13170            .context_menu
13171            .borrow_mut()
13172            .as_mut()
13173            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
13174            .unwrap_or(false)
13175        {
13176            return;
13177        }
13178
13179        if matches!(self.mode, EditorMode::SingleLine) {
13180            cx.propagate();
13181            return;
13182        }
13183
13184        let Some(row_count) = self.visible_row_count() else {
13185            return;
13186        };
13187
13188        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13189
13190        let effects = if action.center_cursor {
13191            SelectionEffects::scroll(Autoscroll::center())
13192        } else {
13193            SelectionEffects::default()
13194        };
13195
13196        let text_layout_details = &self.text_layout_details(window);
13197        self.change_selections(effects, window, cx, |s| {
13198            s.move_with(|map, selection| {
13199                if !selection.is_empty() {
13200                    selection.goal = SelectionGoal::None;
13201                }
13202                let (cursor, goal) = movement::down_by_rows(
13203                    map,
13204                    selection.end,
13205                    row_count,
13206                    selection.goal,
13207                    false,
13208                    text_layout_details,
13209                );
13210                selection.collapse_to(cursor, goal);
13211            });
13212        });
13213    }
13214
13215    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
13216        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13217        let text_layout_details = &self.text_layout_details(window);
13218        self.change_selections(Default::default(), window, cx, |s| {
13219            s.move_heads_with(|map, head, goal| {
13220                movement::down(map, head, goal, false, text_layout_details)
13221            })
13222        });
13223    }
13224
13225    pub fn context_menu_first(
13226        &mut self,
13227        _: &ContextMenuFirst,
13228        window: &mut Window,
13229        cx: &mut Context<Self>,
13230    ) {
13231        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13232            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
13233        }
13234    }
13235
13236    pub fn context_menu_prev(
13237        &mut self,
13238        _: &ContextMenuPrevious,
13239        window: &mut Window,
13240        cx: &mut Context<Self>,
13241    ) {
13242        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13243            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
13244        }
13245    }
13246
13247    pub fn context_menu_next(
13248        &mut self,
13249        _: &ContextMenuNext,
13250        window: &mut Window,
13251        cx: &mut Context<Self>,
13252    ) {
13253        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13254            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
13255        }
13256    }
13257
13258    pub fn context_menu_last(
13259        &mut self,
13260        _: &ContextMenuLast,
13261        window: &mut Window,
13262        cx: &mut Context<Self>,
13263    ) {
13264        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13265            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
13266        }
13267    }
13268
13269    pub fn signature_help_prev(
13270        &mut self,
13271        _: &SignatureHelpPrevious,
13272        _: &mut Window,
13273        cx: &mut Context<Self>,
13274    ) {
13275        if let Some(popover) = self.signature_help_state.popover_mut() {
13276            if popover.current_signature == 0 {
13277                popover.current_signature = popover.signatures.len() - 1;
13278            } else {
13279                popover.current_signature -= 1;
13280            }
13281            cx.notify();
13282        }
13283    }
13284
13285    pub fn signature_help_next(
13286        &mut self,
13287        _: &SignatureHelpNext,
13288        _: &mut Window,
13289        cx: &mut Context<Self>,
13290    ) {
13291        if let Some(popover) = self.signature_help_state.popover_mut() {
13292            if popover.current_signature + 1 == popover.signatures.len() {
13293                popover.current_signature = 0;
13294            } else {
13295                popover.current_signature += 1;
13296            }
13297            cx.notify();
13298        }
13299    }
13300
13301    pub fn move_to_previous_word_start(
13302        &mut self,
13303        _: &MoveToPreviousWordStart,
13304        window: &mut Window,
13305        cx: &mut Context<Self>,
13306    ) {
13307        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13308        self.change_selections(Default::default(), window, cx, |s| {
13309            s.move_cursors_with(|map, head, _| {
13310                (
13311                    movement::previous_word_start(map, head),
13312                    SelectionGoal::None,
13313                )
13314            });
13315        })
13316    }
13317
13318    pub fn move_to_previous_subword_start(
13319        &mut self,
13320        _: &MoveToPreviousSubwordStart,
13321        window: &mut Window,
13322        cx: &mut Context<Self>,
13323    ) {
13324        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13325        self.change_selections(Default::default(), window, cx, |s| {
13326            s.move_cursors_with(|map, head, _| {
13327                (
13328                    movement::previous_subword_start(map, head),
13329                    SelectionGoal::None,
13330                )
13331            });
13332        })
13333    }
13334
13335    pub fn select_to_previous_word_start(
13336        &mut self,
13337        _: &SelectToPreviousWordStart,
13338        window: &mut Window,
13339        cx: &mut Context<Self>,
13340    ) {
13341        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13342        self.change_selections(Default::default(), window, cx, |s| {
13343            s.move_heads_with(|map, head, _| {
13344                (
13345                    movement::previous_word_start(map, head),
13346                    SelectionGoal::None,
13347                )
13348            });
13349        })
13350    }
13351
13352    pub fn select_to_previous_subword_start(
13353        &mut self,
13354        _: &SelectToPreviousSubwordStart,
13355        window: &mut Window,
13356        cx: &mut Context<Self>,
13357    ) {
13358        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13359        self.change_selections(Default::default(), window, cx, |s| {
13360            s.move_heads_with(|map, head, _| {
13361                (
13362                    movement::previous_subword_start(map, head),
13363                    SelectionGoal::None,
13364                )
13365            });
13366        })
13367    }
13368
13369    pub fn delete_to_previous_word_start(
13370        &mut self,
13371        action: &DeleteToPreviousWordStart,
13372        window: &mut Window,
13373        cx: &mut Context<Self>,
13374    ) {
13375        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13376        self.transact(window, cx, |this, window, cx| {
13377            this.select_autoclose_pair(window, cx);
13378            this.change_selections(Default::default(), window, cx, |s| {
13379                s.move_with(|map, selection| {
13380                    if selection.is_empty() {
13381                        let mut cursor = if action.ignore_newlines {
13382                            movement::previous_word_start(map, selection.head())
13383                        } else {
13384                            movement::previous_word_start_or_newline(map, selection.head())
13385                        };
13386                        cursor = movement::adjust_greedy_deletion(
13387                            map,
13388                            selection.head(),
13389                            cursor,
13390                            action.ignore_brackets,
13391                        );
13392                        selection.set_head(cursor, SelectionGoal::None);
13393                    }
13394                });
13395            });
13396            this.insert("", window, cx);
13397        });
13398    }
13399
13400    pub fn delete_to_previous_subword_start(
13401        &mut self,
13402        _: &DeleteToPreviousSubwordStart,
13403        window: &mut Window,
13404        cx: &mut Context<Self>,
13405    ) {
13406        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13407        self.transact(window, cx, |this, window, cx| {
13408            this.select_autoclose_pair(window, cx);
13409            this.change_selections(Default::default(), window, cx, |s| {
13410                s.move_with(|map, selection| {
13411                    if selection.is_empty() {
13412                        let mut cursor = movement::previous_subword_start(map, selection.head());
13413                        cursor =
13414                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13415                        selection.set_head(cursor, SelectionGoal::None);
13416                    }
13417                });
13418            });
13419            this.insert("", window, cx);
13420        });
13421    }
13422
13423    pub fn move_to_next_word_end(
13424        &mut self,
13425        _: &MoveToNextWordEnd,
13426        window: &mut Window,
13427        cx: &mut Context<Self>,
13428    ) {
13429        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13430        self.change_selections(Default::default(), window, cx, |s| {
13431            s.move_cursors_with(|map, head, _| {
13432                (movement::next_word_end(map, head), SelectionGoal::None)
13433            });
13434        })
13435    }
13436
13437    pub fn move_to_next_subword_end(
13438        &mut self,
13439        _: &MoveToNextSubwordEnd,
13440        window: &mut Window,
13441        cx: &mut Context<Self>,
13442    ) {
13443        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13444        self.change_selections(Default::default(), window, cx, |s| {
13445            s.move_cursors_with(|map, head, _| {
13446                (movement::next_subword_end(map, head), SelectionGoal::None)
13447            });
13448        })
13449    }
13450
13451    pub fn select_to_next_word_end(
13452        &mut self,
13453        _: &SelectToNextWordEnd,
13454        window: &mut Window,
13455        cx: &mut Context<Self>,
13456    ) {
13457        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13458        self.change_selections(Default::default(), window, cx, |s| {
13459            s.move_heads_with(|map, head, _| {
13460                (movement::next_word_end(map, head), SelectionGoal::None)
13461            });
13462        })
13463    }
13464
13465    pub fn select_to_next_subword_end(
13466        &mut self,
13467        _: &SelectToNextSubwordEnd,
13468        window: &mut Window,
13469        cx: &mut Context<Self>,
13470    ) {
13471        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13472        self.change_selections(Default::default(), window, cx, |s| {
13473            s.move_heads_with(|map, head, _| {
13474                (movement::next_subword_end(map, head), SelectionGoal::None)
13475            });
13476        })
13477    }
13478
13479    pub fn delete_to_next_word_end(
13480        &mut self,
13481        action: &DeleteToNextWordEnd,
13482        window: &mut Window,
13483        cx: &mut Context<Self>,
13484    ) {
13485        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13486        self.transact(window, cx, |this, window, cx| {
13487            this.change_selections(Default::default(), window, cx, |s| {
13488                s.move_with(|map, selection| {
13489                    if selection.is_empty() {
13490                        let mut cursor = if action.ignore_newlines {
13491                            movement::next_word_end(map, selection.head())
13492                        } else {
13493                            movement::next_word_end_or_newline(map, selection.head())
13494                        };
13495                        cursor = movement::adjust_greedy_deletion(
13496                            map,
13497                            selection.head(),
13498                            cursor,
13499                            action.ignore_brackets,
13500                        );
13501                        selection.set_head(cursor, SelectionGoal::None);
13502                    }
13503                });
13504            });
13505            this.insert("", window, cx);
13506        });
13507    }
13508
13509    pub fn delete_to_next_subword_end(
13510        &mut self,
13511        _: &DeleteToNextSubwordEnd,
13512        window: &mut Window,
13513        cx: &mut Context<Self>,
13514    ) {
13515        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13516        self.transact(window, cx, |this, window, cx| {
13517            this.change_selections(Default::default(), window, cx, |s| {
13518                s.move_with(|map, selection| {
13519                    if selection.is_empty() {
13520                        let mut cursor = movement::next_subword_end(map, selection.head());
13521                        cursor =
13522                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13523                        selection.set_head(cursor, SelectionGoal::None);
13524                    }
13525                });
13526            });
13527            this.insert("", window, cx);
13528        });
13529    }
13530
13531    pub fn move_to_beginning_of_line(
13532        &mut self,
13533        action: &MoveToBeginningOfLine,
13534        window: &mut Window,
13535        cx: &mut Context<Self>,
13536    ) {
13537        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13538        self.change_selections(Default::default(), window, cx, |s| {
13539            s.move_cursors_with(|map, head, _| {
13540                (
13541                    movement::indented_line_beginning(
13542                        map,
13543                        head,
13544                        action.stop_at_soft_wraps,
13545                        action.stop_at_indent,
13546                    ),
13547                    SelectionGoal::None,
13548                )
13549            });
13550        })
13551    }
13552
13553    pub fn select_to_beginning_of_line(
13554        &mut self,
13555        action: &SelectToBeginningOfLine,
13556        window: &mut Window,
13557        cx: &mut Context<Self>,
13558    ) {
13559        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13560        self.change_selections(Default::default(), window, cx, |s| {
13561            s.move_heads_with(|map, head, _| {
13562                (
13563                    movement::indented_line_beginning(
13564                        map,
13565                        head,
13566                        action.stop_at_soft_wraps,
13567                        action.stop_at_indent,
13568                    ),
13569                    SelectionGoal::None,
13570                )
13571            });
13572        });
13573    }
13574
13575    pub fn delete_to_beginning_of_line(
13576        &mut self,
13577        action: &DeleteToBeginningOfLine,
13578        window: &mut Window,
13579        cx: &mut Context<Self>,
13580    ) {
13581        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13582        self.transact(window, cx, |this, window, cx| {
13583            this.change_selections(Default::default(), window, cx, |s| {
13584                s.move_with(|_, selection| {
13585                    selection.reversed = true;
13586                });
13587            });
13588
13589            this.select_to_beginning_of_line(
13590                &SelectToBeginningOfLine {
13591                    stop_at_soft_wraps: false,
13592                    stop_at_indent: action.stop_at_indent,
13593                },
13594                window,
13595                cx,
13596            );
13597            this.backspace(&Backspace, window, cx);
13598        });
13599    }
13600
13601    pub fn move_to_end_of_line(
13602        &mut self,
13603        action: &MoveToEndOfLine,
13604        window: &mut Window,
13605        cx: &mut Context<Self>,
13606    ) {
13607        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13608        self.change_selections(Default::default(), window, cx, |s| {
13609            s.move_cursors_with(|map, head, _| {
13610                (
13611                    movement::line_end(map, head, action.stop_at_soft_wraps),
13612                    SelectionGoal::None,
13613                )
13614            });
13615        })
13616    }
13617
13618    pub fn select_to_end_of_line(
13619        &mut self,
13620        action: &SelectToEndOfLine,
13621        window: &mut Window,
13622        cx: &mut Context<Self>,
13623    ) {
13624        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13625        self.change_selections(Default::default(), window, cx, |s| {
13626            s.move_heads_with(|map, head, _| {
13627                (
13628                    movement::line_end(map, head, action.stop_at_soft_wraps),
13629                    SelectionGoal::None,
13630                )
13631            });
13632        })
13633    }
13634
13635    pub fn delete_to_end_of_line(
13636        &mut self,
13637        _: &DeleteToEndOfLine,
13638        window: &mut Window,
13639        cx: &mut Context<Self>,
13640    ) {
13641        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13642        self.transact(window, cx, |this, window, cx| {
13643            this.select_to_end_of_line(
13644                &SelectToEndOfLine {
13645                    stop_at_soft_wraps: false,
13646                },
13647                window,
13648                cx,
13649            );
13650            this.delete(&Delete, window, cx);
13651        });
13652    }
13653
13654    pub fn cut_to_end_of_line(
13655        &mut self,
13656        action: &CutToEndOfLine,
13657        window: &mut Window,
13658        cx: &mut Context<Self>,
13659    ) {
13660        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13661        self.transact(window, cx, |this, window, cx| {
13662            this.select_to_end_of_line(
13663                &SelectToEndOfLine {
13664                    stop_at_soft_wraps: false,
13665                },
13666                window,
13667                cx,
13668            );
13669            if !action.stop_at_newlines {
13670                this.change_selections(Default::default(), window, cx, |s| {
13671                    s.move_with(|_, sel| {
13672                        if sel.is_empty() {
13673                            sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
13674                        }
13675                    });
13676                });
13677            }
13678            this.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13679            let item = this.cut_common(false, window, cx);
13680            cx.write_to_clipboard(item);
13681        });
13682    }
13683
13684    pub fn move_to_start_of_paragraph(
13685        &mut self,
13686        _: &MoveToStartOfParagraph,
13687        window: &mut Window,
13688        cx: &mut Context<Self>,
13689    ) {
13690        if matches!(self.mode, EditorMode::SingleLine) {
13691            cx.propagate();
13692            return;
13693        }
13694        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13695        self.change_selections(Default::default(), window, cx, |s| {
13696            s.move_with(|map, selection| {
13697                selection.collapse_to(
13698                    movement::start_of_paragraph(map, selection.head(), 1),
13699                    SelectionGoal::None,
13700                )
13701            });
13702        })
13703    }
13704
13705    pub fn move_to_end_of_paragraph(
13706        &mut self,
13707        _: &MoveToEndOfParagraph,
13708        window: &mut Window,
13709        cx: &mut Context<Self>,
13710    ) {
13711        if matches!(self.mode, EditorMode::SingleLine) {
13712            cx.propagate();
13713            return;
13714        }
13715        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13716        self.change_selections(Default::default(), window, cx, |s| {
13717            s.move_with(|map, selection| {
13718                selection.collapse_to(
13719                    movement::end_of_paragraph(map, selection.head(), 1),
13720                    SelectionGoal::None,
13721                )
13722            });
13723        })
13724    }
13725
13726    pub fn select_to_start_of_paragraph(
13727        &mut self,
13728        _: &SelectToStartOfParagraph,
13729        window: &mut Window,
13730        cx: &mut Context<Self>,
13731    ) {
13732        if matches!(self.mode, EditorMode::SingleLine) {
13733            cx.propagate();
13734            return;
13735        }
13736        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13737        self.change_selections(Default::default(), window, cx, |s| {
13738            s.move_heads_with(|map, head, _| {
13739                (
13740                    movement::start_of_paragraph(map, head, 1),
13741                    SelectionGoal::None,
13742                )
13743            });
13744        })
13745    }
13746
13747    pub fn select_to_end_of_paragraph(
13748        &mut self,
13749        _: &SelectToEndOfParagraph,
13750        window: &mut Window,
13751        cx: &mut Context<Self>,
13752    ) {
13753        if matches!(self.mode, EditorMode::SingleLine) {
13754            cx.propagate();
13755            return;
13756        }
13757        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13758        self.change_selections(Default::default(), window, cx, |s| {
13759            s.move_heads_with(|map, head, _| {
13760                (
13761                    movement::end_of_paragraph(map, head, 1),
13762                    SelectionGoal::None,
13763                )
13764            });
13765        })
13766    }
13767
13768    pub fn move_to_start_of_excerpt(
13769        &mut self,
13770        _: &MoveToStartOfExcerpt,
13771        window: &mut Window,
13772        cx: &mut Context<Self>,
13773    ) {
13774        if matches!(self.mode, EditorMode::SingleLine) {
13775            cx.propagate();
13776            return;
13777        }
13778        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13779        self.change_selections(Default::default(), window, cx, |s| {
13780            s.move_with(|map, selection| {
13781                selection.collapse_to(
13782                    movement::start_of_excerpt(
13783                        map,
13784                        selection.head(),
13785                        workspace::searchable::Direction::Prev,
13786                    ),
13787                    SelectionGoal::None,
13788                )
13789            });
13790        })
13791    }
13792
13793    pub fn move_to_start_of_next_excerpt(
13794        &mut self,
13795        _: &MoveToStartOfNextExcerpt,
13796        window: &mut Window,
13797        cx: &mut Context<Self>,
13798    ) {
13799        if matches!(self.mode, EditorMode::SingleLine) {
13800            cx.propagate();
13801            return;
13802        }
13803
13804        self.change_selections(Default::default(), window, cx, |s| {
13805            s.move_with(|map, selection| {
13806                selection.collapse_to(
13807                    movement::start_of_excerpt(
13808                        map,
13809                        selection.head(),
13810                        workspace::searchable::Direction::Next,
13811                    ),
13812                    SelectionGoal::None,
13813                )
13814            });
13815        })
13816    }
13817
13818    pub fn move_to_end_of_excerpt(
13819        &mut self,
13820        _: &MoveToEndOfExcerpt,
13821        window: &mut Window,
13822        cx: &mut Context<Self>,
13823    ) {
13824        if matches!(self.mode, EditorMode::SingleLine) {
13825            cx.propagate();
13826            return;
13827        }
13828        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13829        self.change_selections(Default::default(), window, cx, |s| {
13830            s.move_with(|map, selection| {
13831                selection.collapse_to(
13832                    movement::end_of_excerpt(
13833                        map,
13834                        selection.head(),
13835                        workspace::searchable::Direction::Next,
13836                    ),
13837                    SelectionGoal::None,
13838                )
13839            });
13840        })
13841    }
13842
13843    pub fn move_to_end_of_previous_excerpt(
13844        &mut self,
13845        _: &MoveToEndOfPreviousExcerpt,
13846        window: &mut Window,
13847        cx: &mut Context<Self>,
13848    ) {
13849        if matches!(self.mode, EditorMode::SingleLine) {
13850            cx.propagate();
13851            return;
13852        }
13853        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13854        self.change_selections(Default::default(), window, cx, |s| {
13855            s.move_with(|map, selection| {
13856                selection.collapse_to(
13857                    movement::end_of_excerpt(
13858                        map,
13859                        selection.head(),
13860                        workspace::searchable::Direction::Prev,
13861                    ),
13862                    SelectionGoal::None,
13863                )
13864            });
13865        })
13866    }
13867
13868    pub fn select_to_start_of_excerpt(
13869        &mut self,
13870        _: &SelectToStartOfExcerpt,
13871        window: &mut Window,
13872        cx: &mut Context<Self>,
13873    ) {
13874        if matches!(self.mode, EditorMode::SingleLine) {
13875            cx.propagate();
13876            return;
13877        }
13878        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13879        self.change_selections(Default::default(), window, cx, |s| {
13880            s.move_heads_with(|map, head, _| {
13881                (
13882                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13883                    SelectionGoal::None,
13884                )
13885            });
13886        })
13887    }
13888
13889    pub fn select_to_start_of_next_excerpt(
13890        &mut self,
13891        _: &SelectToStartOfNextExcerpt,
13892        window: &mut Window,
13893        cx: &mut Context<Self>,
13894    ) {
13895        if matches!(self.mode, EditorMode::SingleLine) {
13896            cx.propagate();
13897            return;
13898        }
13899        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13900        self.change_selections(Default::default(), window, cx, |s| {
13901            s.move_heads_with(|map, head, _| {
13902                (
13903                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
13904                    SelectionGoal::None,
13905                )
13906            });
13907        })
13908    }
13909
13910    pub fn select_to_end_of_excerpt(
13911        &mut self,
13912        _: &SelectToEndOfExcerpt,
13913        window: &mut Window,
13914        cx: &mut Context<Self>,
13915    ) {
13916        if matches!(self.mode, EditorMode::SingleLine) {
13917            cx.propagate();
13918            return;
13919        }
13920        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13921        self.change_selections(Default::default(), window, cx, |s| {
13922            s.move_heads_with(|map, head, _| {
13923                (
13924                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
13925                    SelectionGoal::None,
13926                )
13927            });
13928        })
13929    }
13930
13931    pub fn select_to_end_of_previous_excerpt(
13932        &mut self,
13933        _: &SelectToEndOfPreviousExcerpt,
13934        window: &mut Window,
13935        cx: &mut Context<Self>,
13936    ) {
13937        if matches!(self.mode, EditorMode::SingleLine) {
13938            cx.propagate();
13939            return;
13940        }
13941        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13942        self.change_selections(Default::default(), window, cx, |s| {
13943            s.move_heads_with(|map, head, _| {
13944                (
13945                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13946                    SelectionGoal::None,
13947                )
13948            });
13949        })
13950    }
13951
13952    pub fn move_to_beginning(
13953        &mut self,
13954        _: &MoveToBeginning,
13955        window: &mut Window,
13956        cx: &mut Context<Self>,
13957    ) {
13958        if matches!(self.mode, EditorMode::SingleLine) {
13959            cx.propagate();
13960            return;
13961        }
13962        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13963        self.change_selections(Default::default(), window, cx, |s| {
13964            s.select_ranges(vec![0..0]);
13965        });
13966    }
13967
13968    pub fn select_to_beginning(
13969        &mut self,
13970        _: &SelectToBeginning,
13971        window: &mut Window,
13972        cx: &mut Context<Self>,
13973    ) {
13974        let mut selection = self.selections.last::<Point>(&self.display_snapshot(cx));
13975        selection.set_head(Point::zero(), SelectionGoal::None);
13976        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13977        self.change_selections(Default::default(), window, cx, |s| {
13978            s.select(vec![selection]);
13979        });
13980    }
13981
13982    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
13983        if matches!(self.mode, EditorMode::SingleLine) {
13984            cx.propagate();
13985            return;
13986        }
13987        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13988        let cursor = self.buffer.read(cx).read(cx).len();
13989        self.change_selections(Default::default(), window, cx, |s| {
13990            s.select_ranges(vec![cursor..cursor])
13991        });
13992    }
13993
13994    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
13995        self.nav_history = nav_history;
13996    }
13997
13998    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
13999        self.nav_history.as_ref()
14000    }
14001
14002    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
14003        self.push_to_nav_history(
14004            self.selections.newest_anchor().head(),
14005            None,
14006            false,
14007            true,
14008            cx,
14009        );
14010    }
14011
14012    fn push_to_nav_history(
14013        &mut self,
14014        cursor_anchor: Anchor,
14015        new_position: Option<Point>,
14016        is_deactivate: bool,
14017        always: bool,
14018        cx: &mut Context<Self>,
14019    ) {
14020        if let Some(nav_history) = self.nav_history.as_mut() {
14021            let buffer = self.buffer.read(cx).read(cx);
14022            let cursor_position = cursor_anchor.to_point(&buffer);
14023            let scroll_state = self.scroll_manager.anchor();
14024            let scroll_top_row = scroll_state.top_row(&buffer);
14025            drop(buffer);
14026
14027            if let Some(new_position) = new_position {
14028                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
14029                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
14030                    return;
14031                }
14032            }
14033
14034            nav_history.push(
14035                Some(NavigationData {
14036                    cursor_anchor,
14037                    cursor_position,
14038                    scroll_anchor: scroll_state,
14039                    scroll_top_row,
14040                }),
14041                cx,
14042            );
14043            cx.emit(EditorEvent::PushedToNavHistory {
14044                anchor: cursor_anchor,
14045                is_deactivate,
14046            })
14047        }
14048    }
14049
14050    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
14051        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14052        let buffer = self.buffer.read(cx).snapshot(cx);
14053        let mut selection = self.selections.first::<usize>(&self.display_snapshot(cx));
14054        selection.set_head(buffer.len(), SelectionGoal::None);
14055        self.change_selections(Default::default(), window, cx, |s| {
14056            s.select(vec![selection]);
14057        });
14058    }
14059
14060    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
14061        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14062        let end = self.buffer.read(cx).read(cx).len();
14063        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14064            s.select_ranges(vec![0..end]);
14065        });
14066    }
14067
14068    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
14069        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14070        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14071        let mut selections = self.selections.all::<Point>(&display_map);
14072        let max_point = display_map.buffer_snapshot().max_point();
14073        for selection in &mut selections {
14074            let rows = selection.spanned_rows(true, &display_map);
14075            selection.start = Point::new(rows.start.0, 0);
14076            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
14077            selection.reversed = false;
14078        }
14079        self.change_selections(Default::default(), window, cx, |s| {
14080            s.select(selections);
14081        });
14082    }
14083
14084    pub fn split_selection_into_lines(
14085        &mut self,
14086        action: &SplitSelectionIntoLines,
14087        window: &mut Window,
14088        cx: &mut Context<Self>,
14089    ) {
14090        let selections = self
14091            .selections
14092            .all::<Point>(&self.display_snapshot(cx))
14093            .into_iter()
14094            .map(|selection| selection.start..selection.end)
14095            .collect::<Vec<_>>();
14096        self.unfold_ranges(&selections, true, true, cx);
14097
14098        let mut new_selection_ranges = Vec::new();
14099        {
14100            let buffer = self.buffer.read(cx).read(cx);
14101            for selection in selections {
14102                for row in selection.start.row..selection.end.row {
14103                    let line_start = Point::new(row, 0);
14104                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
14105
14106                    if action.keep_selections {
14107                        // Keep the selection range for each line
14108                        let selection_start = if row == selection.start.row {
14109                            selection.start
14110                        } else {
14111                            line_start
14112                        };
14113                        new_selection_ranges.push(selection_start..line_end);
14114                    } else {
14115                        // Collapse to cursor at end of line
14116                        new_selection_ranges.push(line_end..line_end);
14117                    }
14118                }
14119
14120                let is_multiline_selection = selection.start.row != selection.end.row;
14121                // Don't insert last one if it's a multi-line selection ending at the start of a line,
14122                // so this action feels more ergonomic when paired with other selection operations
14123                let should_skip_last = is_multiline_selection && selection.end.column == 0;
14124                if !should_skip_last {
14125                    if action.keep_selections {
14126                        if is_multiline_selection {
14127                            let line_start = Point::new(selection.end.row, 0);
14128                            new_selection_ranges.push(line_start..selection.end);
14129                        } else {
14130                            new_selection_ranges.push(selection.start..selection.end);
14131                        }
14132                    } else {
14133                        new_selection_ranges.push(selection.end..selection.end);
14134                    }
14135                }
14136            }
14137        }
14138        self.change_selections(Default::default(), window, cx, |s| {
14139            s.select_ranges(new_selection_ranges);
14140        });
14141    }
14142
14143    pub fn add_selection_above(
14144        &mut self,
14145        action: &AddSelectionAbove,
14146        window: &mut Window,
14147        cx: &mut Context<Self>,
14148    ) {
14149        self.add_selection(true, action.skip_soft_wrap, window, cx);
14150    }
14151
14152    pub fn add_selection_below(
14153        &mut self,
14154        action: &AddSelectionBelow,
14155        window: &mut Window,
14156        cx: &mut Context<Self>,
14157    ) {
14158        self.add_selection(false, action.skip_soft_wrap, window, cx);
14159    }
14160
14161    fn add_selection(
14162        &mut self,
14163        above: bool,
14164        skip_soft_wrap: bool,
14165        window: &mut Window,
14166        cx: &mut Context<Self>,
14167    ) {
14168        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14169
14170        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14171        let all_selections = self.selections.all::<Point>(&display_map);
14172        let text_layout_details = self.text_layout_details(window);
14173
14174        let (mut columnar_selections, new_selections_to_columnarize) = {
14175            if let Some(state) = self.add_selections_state.as_ref() {
14176                let columnar_selection_ids: HashSet<_> = state
14177                    .groups
14178                    .iter()
14179                    .flat_map(|group| group.stack.iter())
14180                    .copied()
14181                    .collect();
14182
14183                all_selections
14184                    .into_iter()
14185                    .partition(|s| columnar_selection_ids.contains(&s.id))
14186            } else {
14187                (Vec::new(), all_selections)
14188            }
14189        };
14190
14191        let mut state = self
14192            .add_selections_state
14193            .take()
14194            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
14195
14196        for selection in new_selections_to_columnarize {
14197            let range = selection.display_range(&display_map).sorted();
14198            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
14199            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
14200            let positions = start_x.min(end_x)..start_x.max(end_x);
14201            let mut stack = Vec::new();
14202            for row in range.start.row().0..=range.end.row().0 {
14203                if let Some(selection) = self.selections.build_columnar_selection(
14204                    &display_map,
14205                    DisplayRow(row),
14206                    &positions,
14207                    selection.reversed,
14208                    &text_layout_details,
14209                ) {
14210                    stack.push(selection.id);
14211                    columnar_selections.push(selection);
14212                }
14213            }
14214            if !stack.is_empty() {
14215                if above {
14216                    stack.reverse();
14217                }
14218                state.groups.push(AddSelectionsGroup { above, stack });
14219            }
14220        }
14221
14222        let mut final_selections = Vec::new();
14223        let end_row = if above {
14224            DisplayRow(0)
14225        } else {
14226            display_map.max_point().row()
14227        };
14228
14229        let mut last_added_item_per_group = HashMap::default();
14230        for group in state.groups.iter_mut() {
14231            if let Some(last_id) = group.stack.last() {
14232                last_added_item_per_group.insert(*last_id, group);
14233            }
14234        }
14235
14236        for selection in columnar_selections {
14237            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
14238                if above == group.above {
14239                    let range = selection.display_range(&display_map).sorted();
14240                    debug_assert_eq!(range.start.row(), range.end.row());
14241                    let mut row = range.start.row();
14242                    let positions =
14243                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
14244                            Pixels::from(start)..Pixels::from(end)
14245                        } else {
14246                            let start_x =
14247                                display_map.x_for_display_point(range.start, &text_layout_details);
14248                            let end_x =
14249                                display_map.x_for_display_point(range.end, &text_layout_details);
14250                            start_x.min(end_x)..start_x.max(end_x)
14251                        };
14252
14253                    let mut maybe_new_selection = None;
14254                    let direction = if above { -1 } else { 1 };
14255
14256                    while row != end_row {
14257                        if skip_soft_wrap {
14258                            row = display_map
14259                                .start_of_relative_buffer_row(DisplayPoint::new(row, 0), direction)
14260                                .row();
14261                        } else if above {
14262                            row.0 -= 1;
14263                        } else {
14264                            row.0 += 1;
14265                        }
14266
14267                        if let Some(new_selection) = self.selections.build_columnar_selection(
14268                            &display_map,
14269                            row,
14270                            &positions,
14271                            selection.reversed,
14272                            &text_layout_details,
14273                        ) {
14274                            maybe_new_selection = Some(new_selection);
14275                            break;
14276                        }
14277                    }
14278
14279                    if let Some(new_selection) = maybe_new_selection {
14280                        group.stack.push(new_selection.id);
14281                        if above {
14282                            final_selections.push(new_selection);
14283                            final_selections.push(selection);
14284                        } else {
14285                            final_selections.push(selection);
14286                            final_selections.push(new_selection);
14287                        }
14288                    } else {
14289                        final_selections.push(selection);
14290                    }
14291                } else {
14292                    group.stack.pop();
14293                }
14294            } else {
14295                final_selections.push(selection);
14296            }
14297        }
14298
14299        self.change_selections(Default::default(), window, cx, |s| {
14300            s.select(final_selections);
14301        });
14302
14303        let final_selection_ids: HashSet<_> = self
14304            .selections
14305            .all::<Point>(&display_map)
14306            .iter()
14307            .map(|s| s.id)
14308            .collect();
14309        state.groups.retain_mut(|group| {
14310            // selections might get merged above so we remove invalid items from stacks
14311            group.stack.retain(|id| final_selection_ids.contains(id));
14312
14313            // single selection in stack can be treated as initial state
14314            group.stack.len() > 1
14315        });
14316
14317        if !state.groups.is_empty() {
14318            self.add_selections_state = Some(state);
14319        }
14320    }
14321
14322    fn select_match_ranges(
14323        &mut self,
14324        range: Range<usize>,
14325        reversed: bool,
14326        replace_newest: bool,
14327        auto_scroll: Option<Autoscroll>,
14328        window: &mut Window,
14329        cx: &mut Context<Editor>,
14330    ) {
14331        self.unfold_ranges(
14332            std::slice::from_ref(&range),
14333            false,
14334            auto_scroll.is_some(),
14335            cx,
14336        );
14337        let effects = if let Some(scroll) = auto_scroll {
14338            SelectionEffects::scroll(scroll)
14339        } else {
14340            SelectionEffects::no_scroll()
14341        };
14342        self.change_selections(effects, window, cx, |s| {
14343            if replace_newest {
14344                s.delete(s.newest_anchor().id);
14345            }
14346            if reversed {
14347                s.insert_range(range.end..range.start);
14348            } else {
14349                s.insert_range(range);
14350            }
14351        });
14352    }
14353
14354    pub fn select_next_match_internal(
14355        &mut self,
14356        display_map: &DisplaySnapshot,
14357        replace_newest: bool,
14358        autoscroll: Option<Autoscroll>,
14359        window: &mut Window,
14360        cx: &mut Context<Self>,
14361    ) -> Result<()> {
14362        let buffer = display_map.buffer_snapshot();
14363        let mut selections = self.selections.all::<usize>(&display_map);
14364        if let Some(mut select_next_state) = self.select_next_state.take() {
14365            let query = &select_next_state.query;
14366            if !select_next_state.done {
14367                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14368                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14369                let mut next_selected_range = None;
14370
14371                let bytes_after_last_selection =
14372                    buffer.bytes_in_range(last_selection.end..buffer.len());
14373                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
14374                let query_matches = query
14375                    .stream_find_iter(bytes_after_last_selection)
14376                    .map(|result| (last_selection.end, result))
14377                    .chain(
14378                        query
14379                            .stream_find_iter(bytes_before_first_selection)
14380                            .map(|result| (0, result)),
14381                    );
14382
14383                for (start_offset, query_match) in query_matches {
14384                    let query_match = query_match.unwrap(); // can only fail due to I/O
14385                    let offset_range =
14386                        start_offset + query_match.start()..start_offset + query_match.end();
14387
14388                    if !select_next_state.wordwise
14389                        || (!buffer.is_inside_word(offset_range.start, None)
14390                            && !buffer.is_inside_word(offset_range.end, None))
14391                    {
14392                        let idx = selections
14393                            .partition_point(|selection| selection.end <= offset_range.start);
14394                        let overlaps = selections
14395                            .get(idx)
14396                            .map_or(false, |selection| selection.start < offset_range.end);
14397
14398                        if !overlaps {
14399                            next_selected_range = Some(offset_range);
14400                            break;
14401                        }
14402                    }
14403                }
14404
14405                if let Some(next_selected_range) = next_selected_range {
14406                    self.select_match_ranges(
14407                        next_selected_range,
14408                        last_selection.reversed,
14409                        replace_newest,
14410                        autoscroll,
14411                        window,
14412                        cx,
14413                    );
14414                } else {
14415                    select_next_state.done = true;
14416                }
14417            }
14418
14419            self.select_next_state = Some(select_next_state);
14420        } else {
14421            let mut only_carets = true;
14422            let mut same_text_selected = true;
14423            let mut selected_text = None;
14424
14425            let mut selections_iter = selections.iter().peekable();
14426            while let Some(selection) = selections_iter.next() {
14427                if selection.start != selection.end {
14428                    only_carets = false;
14429                }
14430
14431                if same_text_selected {
14432                    if selected_text.is_none() {
14433                        selected_text =
14434                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14435                    }
14436
14437                    if let Some(next_selection) = selections_iter.peek() {
14438                        if next_selection.range().len() == selection.range().len() {
14439                            let next_selected_text = buffer
14440                                .text_for_range(next_selection.range())
14441                                .collect::<String>();
14442                            if Some(next_selected_text) != selected_text {
14443                                same_text_selected = false;
14444                                selected_text = None;
14445                            }
14446                        } else {
14447                            same_text_selected = false;
14448                            selected_text = None;
14449                        }
14450                    }
14451                }
14452            }
14453
14454            if only_carets {
14455                for selection in &mut selections {
14456                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14457                    selection.start = word_range.start;
14458                    selection.end = word_range.end;
14459                    selection.goal = SelectionGoal::None;
14460                    selection.reversed = false;
14461                    self.select_match_ranges(
14462                        selection.start..selection.end,
14463                        selection.reversed,
14464                        replace_newest,
14465                        autoscroll,
14466                        window,
14467                        cx,
14468                    );
14469                }
14470
14471                if selections.len() == 1 {
14472                    let selection = selections
14473                        .last()
14474                        .expect("ensured that there's only one selection");
14475                    let query = buffer
14476                        .text_for_range(selection.start..selection.end)
14477                        .collect::<String>();
14478                    let is_empty = query.is_empty();
14479                    let select_state = SelectNextState {
14480                        query: AhoCorasick::new(&[query])?,
14481                        wordwise: true,
14482                        done: is_empty,
14483                    };
14484                    self.select_next_state = Some(select_state);
14485                } else {
14486                    self.select_next_state = None;
14487                }
14488            } else if let Some(selected_text) = selected_text {
14489                self.select_next_state = Some(SelectNextState {
14490                    query: AhoCorasick::new(&[selected_text])?,
14491                    wordwise: false,
14492                    done: false,
14493                });
14494                self.select_next_match_internal(
14495                    display_map,
14496                    replace_newest,
14497                    autoscroll,
14498                    window,
14499                    cx,
14500                )?;
14501            }
14502        }
14503        Ok(())
14504    }
14505
14506    pub fn select_all_matches(
14507        &mut self,
14508        _action: &SelectAllMatches,
14509        window: &mut Window,
14510        cx: &mut Context<Self>,
14511    ) -> Result<()> {
14512        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14513
14514        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14515
14516        self.select_next_match_internal(&display_map, false, None, window, cx)?;
14517        let Some(select_next_state) = self.select_next_state.as_mut() else {
14518            return Ok(());
14519        };
14520        if select_next_state.done {
14521            return Ok(());
14522        }
14523
14524        let mut new_selections = Vec::new();
14525
14526        let reversed = self.selections.oldest::<usize>(&display_map).reversed;
14527        let buffer = display_map.buffer_snapshot();
14528        let query_matches = select_next_state
14529            .query
14530            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
14531
14532        for query_match in query_matches.into_iter() {
14533            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
14534            let offset_range = if reversed {
14535                query_match.end()..query_match.start()
14536            } else {
14537                query_match.start()..query_match.end()
14538            };
14539
14540            if !select_next_state.wordwise
14541                || (!buffer.is_inside_word(offset_range.start, None)
14542                    && !buffer.is_inside_word(offset_range.end, None))
14543            {
14544                new_selections.push(offset_range.start..offset_range.end);
14545            }
14546        }
14547
14548        select_next_state.done = true;
14549
14550        if new_selections.is_empty() {
14551            log::error!("bug: new_selections is empty in select_all_matches");
14552            return Ok(());
14553        }
14554
14555        self.unfold_ranges(&new_selections.clone(), false, false, cx);
14556        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
14557            selections.select_ranges(new_selections)
14558        });
14559
14560        Ok(())
14561    }
14562
14563    pub fn select_next(
14564        &mut self,
14565        action: &SelectNext,
14566        window: &mut Window,
14567        cx: &mut Context<Self>,
14568    ) -> Result<()> {
14569        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14570        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14571        self.select_next_match_internal(
14572            &display_map,
14573            action.replace_newest,
14574            Some(Autoscroll::newest()),
14575            window,
14576            cx,
14577        )?;
14578        Ok(())
14579    }
14580
14581    pub fn select_previous(
14582        &mut self,
14583        action: &SelectPrevious,
14584        window: &mut Window,
14585        cx: &mut Context<Self>,
14586    ) -> Result<()> {
14587        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14588        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14589        let buffer = display_map.buffer_snapshot();
14590        let mut selections = self.selections.all::<usize>(&display_map);
14591        if let Some(mut select_prev_state) = self.select_prev_state.take() {
14592            let query = &select_prev_state.query;
14593            if !select_prev_state.done {
14594                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14595                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14596                let mut next_selected_range = None;
14597                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
14598                let bytes_before_last_selection =
14599                    buffer.reversed_bytes_in_range(0..last_selection.start);
14600                let bytes_after_first_selection =
14601                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
14602                let query_matches = query
14603                    .stream_find_iter(bytes_before_last_selection)
14604                    .map(|result| (last_selection.start, result))
14605                    .chain(
14606                        query
14607                            .stream_find_iter(bytes_after_first_selection)
14608                            .map(|result| (buffer.len(), result)),
14609                    );
14610                for (end_offset, query_match) in query_matches {
14611                    let query_match = query_match.unwrap(); // can only fail due to I/O
14612                    let offset_range =
14613                        end_offset - query_match.end()..end_offset - query_match.start();
14614
14615                    if !select_prev_state.wordwise
14616                        || (!buffer.is_inside_word(offset_range.start, None)
14617                            && !buffer.is_inside_word(offset_range.end, None))
14618                    {
14619                        next_selected_range = Some(offset_range);
14620                        break;
14621                    }
14622                }
14623
14624                if let Some(next_selected_range) = next_selected_range {
14625                    self.select_match_ranges(
14626                        next_selected_range,
14627                        last_selection.reversed,
14628                        action.replace_newest,
14629                        Some(Autoscroll::newest()),
14630                        window,
14631                        cx,
14632                    );
14633                } else {
14634                    select_prev_state.done = true;
14635                }
14636            }
14637
14638            self.select_prev_state = Some(select_prev_state);
14639        } else {
14640            let mut only_carets = true;
14641            let mut same_text_selected = true;
14642            let mut selected_text = None;
14643
14644            let mut selections_iter = selections.iter().peekable();
14645            while let Some(selection) = selections_iter.next() {
14646                if selection.start != selection.end {
14647                    only_carets = false;
14648                }
14649
14650                if same_text_selected {
14651                    if selected_text.is_none() {
14652                        selected_text =
14653                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14654                    }
14655
14656                    if let Some(next_selection) = selections_iter.peek() {
14657                        if next_selection.range().len() == selection.range().len() {
14658                            let next_selected_text = buffer
14659                                .text_for_range(next_selection.range())
14660                                .collect::<String>();
14661                            if Some(next_selected_text) != selected_text {
14662                                same_text_selected = false;
14663                                selected_text = None;
14664                            }
14665                        } else {
14666                            same_text_selected = false;
14667                            selected_text = None;
14668                        }
14669                    }
14670                }
14671            }
14672
14673            if only_carets {
14674                for selection in &mut selections {
14675                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14676                    selection.start = word_range.start;
14677                    selection.end = word_range.end;
14678                    selection.goal = SelectionGoal::None;
14679                    selection.reversed = false;
14680                    self.select_match_ranges(
14681                        selection.start..selection.end,
14682                        selection.reversed,
14683                        action.replace_newest,
14684                        Some(Autoscroll::newest()),
14685                        window,
14686                        cx,
14687                    );
14688                }
14689                if selections.len() == 1 {
14690                    let selection = selections
14691                        .last()
14692                        .expect("ensured that there's only one selection");
14693                    let query = buffer
14694                        .text_for_range(selection.start..selection.end)
14695                        .collect::<String>();
14696                    let is_empty = query.is_empty();
14697                    let select_state = SelectNextState {
14698                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
14699                        wordwise: true,
14700                        done: is_empty,
14701                    };
14702                    self.select_prev_state = Some(select_state);
14703                } else {
14704                    self.select_prev_state = None;
14705                }
14706            } else if let Some(selected_text) = selected_text {
14707                self.select_prev_state = Some(SelectNextState {
14708                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
14709                    wordwise: false,
14710                    done: false,
14711                });
14712                self.select_previous(action, window, cx)?;
14713            }
14714        }
14715        Ok(())
14716    }
14717
14718    pub fn find_next_match(
14719        &mut self,
14720        _: &FindNextMatch,
14721        window: &mut Window,
14722        cx: &mut Context<Self>,
14723    ) -> Result<()> {
14724        let selections = self.selections.disjoint_anchors_arc();
14725        match selections.first() {
14726            Some(first) if selections.len() >= 2 => {
14727                self.change_selections(Default::default(), window, cx, |s| {
14728                    s.select_ranges([first.range()]);
14729                });
14730            }
14731            _ => self.select_next(
14732                &SelectNext {
14733                    replace_newest: true,
14734                },
14735                window,
14736                cx,
14737            )?,
14738        }
14739        Ok(())
14740    }
14741
14742    pub fn find_previous_match(
14743        &mut self,
14744        _: &FindPreviousMatch,
14745        window: &mut Window,
14746        cx: &mut Context<Self>,
14747    ) -> Result<()> {
14748        let selections = self.selections.disjoint_anchors_arc();
14749        match selections.last() {
14750            Some(last) if selections.len() >= 2 => {
14751                self.change_selections(Default::default(), window, cx, |s| {
14752                    s.select_ranges([last.range()]);
14753                });
14754            }
14755            _ => self.select_previous(
14756                &SelectPrevious {
14757                    replace_newest: true,
14758                },
14759                window,
14760                cx,
14761            )?,
14762        }
14763        Ok(())
14764    }
14765
14766    pub fn toggle_comments(
14767        &mut self,
14768        action: &ToggleComments,
14769        window: &mut Window,
14770        cx: &mut Context<Self>,
14771    ) {
14772        if self.read_only(cx) {
14773            return;
14774        }
14775        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14776        let text_layout_details = &self.text_layout_details(window);
14777        self.transact(window, cx, |this, window, cx| {
14778            let mut selections = this
14779                .selections
14780                .all::<MultiBufferPoint>(&this.display_snapshot(cx));
14781            let mut edits = Vec::new();
14782            let mut selection_edit_ranges = Vec::new();
14783            let mut last_toggled_row = None;
14784            let snapshot = this.buffer.read(cx).read(cx);
14785            let empty_str: Arc<str> = Arc::default();
14786            let mut suffixes_inserted = Vec::new();
14787            let ignore_indent = action.ignore_indent;
14788
14789            fn comment_prefix_range(
14790                snapshot: &MultiBufferSnapshot,
14791                row: MultiBufferRow,
14792                comment_prefix: &str,
14793                comment_prefix_whitespace: &str,
14794                ignore_indent: bool,
14795            ) -> Range<Point> {
14796                let indent_size = if ignore_indent {
14797                    0
14798                } else {
14799                    snapshot.indent_size_for_line(row).len
14800                };
14801
14802                let start = Point::new(row.0, indent_size);
14803
14804                let mut line_bytes = snapshot
14805                    .bytes_in_range(start..snapshot.max_point())
14806                    .flatten()
14807                    .copied();
14808
14809                // If this line currently begins with the line comment prefix, then record
14810                // the range containing the prefix.
14811                if line_bytes
14812                    .by_ref()
14813                    .take(comment_prefix.len())
14814                    .eq(comment_prefix.bytes())
14815                {
14816                    // Include any whitespace that matches the comment prefix.
14817                    let matching_whitespace_len = line_bytes
14818                        .zip(comment_prefix_whitespace.bytes())
14819                        .take_while(|(a, b)| a == b)
14820                        .count() as u32;
14821                    let end = Point::new(
14822                        start.row,
14823                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
14824                    );
14825                    start..end
14826                } else {
14827                    start..start
14828                }
14829            }
14830
14831            fn comment_suffix_range(
14832                snapshot: &MultiBufferSnapshot,
14833                row: MultiBufferRow,
14834                comment_suffix: &str,
14835                comment_suffix_has_leading_space: bool,
14836            ) -> Range<Point> {
14837                let end = Point::new(row.0, snapshot.line_len(row));
14838                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
14839
14840                let mut line_end_bytes = snapshot
14841                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
14842                    .flatten()
14843                    .copied();
14844
14845                let leading_space_len = if suffix_start_column > 0
14846                    && line_end_bytes.next() == Some(b' ')
14847                    && comment_suffix_has_leading_space
14848                {
14849                    1
14850                } else {
14851                    0
14852                };
14853
14854                // If this line currently begins with the line comment prefix, then record
14855                // the range containing the prefix.
14856                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
14857                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
14858                    start..end
14859                } else {
14860                    end..end
14861                }
14862            }
14863
14864            // TODO: Handle selections that cross excerpts
14865            for selection in &mut selections {
14866                let start_column = snapshot
14867                    .indent_size_for_line(MultiBufferRow(selection.start.row))
14868                    .len;
14869                let language = if let Some(language) =
14870                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
14871                {
14872                    language
14873                } else {
14874                    continue;
14875                };
14876
14877                selection_edit_ranges.clear();
14878
14879                // If multiple selections contain a given row, avoid processing that
14880                // row more than once.
14881                let mut start_row = MultiBufferRow(selection.start.row);
14882                if last_toggled_row == Some(start_row) {
14883                    start_row = start_row.next_row();
14884                }
14885                let end_row =
14886                    if selection.end.row > selection.start.row && selection.end.column == 0 {
14887                        MultiBufferRow(selection.end.row - 1)
14888                    } else {
14889                        MultiBufferRow(selection.end.row)
14890                    };
14891                last_toggled_row = Some(end_row);
14892
14893                if start_row > end_row {
14894                    continue;
14895                }
14896
14897                // If the language has line comments, toggle those.
14898                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
14899
14900                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
14901                if ignore_indent {
14902                    full_comment_prefixes = full_comment_prefixes
14903                        .into_iter()
14904                        .map(|s| Arc::from(s.trim_end()))
14905                        .collect();
14906                }
14907
14908                if !full_comment_prefixes.is_empty() {
14909                    let first_prefix = full_comment_prefixes
14910                        .first()
14911                        .expect("prefixes is non-empty");
14912                    let prefix_trimmed_lengths = full_comment_prefixes
14913                        .iter()
14914                        .map(|p| p.trim_end_matches(' ').len())
14915                        .collect::<SmallVec<[usize; 4]>>();
14916
14917                    let mut all_selection_lines_are_comments = true;
14918
14919                    for row in start_row.0..=end_row.0 {
14920                        let row = MultiBufferRow(row);
14921                        if start_row < end_row && snapshot.is_line_blank(row) {
14922                            continue;
14923                        }
14924
14925                        let prefix_range = full_comment_prefixes
14926                            .iter()
14927                            .zip(prefix_trimmed_lengths.iter().copied())
14928                            .map(|(prefix, trimmed_prefix_len)| {
14929                                comment_prefix_range(
14930                                    snapshot.deref(),
14931                                    row,
14932                                    &prefix[..trimmed_prefix_len],
14933                                    &prefix[trimmed_prefix_len..],
14934                                    ignore_indent,
14935                                )
14936                            })
14937                            .max_by_key(|range| range.end.column - range.start.column)
14938                            .expect("prefixes is non-empty");
14939
14940                        if prefix_range.is_empty() {
14941                            all_selection_lines_are_comments = false;
14942                        }
14943
14944                        selection_edit_ranges.push(prefix_range);
14945                    }
14946
14947                    if all_selection_lines_are_comments {
14948                        edits.extend(
14949                            selection_edit_ranges
14950                                .iter()
14951                                .cloned()
14952                                .map(|range| (range, empty_str.clone())),
14953                        );
14954                    } else {
14955                        let min_column = selection_edit_ranges
14956                            .iter()
14957                            .map(|range| range.start.column)
14958                            .min()
14959                            .unwrap_or(0);
14960                        edits.extend(selection_edit_ranges.iter().map(|range| {
14961                            let position = Point::new(range.start.row, min_column);
14962                            (position..position, first_prefix.clone())
14963                        }));
14964                    }
14965                } else if let Some(BlockCommentConfig {
14966                    start: full_comment_prefix,
14967                    end: comment_suffix,
14968                    ..
14969                }) = language.block_comment()
14970                {
14971                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
14972                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
14973                    let prefix_range = comment_prefix_range(
14974                        snapshot.deref(),
14975                        start_row,
14976                        comment_prefix,
14977                        comment_prefix_whitespace,
14978                        ignore_indent,
14979                    );
14980                    let suffix_range = comment_suffix_range(
14981                        snapshot.deref(),
14982                        end_row,
14983                        comment_suffix.trim_start_matches(' '),
14984                        comment_suffix.starts_with(' '),
14985                    );
14986
14987                    if prefix_range.is_empty() || suffix_range.is_empty() {
14988                        edits.push((
14989                            prefix_range.start..prefix_range.start,
14990                            full_comment_prefix.clone(),
14991                        ));
14992                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
14993                        suffixes_inserted.push((end_row, comment_suffix.len()));
14994                    } else {
14995                        edits.push((prefix_range, empty_str.clone()));
14996                        edits.push((suffix_range, empty_str.clone()));
14997                    }
14998                } else {
14999                    continue;
15000                }
15001            }
15002
15003            drop(snapshot);
15004            this.buffer.update(cx, |buffer, cx| {
15005                buffer.edit(edits, None, cx);
15006            });
15007
15008            // Adjust selections so that they end before any comment suffixes that
15009            // were inserted.
15010            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
15011            let mut selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15012            let snapshot = this.buffer.read(cx).read(cx);
15013            for selection in &mut selections {
15014                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
15015                    match row.cmp(&MultiBufferRow(selection.end.row)) {
15016                        Ordering::Less => {
15017                            suffixes_inserted.next();
15018                            continue;
15019                        }
15020                        Ordering::Greater => break,
15021                        Ordering::Equal => {
15022                            if selection.end.column == snapshot.line_len(row) {
15023                                if selection.is_empty() {
15024                                    selection.start.column -= suffix_len as u32;
15025                                }
15026                                selection.end.column -= suffix_len as u32;
15027                            }
15028                            break;
15029                        }
15030                    }
15031                }
15032            }
15033
15034            drop(snapshot);
15035            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
15036
15037            let selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15038            let selections_on_single_row = selections.windows(2).all(|selections| {
15039                selections[0].start.row == selections[1].start.row
15040                    && selections[0].end.row == selections[1].end.row
15041                    && selections[0].start.row == selections[0].end.row
15042            });
15043            let selections_selecting = selections
15044                .iter()
15045                .any(|selection| selection.start != selection.end);
15046            let advance_downwards = action.advance_downwards
15047                && selections_on_single_row
15048                && !selections_selecting
15049                && !matches!(this.mode, EditorMode::SingleLine);
15050
15051            if advance_downwards {
15052                let snapshot = this.buffer.read(cx).snapshot(cx);
15053
15054                this.change_selections(Default::default(), window, cx, |s| {
15055                    s.move_cursors_with(|display_snapshot, display_point, _| {
15056                        let mut point = display_point.to_point(display_snapshot);
15057                        point.row += 1;
15058                        point = snapshot.clip_point(point, Bias::Left);
15059                        let display_point = point.to_display_point(display_snapshot);
15060                        let goal = SelectionGoal::HorizontalPosition(
15061                            display_snapshot
15062                                .x_for_display_point(display_point, text_layout_details)
15063                                .into(),
15064                        );
15065                        (display_point, goal)
15066                    })
15067                });
15068            }
15069        });
15070    }
15071
15072    pub fn select_enclosing_symbol(
15073        &mut self,
15074        _: &SelectEnclosingSymbol,
15075        window: &mut Window,
15076        cx: &mut Context<Self>,
15077    ) {
15078        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15079
15080        let buffer = self.buffer.read(cx).snapshot(cx);
15081        let old_selections = self
15082            .selections
15083            .all::<usize>(&self.display_snapshot(cx))
15084            .into_boxed_slice();
15085
15086        fn update_selection(
15087            selection: &Selection<usize>,
15088            buffer_snap: &MultiBufferSnapshot,
15089        ) -> Option<Selection<usize>> {
15090            let cursor = selection.head();
15091            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
15092            for symbol in symbols.iter().rev() {
15093                let start = symbol.range.start.to_offset(buffer_snap);
15094                let end = symbol.range.end.to_offset(buffer_snap);
15095                let new_range = start..end;
15096                if start < selection.start || end > selection.end {
15097                    return Some(Selection {
15098                        id: selection.id,
15099                        start: new_range.start,
15100                        end: new_range.end,
15101                        goal: SelectionGoal::None,
15102                        reversed: selection.reversed,
15103                    });
15104                }
15105            }
15106            None
15107        }
15108
15109        let mut selected_larger_symbol = false;
15110        let new_selections = old_selections
15111            .iter()
15112            .map(|selection| match update_selection(selection, &buffer) {
15113                Some(new_selection) => {
15114                    if new_selection.range() != selection.range() {
15115                        selected_larger_symbol = true;
15116                    }
15117                    new_selection
15118                }
15119                None => selection.clone(),
15120            })
15121            .collect::<Vec<_>>();
15122
15123        if selected_larger_symbol {
15124            self.change_selections(Default::default(), window, cx, |s| {
15125                s.select(new_selections);
15126            });
15127        }
15128    }
15129
15130    pub fn select_larger_syntax_node(
15131        &mut self,
15132        _: &SelectLargerSyntaxNode,
15133        window: &mut Window,
15134        cx: &mut Context<Self>,
15135    ) {
15136        let Some(visible_row_count) = self.visible_row_count() else {
15137            return;
15138        };
15139        let old_selections: Box<[_]> = self
15140            .selections
15141            .all::<usize>(&self.display_snapshot(cx))
15142            .into();
15143        if old_selections.is_empty() {
15144            return;
15145        }
15146
15147        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15148
15149        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15150        let buffer = self.buffer.read(cx).snapshot(cx);
15151
15152        let mut selected_larger_node = false;
15153        let mut new_selections = old_selections
15154            .iter()
15155            .map(|selection| {
15156                let old_range = selection.start..selection.end;
15157
15158                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
15159                    // manually select word at selection
15160                    if ["string_content", "inline"].contains(&node.kind()) {
15161                        let (word_range, _) = buffer.surrounding_word(old_range.start, None);
15162                        // ignore if word is already selected
15163                        if !word_range.is_empty() && old_range != word_range {
15164                            let (last_word_range, _) = buffer.surrounding_word(old_range.end, None);
15165                            // only select word if start and end point belongs to same word
15166                            if word_range == last_word_range {
15167                                selected_larger_node = true;
15168                                return Selection {
15169                                    id: selection.id,
15170                                    start: word_range.start,
15171                                    end: word_range.end,
15172                                    goal: SelectionGoal::None,
15173                                    reversed: selection.reversed,
15174                                };
15175                            }
15176                        }
15177                    }
15178                }
15179
15180                let mut new_range = old_range.clone();
15181                while let Some((node, range)) = buffer.syntax_ancestor(new_range.clone()) {
15182                    new_range = range;
15183                    if !node.is_named() {
15184                        continue;
15185                    }
15186                    if !display_map.intersects_fold(new_range.start)
15187                        && !display_map.intersects_fold(new_range.end)
15188                    {
15189                        break;
15190                    }
15191                }
15192
15193                selected_larger_node |= new_range != old_range;
15194                Selection {
15195                    id: selection.id,
15196                    start: new_range.start,
15197                    end: new_range.end,
15198                    goal: SelectionGoal::None,
15199                    reversed: selection.reversed,
15200                }
15201            })
15202            .collect::<Vec<_>>();
15203
15204        if !selected_larger_node {
15205            return; // don't put this call in the history
15206        }
15207
15208        // scroll based on transformation done to the last selection created by the user
15209        let (last_old, last_new) = old_selections
15210            .last()
15211            .zip(new_selections.last().cloned())
15212            .expect("old_selections isn't empty");
15213
15214        // revert selection
15215        let is_selection_reversed = {
15216            let should_newest_selection_be_reversed = last_old.start != last_new.start;
15217            new_selections.last_mut().expect("checked above").reversed =
15218                should_newest_selection_be_reversed;
15219            should_newest_selection_be_reversed
15220        };
15221
15222        if selected_larger_node {
15223            self.select_syntax_node_history.disable_clearing = true;
15224            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15225                s.select(new_selections.clone());
15226            });
15227            self.select_syntax_node_history.disable_clearing = false;
15228        }
15229
15230        let start_row = last_new.start.to_display_point(&display_map).row().0;
15231        let end_row = last_new.end.to_display_point(&display_map).row().0;
15232        let selection_height = end_row - start_row + 1;
15233        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
15234
15235        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
15236        let scroll_behavior = if fits_on_the_screen {
15237            self.request_autoscroll(Autoscroll::fit(), cx);
15238            SelectSyntaxNodeScrollBehavior::FitSelection
15239        } else if is_selection_reversed {
15240            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15241            SelectSyntaxNodeScrollBehavior::CursorTop
15242        } else {
15243            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15244            SelectSyntaxNodeScrollBehavior::CursorBottom
15245        };
15246
15247        self.select_syntax_node_history.push((
15248            old_selections,
15249            scroll_behavior,
15250            is_selection_reversed,
15251        ));
15252    }
15253
15254    pub fn select_smaller_syntax_node(
15255        &mut self,
15256        _: &SelectSmallerSyntaxNode,
15257        window: &mut Window,
15258        cx: &mut Context<Self>,
15259    ) {
15260        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15261
15262        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
15263            self.select_syntax_node_history.pop()
15264        {
15265            if let Some(selection) = selections.last_mut() {
15266                selection.reversed = is_selection_reversed;
15267            }
15268
15269            self.select_syntax_node_history.disable_clearing = true;
15270            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15271                s.select(selections.to_vec());
15272            });
15273            self.select_syntax_node_history.disable_clearing = false;
15274
15275            match scroll_behavior {
15276                SelectSyntaxNodeScrollBehavior::CursorTop => {
15277                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15278                }
15279                SelectSyntaxNodeScrollBehavior::FitSelection => {
15280                    self.request_autoscroll(Autoscroll::fit(), cx);
15281                }
15282                SelectSyntaxNodeScrollBehavior::CursorBottom => {
15283                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15284                }
15285            }
15286        }
15287    }
15288
15289    pub fn unwrap_syntax_node(
15290        &mut self,
15291        _: &UnwrapSyntaxNode,
15292        window: &mut Window,
15293        cx: &mut Context<Self>,
15294    ) {
15295        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15296
15297        let buffer = self.buffer.read(cx).snapshot(cx);
15298        let selections = self
15299            .selections
15300            .all::<usize>(&self.display_snapshot(cx))
15301            .into_iter()
15302            // subtracting the offset requires sorting
15303            .sorted_by_key(|i| i.start);
15304
15305        let full_edits = selections
15306            .into_iter()
15307            .filter_map(|selection| {
15308                let child = if selection.is_empty()
15309                    && let Some((_, ancestor_range)) =
15310                        buffer.syntax_ancestor(selection.start..selection.end)
15311                {
15312                    ancestor_range
15313                } else {
15314                    selection.range()
15315                };
15316
15317                let mut parent = child.clone();
15318                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
15319                    parent = ancestor_range;
15320                    if parent.start < child.start || parent.end > child.end {
15321                        break;
15322                    }
15323                }
15324
15325                if parent == child {
15326                    return None;
15327                }
15328                let text = buffer.text_for_range(child).collect::<String>();
15329                Some((selection.id, parent, text))
15330            })
15331            .collect::<Vec<_>>();
15332        if full_edits.is_empty() {
15333            return;
15334        }
15335
15336        self.transact(window, cx, |this, window, cx| {
15337            this.buffer.update(cx, |buffer, cx| {
15338                buffer.edit(
15339                    full_edits
15340                        .iter()
15341                        .map(|(_, p, t)| (p.clone(), t.clone()))
15342                        .collect::<Vec<_>>(),
15343                    None,
15344                    cx,
15345                );
15346            });
15347            this.change_selections(Default::default(), window, cx, |s| {
15348                let mut offset = 0;
15349                let mut selections = vec![];
15350                for (id, parent, text) in full_edits {
15351                    let start = parent.start - offset;
15352                    offset += parent.len() - text.len();
15353                    selections.push(Selection {
15354                        id,
15355                        start,
15356                        end: start + text.len(),
15357                        reversed: false,
15358                        goal: Default::default(),
15359                    });
15360                }
15361                s.select(selections);
15362            });
15363        });
15364    }
15365
15366    pub fn select_next_syntax_node(
15367        &mut self,
15368        _: &SelectNextSyntaxNode,
15369        window: &mut Window,
15370        cx: &mut Context<Self>,
15371    ) {
15372        let old_selections: Box<[_]> = self
15373            .selections
15374            .all::<usize>(&self.display_snapshot(cx))
15375            .into();
15376        if old_selections.is_empty() {
15377            return;
15378        }
15379
15380        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15381
15382        let buffer = self.buffer.read(cx).snapshot(cx);
15383        let mut selected_sibling = false;
15384
15385        let new_selections = old_selections
15386            .iter()
15387            .map(|selection| {
15388                let old_range = selection.start..selection.end;
15389
15390                if let Some(node) = buffer.syntax_next_sibling(old_range) {
15391                    let new_range = node.byte_range();
15392                    selected_sibling = true;
15393                    Selection {
15394                        id: selection.id,
15395                        start: new_range.start,
15396                        end: new_range.end,
15397                        goal: SelectionGoal::None,
15398                        reversed: selection.reversed,
15399                    }
15400                } else {
15401                    selection.clone()
15402                }
15403            })
15404            .collect::<Vec<_>>();
15405
15406        if selected_sibling {
15407            self.change_selections(
15408                SelectionEffects::scroll(Autoscroll::fit()),
15409                window,
15410                cx,
15411                |s| {
15412                    s.select(new_selections);
15413                },
15414            );
15415        }
15416    }
15417
15418    pub fn select_prev_syntax_node(
15419        &mut self,
15420        _: &SelectPreviousSyntaxNode,
15421        window: &mut Window,
15422        cx: &mut Context<Self>,
15423    ) {
15424        let old_selections: Box<[_]> = self
15425            .selections
15426            .all::<usize>(&self.display_snapshot(cx))
15427            .into();
15428        if old_selections.is_empty() {
15429            return;
15430        }
15431
15432        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15433
15434        let buffer = self.buffer.read(cx).snapshot(cx);
15435        let mut selected_sibling = false;
15436
15437        let new_selections = old_selections
15438            .iter()
15439            .map(|selection| {
15440                let old_range = selection.start..selection.end;
15441
15442                if let Some(node) = buffer.syntax_prev_sibling(old_range) {
15443                    let new_range = node.byte_range();
15444                    selected_sibling = true;
15445                    Selection {
15446                        id: selection.id,
15447                        start: new_range.start,
15448                        end: new_range.end,
15449                        goal: SelectionGoal::None,
15450                        reversed: selection.reversed,
15451                    }
15452                } else {
15453                    selection.clone()
15454                }
15455            })
15456            .collect::<Vec<_>>();
15457
15458        if selected_sibling {
15459            self.change_selections(
15460                SelectionEffects::scroll(Autoscroll::fit()),
15461                window,
15462                cx,
15463                |s| {
15464                    s.select(new_selections);
15465                },
15466            );
15467        }
15468    }
15469
15470    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
15471        if !EditorSettings::get_global(cx).gutter.runnables {
15472            self.clear_tasks();
15473            return Task::ready(());
15474        }
15475        let project = self.project().map(Entity::downgrade);
15476        let task_sources = self.lsp_task_sources(cx);
15477        let multi_buffer = self.buffer.downgrade();
15478        cx.spawn_in(window, async move |editor, cx| {
15479            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
15480            let Some(project) = project.and_then(|p| p.upgrade()) else {
15481                return;
15482            };
15483            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
15484                this.display_map.update(cx, |map, cx| map.snapshot(cx))
15485            }) else {
15486                return;
15487            };
15488
15489            let hide_runnables = project
15490                .update(cx, |project, _| project.is_via_collab())
15491                .unwrap_or(true);
15492            if hide_runnables {
15493                return;
15494            }
15495            let new_rows =
15496                cx.background_spawn({
15497                    let snapshot = display_snapshot.clone();
15498                    async move {
15499                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
15500                    }
15501                })
15502                    .await;
15503            let Ok(lsp_tasks) =
15504                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
15505            else {
15506                return;
15507            };
15508            let lsp_tasks = lsp_tasks.await;
15509
15510            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
15511                lsp_tasks
15512                    .into_iter()
15513                    .flat_map(|(kind, tasks)| {
15514                        tasks.into_iter().filter_map(move |(location, task)| {
15515                            Some((kind.clone(), location?, task))
15516                        })
15517                    })
15518                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
15519                        let buffer = location.target.buffer;
15520                        let buffer_snapshot = buffer.read(cx).snapshot();
15521                        let offset = display_snapshot.buffer_snapshot().excerpts().find_map(
15522                            |(excerpt_id, snapshot, _)| {
15523                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
15524                                    display_snapshot
15525                                        .buffer_snapshot()
15526                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
15527                                } else {
15528                                    None
15529                                }
15530                            },
15531                        );
15532                        if let Some(offset) = offset {
15533                            let task_buffer_range =
15534                                location.target.range.to_point(&buffer_snapshot);
15535                            let context_buffer_range =
15536                                task_buffer_range.to_offset(&buffer_snapshot);
15537                            let context_range = BufferOffset(context_buffer_range.start)
15538                                ..BufferOffset(context_buffer_range.end);
15539
15540                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
15541                                .or_insert_with(|| RunnableTasks {
15542                                    templates: Vec::new(),
15543                                    offset,
15544                                    column: task_buffer_range.start.column,
15545                                    extra_variables: HashMap::default(),
15546                                    context_range,
15547                                })
15548                                .templates
15549                                .push((kind, task.original_task().clone()));
15550                        }
15551
15552                        acc
15553                    })
15554            }) else {
15555                return;
15556            };
15557
15558            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
15559                buffer.language_settings(cx).tasks.prefer_lsp
15560            }) else {
15561                return;
15562            };
15563
15564            let rows = Self::runnable_rows(
15565                project,
15566                display_snapshot,
15567                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
15568                new_rows,
15569                cx.clone(),
15570            )
15571            .await;
15572            editor
15573                .update(cx, |editor, _| {
15574                    editor.clear_tasks();
15575                    for (key, mut value) in rows {
15576                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
15577                            value.templates.extend(lsp_tasks.templates);
15578                        }
15579
15580                        editor.insert_tasks(key, value);
15581                    }
15582                    for (key, value) in lsp_tasks_by_rows {
15583                        editor.insert_tasks(key, value);
15584                    }
15585                })
15586                .ok();
15587        })
15588    }
15589    fn fetch_runnable_ranges(
15590        snapshot: &DisplaySnapshot,
15591        range: Range<Anchor>,
15592    ) -> Vec<language::RunnableRange> {
15593        snapshot.buffer_snapshot().runnable_ranges(range).collect()
15594    }
15595
15596    fn runnable_rows(
15597        project: Entity<Project>,
15598        snapshot: DisplaySnapshot,
15599        prefer_lsp: bool,
15600        runnable_ranges: Vec<RunnableRange>,
15601        cx: AsyncWindowContext,
15602    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
15603        cx.spawn(async move |cx| {
15604            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
15605            for mut runnable in runnable_ranges {
15606                let Some(tasks) = cx
15607                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
15608                    .ok()
15609                else {
15610                    continue;
15611                };
15612                let mut tasks = tasks.await;
15613
15614                if prefer_lsp {
15615                    tasks.retain(|(task_kind, _)| {
15616                        !matches!(task_kind, TaskSourceKind::Language { .. })
15617                    });
15618                }
15619                if tasks.is_empty() {
15620                    continue;
15621                }
15622
15623                let point = runnable
15624                    .run_range
15625                    .start
15626                    .to_point(&snapshot.buffer_snapshot());
15627                let Some(row) = snapshot
15628                    .buffer_snapshot()
15629                    .buffer_line_for_row(MultiBufferRow(point.row))
15630                    .map(|(_, range)| range.start.row)
15631                else {
15632                    continue;
15633                };
15634
15635                let context_range =
15636                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
15637                runnable_rows.push((
15638                    (runnable.buffer_id, row),
15639                    RunnableTasks {
15640                        templates: tasks,
15641                        offset: snapshot
15642                            .buffer_snapshot()
15643                            .anchor_before(runnable.run_range.start),
15644                        context_range,
15645                        column: point.column,
15646                        extra_variables: runnable.extra_captures,
15647                    },
15648                ));
15649            }
15650            runnable_rows
15651        })
15652    }
15653
15654    fn templates_with_tags(
15655        project: &Entity<Project>,
15656        runnable: &mut Runnable,
15657        cx: &mut App,
15658    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
15659        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
15660            let (worktree_id, file) = project
15661                .buffer_for_id(runnable.buffer, cx)
15662                .and_then(|buffer| buffer.read(cx).file())
15663                .map(|file| (file.worktree_id(cx), file.clone()))
15664                .unzip();
15665
15666            (
15667                project.task_store().read(cx).task_inventory().cloned(),
15668                worktree_id,
15669                file,
15670            )
15671        });
15672
15673        let tags = mem::take(&mut runnable.tags);
15674        let language = runnable.language.clone();
15675        cx.spawn(async move |cx| {
15676            let mut templates_with_tags = Vec::new();
15677            if let Some(inventory) = inventory {
15678                for RunnableTag(tag) in tags {
15679                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
15680                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
15681                    }) else {
15682                        return templates_with_tags;
15683                    };
15684                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
15685                        move |(_, template)| {
15686                            template.tags.iter().any(|source_tag| source_tag == &tag)
15687                        },
15688                    ));
15689                }
15690            }
15691            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
15692
15693            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
15694                // Strongest source wins; if we have worktree tag binding, prefer that to
15695                // global and language bindings;
15696                // if we have a global binding, prefer that to language binding.
15697                let first_mismatch = templates_with_tags
15698                    .iter()
15699                    .position(|(tag_source, _)| tag_source != leading_tag_source);
15700                if let Some(index) = first_mismatch {
15701                    templates_with_tags.truncate(index);
15702                }
15703            }
15704
15705            templates_with_tags
15706        })
15707    }
15708
15709    pub fn move_to_enclosing_bracket(
15710        &mut self,
15711        _: &MoveToEnclosingBracket,
15712        window: &mut Window,
15713        cx: &mut Context<Self>,
15714    ) {
15715        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15716        self.change_selections(Default::default(), window, cx, |s| {
15717            s.move_offsets_with(|snapshot, selection| {
15718                let Some(enclosing_bracket_ranges) =
15719                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
15720                else {
15721                    return;
15722                };
15723
15724                let mut best_length = usize::MAX;
15725                let mut best_inside = false;
15726                let mut best_in_bracket_range = false;
15727                let mut best_destination = None;
15728                for (open, close) in enclosing_bracket_ranges {
15729                    let close = close.to_inclusive();
15730                    let length = close.end() - open.start;
15731                    let inside = selection.start >= open.end && selection.end <= *close.start();
15732                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
15733                        || close.contains(&selection.head());
15734
15735                    // If best is next to a bracket and current isn't, skip
15736                    if !in_bracket_range && best_in_bracket_range {
15737                        continue;
15738                    }
15739
15740                    // Prefer smaller lengths unless best is inside and current isn't
15741                    if length > best_length && (best_inside || !inside) {
15742                        continue;
15743                    }
15744
15745                    best_length = length;
15746                    best_inside = inside;
15747                    best_in_bracket_range = in_bracket_range;
15748                    best_destination = Some(
15749                        if close.contains(&selection.start) && close.contains(&selection.end) {
15750                            if inside { open.end } else { open.start }
15751                        } else if inside {
15752                            *close.start()
15753                        } else {
15754                            *close.end()
15755                        },
15756                    );
15757                }
15758
15759                if let Some(destination) = best_destination {
15760                    selection.collapse_to(destination, SelectionGoal::None);
15761                }
15762            })
15763        });
15764    }
15765
15766    pub fn undo_selection(
15767        &mut self,
15768        _: &UndoSelection,
15769        window: &mut Window,
15770        cx: &mut Context<Self>,
15771    ) {
15772        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15773        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
15774            self.selection_history.mode = SelectionHistoryMode::Undoing;
15775            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15776                this.end_selection(window, cx);
15777                this.change_selections(
15778                    SelectionEffects::scroll(Autoscroll::newest()),
15779                    window,
15780                    cx,
15781                    |s| s.select_anchors(entry.selections.to_vec()),
15782                );
15783            });
15784            self.selection_history.mode = SelectionHistoryMode::Normal;
15785
15786            self.select_next_state = entry.select_next_state;
15787            self.select_prev_state = entry.select_prev_state;
15788            self.add_selections_state = entry.add_selections_state;
15789        }
15790    }
15791
15792    pub fn redo_selection(
15793        &mut self,
15794        _: &RedoSelection,
15795        window: &mut Window,
15796        cx: &mut Context<Self>,
15797    ) {
15798        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15799        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
15800            self.selection_history.mode = SelectionHistoryMode::Redoing;
15801            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15802                this.end_selection(window, cx);
15803                this.change_selections(
15804                    SelectionEffects::scroll(Autoscroll::newest()),
15805                    window,
15806                    cx,
15807                    |s| s.select_anchors(entry.selections.to_vec()),
15808                );
15809            });
15810            self.selection_history.mode = SelectionHistoryMode::Normal;
15811
15812            self.select_next_state = entry.select_next_state;
15813            self.select_prev_state = entry.select_prev_state;
15814            self.add_selections_state = entry.add_selections_state;
15815        }
15816    }
15817
15818    pub fn expand_excerpts(
15819        &mut self,
15820        action: &ExpandExcerpts,
15821        _: &mut Window,
15822        cx: &mut Context<Self>,
15823    ) {
15824        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
15825    }
15826
15827    pub fn expand_excerpts_down(
15828        &mut self,
15829        action: &ExpandExcerptsDown,
15830        _: &mut Window,
15831        cx: &mut Context<Self>,
15832    ) {
15833        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
15834    }
15835
15836    pub fn expand_excerpts_up(
15837        &mut self,
15838        action: &ExpandExcerptsUp,
15839        _: &mut Window,
15840        cx: &mut Context<Self>,
15841    ) {
15842        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
15843    }
15844
15845    pub fn expand_excerpts_for_direction(
15846        &mut self,
15847        lines: u32,
15848        direction: ExpandExcerptDirection,
15849
15850        cx: &mut Context<Self>,
15851    ) {
15852        let selections = self.selections.disjoint_anchors_arc();
15853
15854        let lines = if lines == 0 {
15855            EditorSettings::get_global(cx).expand_excerpt_lines
15856        } else {
15857            lines
15858        };
15859
15860        self.buffer.update(cx, |buffer, cx| {
15861            let snapshot = buffer.snapshot(cx);
15862            let mut excerpt_ids = selections
15863                .iter()
15864                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
15865                .collect::<Vec<_>>();
15866            excerpt_ids.sort();
15867            excerpt_ids.dedup();
15868            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
15869        })
15870    }
15871
15872    pub fn expand_excerpt(
15873        &mut self,
15874        excerpt: ExcerptId,
15875        direction: ExpandExcerptDirection,
15876        window: &mut Window,
15877        cx: &mut Context<Self>,
15878    ) {
15879        let current_scroll_position = self.scroll_position(cx);
15880        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
15881        let mut scroll = None;
15882
15883        if direction == ExpandExcerptDirection::Down {
15884            let multi_buffer = self.buffer.read(cx);
15885            let snapshot = multi_buffer.snapshot(cx);
15886            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
15887                && let Some(buffer) = multi_buffer.buffer(buffer_id)
15888                && let Some(excerpt_range) = snapshot.context_range_for_excerpt(excerpt)
15889            {
15890                let buffer_snapshot = buffer.read(cx).snapshot();
15891                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
15892                let last_row = buffer_snapshot.max_point().row;
15893                let lines_below = last_row.saturating_sub(excerpt_end_row);
15894                if lines_below >= lines_to_expand {
15895                    scroll = Some(
15896                        current_scroll_position
15897                            + gpui::Point::new(0.0, lines_to_expand as ScrollOffset),
15898                    );
15899                }
15900            }
15901        }
15902        if direction == ExpandExcerptDirection::Up
15903            && self
15904                .buffer
15905                .read(cx)
15906                .snapshot(cx)
15907                .excerpt_before(excerpt)
15908                .is_none()
15909        {
15910            scroll = Some(current_scroll_position);
15911        }
15912
15913        self.buffer.update(cx, |buffer, cx| {
15914            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
15915        });
15916
15917        if let Some(new_scroll_position) = scroll {
15918            self.set_scroll_position(new_scroll_position, window, cx);
15919        }
15920    }
15921
15922    pub fn go_to_singleton_buffer_point(
15923        &mut self,
15924        point: Point,
15925        window: &mut Window,
15926        cx: &mut Context<Self>,
15927    ) {
15928        self.go_to_singleton_buffer_range(point..point, window, cx);
15929    }
15930
15931    pub fn go_to_singleton_buffer_range(
15932        &mut self,
15933        range: Range<Point>,
15934        window: &mut Window,
15935        cx: &mut Context<Self>,
15936    ) {
15937        let multibuffer = self.buffer().read(cx);
15938        let Some(buffer) = multibuffer.as_singleton() else {
15939            return;
15940        };
15941        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
15942            return;
15943        };
15944        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
15945            return;
15946        };
15947        self.change_selections(
15948            SelectionEffects::default().nav_history(true),
15949            window,
15950            cx,
15951            |s| s.select_anchor_ranges([start..end]),
15952        );
15953    }
15954
15955    pub fn go_to_diagnostic(
15956        &mut self,
15957        action: &GoToDiagnostic,
15958        window: &mut Window,
15959        cx: &mut Context<Self>,
15960    ) {
15961        if !self.diagnostics_enabled() {
15962            return;
15963        }
15964        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15965        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
15966    }
15967
15968    pub fn go_to_prev_diagnostic(
15969        &mut self,
15970        action: &GoToPreviousDiagnostic,
15971        window: &mut Window,
15972        cx: &mut Context<Self>,
15973    ) {
15974        if !self.diagnostics_enabled() {
15975            return;
15976        }
15977        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15978        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
15979    }
15980
15981    pub fn go_to_diagnostic_impl(
15982        &mut self,
15983        direction: Direction,
15984        severity: GoToDiagnosticSeverityFilter,
15985        window: &mut Window,
15986        cx: &mut Context<Self>,
15987    ) {
15988        let buffer = self.buffer.read(cx).snapshot(cx);
15989        let selection = self.selections.newest::<usize>(&self.display_snapshot(cx));
15990
15991        let mut active_group_id = None;
15992        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
15993            && active_group.active_range.start.to_offset(&buffer) == selection.start
15994        {
15995            active_group_id = Some(active_group.group_id);
15996        }
15997
15998        fn filtered<'a>(
15999            snapshot: EditorSnapshot,
16000            severity: GoToDiagnosticSeverityFilter,
16001            diagnostics: impl Iterator<Item = DiagnosticEntryRef<'a, usize>>,
16002        ) -> impl Iterator<Item = DiagnosticEntryRef<'a, usize>> {
16003            diagnostics
16004                .filter(move |entry| severity.matches(entry.diagnostic.severity))
16005                .filter(|entry| entry.range.start != entry.range.end)
16006                .filter(|entry| !entry.diagnostic.is_unnecessary)
16007                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
16008        }
16009
16010        let snapshot = self.snapshot(window, cx);
16011        let before = filtered(
16012            snapshot.clone(),
16013            severity,
16014            buffer
16015                .diagnostics_in_range(0..selection.start)
16016                .filter(|entry| entry.range.start <= selection.start),
16017        );
16018        let after = filtered(
16019            snapshot,
16020            severity,
16021            buffer
16022                .diagnostics_in_range(selection.start..buffer.len())
16023                .filter(|entry| entry.range.start >= selection.start),
16024        );
16025
16026        let mut found: Option<DiagnosticEntryRef<usize>> = None;
16027        if direction == Direction::Prev {
16028            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
16029            {
16030                for diagnostic in prev_diagnostics.into_iter().rev() {
16031                    if diagnostic.range.start != selection.start
16032                        || active_group_id
16033                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
16034                    {
16035                        found = Some(diagnostic);
16036                        break 'outer;
16037                    }
16038                }
16039            }
16040        } else {
16041            for diagnostic in after.chain(before) {
16042                if diagnostic.range.start != selection.start
16043                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
16044                {
16045                    found = Some(diagnostic);
16046                    break;
16047                }
16048            }
16049        }
16050        let Some(next_diagnostic) = found else {
16051            return;
16052        };
16053
16054        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
16055        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
16056            return;
16057        };
16058        self.change_selections(Default::default(), window, cx, |s| {
16059            s.select_ranges(vec![
16060                next_diagnostic.range.start..next_diagnostic.range.start,
16061            ])
16062        });
16063        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
16064        self.refresh_edit_prediction(false, true, window, cx);
16065    }
16066
16067    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
16068        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16069        let snapshot = self.snapshot(window, cx);
16070        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
16071        self.go_to_hunk_before_or_after_position(
16072            &snapshot,
16073            selection.head(),
16074            Direction::Next,
16075            window,
16076            cx,
16077        );
16078    }
16079
16080    pub fn go_to_hunk_before_or_after_position(
16081        &mut self,
16082        snapshot: &EditorSnapshot,
16083        position: Point,
16084        direction: Direction,
16085        window: &mut Window,
16086        cx: &mut Context<Editor>,
16087    ) {
16088        let row = if direction == Direction::Next {
16089            self.hunk_after_position(snapshot, position)
16090                .map(|hunk| hunk.row_range.start)
16091        } else {
16092            self.hunk_before_position(snapshot, position)
16093        };
16094
16095        if let Some(row) = row {
16096            let destination = Point::new(row.0, 0);
16097            let autoscroll = Autoscroll::center();
16098
16099            self.unfold_ranges(&[destination..destination], false, false, cx);
16100            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16101                s.select_ranges([destination..destination]);
16102            });
16103        }
16104    }
16105
16106    fn hunk_after_position(
16107        &mut self,
16108        snapshot: &EditorSnapshot,
16109        position: Point,
16110    ) -> Option<MultiBufferDiffHunk> {
16111        snapshot
16112            .buffer_snapshot()
16113            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
16114            .find(|hunk| hunk.row_range.start.0 > position.row)
16115            .or_else(|| {
16116                snapshot
16117                    .buffer_snapshot()
16118                    .diff_hunks_in_range(Point::zero()..position)
16119                    .find(|hunk| hunk.row_range.end.0 < position.row)
16120            })
16121    }
16122
16123    fn go_to_prev_hunk(
16124        &mut self,
16125        _: &GoToPreviousHunk,
16126        window: &mut Window,
16127        cx: &mut Context<Self>,
16128    ) {
16129        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16130        let snapshot = self.snapshot(window, cx);
16131        let selection = self.selections.newest::<Point>(&snapshot.display_snapshot);
16132        self.go_to_hunk_before_or_after_position(
16133            &snapshot,
16134            selection.head(),
16135            Direction::Prev,
16136            window,
16137            cx,
16138        );
16139    }
16140
16141    fn hunk_before_position(
16142        &mut self,
16143        snapshot: &EditorSnapshot,
16144        position: Point,
16145    ) -> Option<MultiBufferRow> {
16146        snapshot
16147            .buffer_snapshot()
16148            .diff_hunk_before(position)
16149            .or_else(|| snapshot.buffer_snapshot().diff_hunk_before(Point::MAX))
16150    }
16151
16152    fn go_to_next_change(
16153        &mut self,
16154        _: &GoToNextChange,
16155        window: &mut Window,
16156        cx: &mut Context<Self>,
16157    ) {
16158        if let Some(selections) = self
16159            .change_list
16160            .next_change(1, Direction::Next)
16161            .map(|s| s.to_vec())
16162        {
16163            self.change_selections(Default::default(), window, cx, |s| {
16164                let map = s.display_map();
16165                s.select_display_ranges(selections.iter().map(|a| {
16166                    let point = a.to_display_point(&map);
16167                    point..point
16168                }))
16169            })
16170        }
16171    }
16172
16173    fn go_to_previous_change(
16174        &mut self,
16175        _: &GoToPreviousChange,
16176        window: &mut Window,
16177        cx: &mut Context<Self>,
16178    ) {
16179        if let Some(selections) = self
16180            .change_list
16181            .next_change(1, Direction::Prev)
16182            .map(|s| s.to_vec())
16183        {
16184            self.change_selections(Default::default(), window, cx, |s| {
16185                let map = s.display_map();
16186                s.select_display_ranges(selections.iter().map(|a| {
16187                    let point = a.to_display_point(&map);
16188                    point..point
16189                }))
16190            })
16191        }
16192    }
16193
16194    pub fn go_to_next_document_highlight(
16195        &mut self,
16196        _: &GoToNextDocumentHighlight,
16197        window: &mut Window,
16198        cx: &mut Context<Self>,
16199    ) {
16200        self.go_to_document_highlight_before_or_after_position(Direction::Next, window, cx);
16201    }
16202
16203    pub fn go_to_prev_document_highlight(
16204        &mut self,
16205        _: &GoToPreviousDocumentHighlight,
16206        window: &mut Window,
16207        cx: &mut Context<Self>,
16208    ) {
16209        self.go_to_document_highlight_before_or_after_position(Direction::Prev, window, cx);
16210    }
16211
16212    pub fn go_to_document_highlight_before_or_after_position(
16213        &mut self,
16214        direction: Direction,
16215        window: &mut Window,
16216        cx: &mut Context<Editor>,
16217    ) {
16218        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16219        let snapshot = self.snapshot(window, cx);
16220        let buffer = &snapshot.buffer_snapshot();
16221        let position = self
16222            .selections
16223            .newest::<Point>(&snapshot.display_snapshot)
16224            .head();
16225        let anchor_position = buffer.anchor_after(position);
16226
16227        // Get all document highlights (both read and write)
16228        let mut all_highlights = Vec::new();
16229
16230        if let Some((_, read_highlights)) = self
16231            .background_highlights
16232            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
16233        {
16234            all_highlights.extend(read_highlights.iter());
16235        }
16236
16237        if let Some((_, write_highlights)) = self
16238            .background_highlights
16239            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
16240        {
16241            all_highlights.extend(write_highlights.iter());
16242        }
16243
16244        if all_highlights.is_empty() {
16245            return;
16246        }
16247
16248        // Sort highlights by position
16249        all_highlights.sort_by(|a, b| a.start.cmp(&b.start, buffer));
16250
16251        let target_highlight = match direction {
16252            Direction::Next => {
16253                // Find the first highlight after the current position
16254                all_highlights
16255                    .iter()
16256                    .find(|highlight| highlight.start.cmp(&anchor_position, buffer).is_gt())
16257            }
16258            Direction::Prev => {
16259                // Find the last highlight before the current position
16260                all_highlights
16261                    .iter()
16262                    .rev()
16263                    .find(|highlight| highlight.end.cmp(&anchor_position, buffer).is_lt())
16264            }
16265        };
16266
16267        if let Some(highlight) = target_highlight {
16268            let destination = highlight.start.to_point(buffer);
16269            let autoscroll = Autoscroll::center();
16270
16271            self.unfold_ranges(&[destination..destination], false, false, cx);
16272            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16273                s.select_ranges([destination..destination]);
16274            });
16275        }
16276    }
16277
16278    fn go_to_line<T: 'static>(
16279        &mut self,
16280        position: Anchor,
16281        highlight_color: Option<Hsla>,
16282        window: &mut Window,
16283        cx: &mut Context<Self>,
16284    ) {
16285        let snapshot = self.snapshot(window, cx).display_snapshot;
16286        let position = position.to_point(&snapshot.buffer_snapshot());
16287        let start = snapshot
16288            .buffer_snapshot()
16289            .clip_point(Point::new(position.row, 0), Bias::Left);
16290        let end = start + Point::new(1, 0);
16291        let start = snapshot.buffer_snapshot().anchor_before(start);
16292        let end = snapshot.buffer_snapshot().anchor_before(end);
16293
16294        self.highlight_rows::<T>(
16295            start..end,
16296            highlight_color
16297                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
16298            Default::default(),
16299            cx,
16300        );
16301
16302        if self.buffer.read(cx).is_singleton() {
16303            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
16304        }
16305    }
16306
16307    pub fn go_to_definition(
16308        &mut self,
16309        _: &GoToDefinition,
16310        window: &mut Window,
16311        cx: &mut Context<Self>,
16312    ) -> Task<Result<Navigated>> {
16313        let definition =
16314            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
16315        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
16316        cx.spawn_in(window, async move |editor, cx| {
16317            if definition.await? == Navigated::Yes {
16318                return Ok(Navigated::Yes);
16319            }
16320            match fallback_strategy {
16321                GoToDefinitionFallback::None => Ok(Navigated::No),
16322                GoToDefinitionFallback::FindAllReferences => {
16323                    match editor.update_in(cx, |editor, window, cx| {
16324                        editor.find_all_references(&FindAllReferences, window, cx)
16325                    })? {
16326                        Some(references) => references.await,
16327                        None => Ok(Navigated::No),
16328                    }
16329                }
16330            }
16331        })
16332    }
16333
16334    pub fn go_to_declaration(
16335        &mut self,
16336        _: &GoToDeclaration,
16337        window: &mut Window,
16338        cx: &mut Context<Self>,
16339    ) -> Task<Result<Navigated>> {
16340        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
16341    }
16342
16343    pub fn go_to_declaration_split(
16344        &mut self,
16345        _: &GoToDeclaration,
16346        window: &mut Window,
16347        cx: &mut Context<Self>,
16348    ) -> Task<Result<Navigated>> {
16349        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
16350    }
16351
16352    pub fn go_to_implementation(
16353        &mut self,
16354        _: &GoToImplementation,
16355        window: &mut Window,
16356        cx: &mut Context<Self>,
16357    ) -> Task<Result<Navigated>> {
16358        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
16359    }
16360
16361    pub fn go_to_implementation_split(
16362        &mut self,
16363        _: &GoToImplementationSplit,
16364        window: &mut Window,
16365        cx: &mut Context<Self>,
16366    ) -> Task<Result<Navigated>> {
16367        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
16368    }
16369
16370    pub fn go_to_type_definition(
16371        &mut self,
16372        _: &GoToTypeDefinition,
16373        window: &mut Window,
16374        cx: &mut Context<Self>,
16375    ) -> Task<Result<Navigated>> {
16376        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
16377    }
16378
16379    pub fn go_to_definition_split(
16380        &mut self,
16381        _: &GoToDefinitionSplit,
16382        window: &mut Window,
16383        cx: &mut Context<Self>,
16384    ) -> Task<Result<Navigated>> {
16385        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
16386    }
16387
16388    pub fn go_to_type_definition_split(
16389        &mut self,
16390        _: &GoToTypeDefinitionSplit,
16391        window: &mut Window,
16392        cx: &mut Context<Self>,
16393    ) -> Task<Result<Navigated>> {
16394        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
16395    }
16396
16397    fn go_to_definition_of_kind(
16398        &mut self,
16399        kind: GotoDefinitionKind,
16400        split: bool,
16401        window: &mut Window,
16402        cx: &mut Context<Self>,
16403    ) -> Task<Result<Navigated>> {
16404        let Some(provider) = self.semantics_provider.clone() else {
16405            return Task::ready(Ok(Navigated::No));
16406        };
16407        let head = self
16408            .selections
16409            .newest::<usize>(&self.display_snapshot(cx))
16410            .head();
16411        let buffer = self.buffer.read(cx);
16412        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
16413            return Task::ready(Ok(Navigated::No));
16414        };
16415        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
16416            return Task::ready(Ok(Navigated::No));
16417        };
16418
16419        cx.spawn_in(window, async move |editor, cx| {
16420            let Some(definitions) = definitions.await? else {
16421                return Ok(Navigated::No);
16422            };
16423            let navigated = editor
16424                .update_in(cx, |editor, window, cx| {
16425                    editor.navigate_to_hover_links(
16426                        Some(kind),
16427                        definitions
16428                            .into_iter()
16429                            .filter(|location| {
16430                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
16431                            })
16432                            .map(HoverLink::Text)
16433                            .collect::<Vec<_>>(),
16434                        split,
16435                        window,
16436                        cx,
16437                    )
16438                })?
16439                .await?;
16440            anyhow::Ok(navigated)
16441        })
16442    }
16443
16444    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
16445        let selection = self.selections.newest_anchor();
16446        let head = selection.head();
16447        let tail = selection.tail();
16448
16449        let Some((buffer, start_position)) =
16450            self.buffer.read(cx).text_anchor_for_position(head, cx)
16451        else {
16452            return;
16453        };
16454
16455        let end_position = if head != tail {
16456            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
16457                return;
16458            };
16459            Some(pos)
16460        } else {
16461            None
16462        };
16463
16464        let url_finder = cx.spawn_in(window, async move |_editor, cx| {
16465            let url = if let Some(end_pos) = end_position {
16466                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
16467            } else {
16468                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
16469            };
16470
16471            if let Some(url) = url {
16472                cx.update(|window, cx| {
16473                    if parse_zed_link(&url, cx).is_some() {
16474                        window.dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
16475                    } else {
16476                        cx.open_url(&url);
16477                    }
16478                })?;
16479            }
16480
16481            anyhow::Ok(())
16482        });
16483
16484        url_finder.detach();
16485    }
16486
16487    pub fn open_selected_filename(
16488        &mut self,
16489        _: &OpenSelectedFilename,
16490        window: &mut Window,
16491        cx: &mut Context<Self>,
16492    ) {
16493        let Some(workspace) = self.workspace() else {
16494            return;
16495        };
16496
16497        let position = self.selections.newest_anchor().head();
16498
16499        let Some((buffer, buffer_position)) =
16500            self.buffer.read(cx).text_anchor_for_position(position, cx)
16501        else {
16502            return;
16503        };
16504
16505        let project = self.project.clone();
16506
16507        cx.spawn_in(window, async move |_, cx| {
16508            let result = find_file(&buffer, project, buffer_position, cx).await;
16509
16510            if let Some((_, path)) = result {
16511                workspace
16512                    .update_in(cx, |workspace, window, cx| {
16513                        workspace.open_resolved_path(path, window, cx)
16514                    })?
16515                    .await?;
16516            }
16517            anyhow::Ok(())
16518        })
16519        .detach();
16520    }
16521
16522    pub(crate) fn navigate_to_hover_links(
16523        &mut self,
16524        kind: Option<GotoDefinitionKind>,
16525        definitions: Vec<HoverLink>,
16526        split: bool,
16527        window: &mut Window,
16528        cx: &mut Context<Editor>,
16529    ) -> Task<Result<Navigated>> {
16530        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
16531        let mut first_url_or_file = None;
16532        let definitions: Vec<_> = definitions
16533            .into_iter()
16534            .filter_map(|def| match def {
16535                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
16536                HoverLink::InlayHint(lsp_location, server_id) => {
16537                    let computation =
16538                        self.compute_target_location(lsp_location, server_id, window, cx);
16539                    Some(cx.background_spawn(computation))
16540                }
16541                HoverLink::Url(url) => {
16542                    first_url_or_file = Some(Either::Left(url));
16543                    None
16544                }
16545                HoverLink::File(path) => {
16546                    first_url_or_file = Some(Either::Right(path));
16547                    None
16548                }
16549            })
16550            .collect();
16551
16552        let workspace = self.workspace();
16553
16554        cx.spawn_in(window, async move |editor, cx| {
16555            let locations: Vec<Location> = future::join_all(definitions)
16556                .await
16557                .into_iter()
16558                .filter_map(|location| location.transpose())
16559                .collect::<Result<_>>()
16560                .context("location tasks")?;
16561            let mut locations = cx.update(|_, cx| {
16562                locations
16563                    .into_iter()
16564                    .map(|location| {
16565                        let buffer = location.buffer.read(cx);
16566                        (location.buffer, location.range.to_point(buffer))
16567                    })
16568                    .into_group_map()
16569            })?;
16570            let mut num_locations = 0;
16571            for ranges in locations.values_mut() {
16572                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
16573                ranges.dedup();
16574                num_locations += ranges.len();
16575            }
16576
16577            if num_locations > 1 {
16578                let Some(workspace) = workspace else {
16579                    return Ok(Navigated::No);
16580                };
16581
16582                let tab_kind = match kind {
16583                    Some(GotoDefinitionKind::Implementation) => "Implementations",
16584                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
16585                    Some(GotoDefinitionKind::Declaration) => "Declarations",
16586                    Some(GotoDefinitionKind::Type) => "Types",
16587                };
16588                let title = editor
16589                    .update_in(cx, |_, _, cx| {
16590                        let target = locations
16591                            .iter()
16592                            .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
16593                            .map(|(buffer, location)| {
16594                                buffer
16595                                    .read(cx)
16596                                    .text_for_range(location.clone())
16597                                    .collect::<String>()
16598                            })
16599                            .filter(|text| !text.contains('\n'))
16600                            .unique()
16601                            .take(3)
16602                            .join(", ");
16603                        if target.is_empty() {
16604                            tab_kind.to_owned()
16605                        } else {
16606                            format!("{tab_kind} for {target}")
16607                        }
16608                    })
16609                    .context("buffer title")?;
16610
16611                let opened = workspace
16612                    .update_in(cx, |workspace, window, cx| {
16613                        Self::open_locations_in_multibuffer(
16614                            workspace,
16615                            locations,
16616                            title,
16617                            split,
16618                            MultibufferSelectionMode::First,
16619                            window,
16620                            cx,
16621                        )
16622                    })
16623                    .is_ok();
16624
16625                anyhow::Ok(Navigated::from_bool(opened))
16626            } else if num_locations == 0 {
16627                // If there is one url or file, open it directly
16628                match first_url_or_file {
16629                    Some(Either::Left(url)) => {
16630                        cx.update(|_, cx| cx.open_url(&url))?;
16631                        Ok(Navigated::Yes)
16632                    }
16633                    Some(Either::Right(path)) => {
16634                        let Some(workspace) = workspace else {
16635                            return Ok(Navigated::No);
16636                        };
16637
16638                        workspace
16639                            .update_in(cx, |workspace, window, cx| {
16640                                workspace.open_resolved_path(path, window, cx)
16641                            })?
16642                            .await?;
16643                        Ok(Navigated::Yes)
16644                    }
16645                    None => Ok(Navigated::No),
16646                }
16647            } else {
16648                let Some(workspace) = workspace else {
16649                    return Ok(Navigated::No);
16650                };
16651
16652                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
16653                let target_range = target_ranges.first().unwrap().clone();
16654
16655                editor.update_in(cx, |editor, window, cx| {
16656                    let range = target_range.to_point(target_buffer.read(cx));
16657                    let range = editor.range_for_match(&range);
16658                    let range = collapse_multiline_range(range);
16659
16660                    if !split
16661                        && Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref()
16662                    {
16663                        editor.go_to_singleton_buffer_range(range, window, cx);
16664                    } else {
16665                        let pane = workspace.read(cx).active_pane().clone();
16666                        window.defer(cx, move |window, cx| {
16667                            let target_editor: Entity<Self> =
16668                                workspace.update(cx, |workspace, cx| {
16669                                    let pane = if split {
16670                                        workspace.adjacent_pane(window, cx)
16671                                    } else {
16672                                        workspace.active_pane().clone()
16673                                    };
16674
16675                                    workspace.open_project_item(
16676                                        pane,
16677                                        target_buffer.clone(),
16678                                        true,
16679                                        true,
16680                                        window,
16681                                        cx,
16682                                    )
16683                                });
16684                            target_editor.update(cx, |target_editor, cx| {
16685                                // When selecting a definition in a different buffer, disable the nav history
16686                                // to avoid creating a history entry at the previous cursor location.
16687                                pane.update(cx, |pane, _| pane.disable_history());
16688                                target_editor.go_to_singleton_buffer_range(range, window, cx);
16689                                pane.update(cx, |pane, _| pane.enable_history());
16690                            });
16691                        });
16692                    }
16693                    Navigated::Yes
16694                })
16695            }
16696        })
16697    }
16698
16699    fn compute_target_location(
16700        &self,
16701        lsp_location: lsp::Location,
16702        server_id: LanguageServerId,
16703        window: &mut Window,
16704        cx: &mut Context<Self>,
16705    ) -> Task<anyhow::Result<Option<Location>>> {
16706        let Some(project) = self.project.clone() else {
16707            return Task::ready(Ok(None));
16708        };
16709
16710        cx.spawn_in(window, async move |editor, cx| {
16711            let location_task = editor.update(cx, |_, cx| {
16712                project.update(cx, |project, cx| {
16713                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
16714                })
16715            })?;
16716            let location = Some({
16717                let target_buffer_handle = location_task.await.context("open local buffer")?;
16718                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
16719                    let target_start = target_buffer
16720                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
16721                    let target_end = target_buffer
16722                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
16723                    target_buffer.anchor_after(target_start)
16724                        ..target_buffer.anchor_before(target_end)
16725                })?;
16726                Location {
16727                    buffer: target_buffer_handle,
16728                    range,
16729                }
16730            });
16731            Ok(location)
16732        })
16733    }
16734
16735    fn go_to_next_reference(
16736        &mut self,
16737        _: &GoToNextReference,
16738        window: &mut Window,
16739        cx: &mut Context<Self>,
16740    ) {
16741        let task = self.go_to_reference_before_or_after_position(Direction::Next, 1, window, cx);
16742        if let Some(task) = task {
16743            task.detach();
16744        };
16745    }
16746
16747    fn go_to_prev_reference(
16748        &mut self,
16749        _: &GoToPreviousReference,
16750        window: &mut Window,
16751        cx: &mut Context<Self>,
16752    ) {
16753        let task = self.go_to_reference_before_or_after_position(Direction::Prev, 1, window, cx);
16754        if let Some(task) = task {
16755            task.detach();
16756        };
16757    }
16758
16759    pub fn go_to_reference_before_or_after_position(
16760        &mut self,
16761        direction: Direction,
16762        count: usize,
16763        window: &mut Window,
16764        cx: &mut Context<Self>,
16765    ) -> Option<Task<Result<()>>> {
16766        let selection = self.selections.newest_anchor();
16767        let head = selection.head();
16768
16769        let multi_buffer = self.buffer.read(cx);
16770
16771        let (buffer, text_head) = multi_buffer.text_anchor_for_position(head, cx)?;
16772        let workspace = self.workspace()?;
16773        let project = workspace.read(cx).project().clone();
16774        let references =
16775            project.update(cx, |project, cx| project.references(&buffer, text_head, cx));
16776        Some(cx.spawn_in(window, async move |editor, cx| -> Result<()> {
16777            let Some(locations) = references.await? else {
16778                return Ok(());
16779            };
16780
16781            if locations.is_empty() {
16782                // totally normal - the cursor may be on something which is not
16783                // a symbol (e.g. a keyword)
16784                log::info!("no references found under cursor");
16785                return Ok(());
16786            }
16787
16788            let multi_buffer = editor.read_with(cx, |editor, _| editor.buffer().clone())?;
16789
16790            let multi_buffer_snapshot =
16791                multi_buffer.read_with(cx, |multi_buffer, cx| multi_buffer.snapshot(cx))?;
16792
16793            let (locations, current_location_index) =
16794                multi_buffer.update(cx, |multi_buffer, cx| {
16795                    let mut locations = locations
16796                        .into_iter()
16797                        .filter_map(|loc| {
16798                            let start = multi_buffer.buffer_anchor_to_anchor(
16799                                &loc.buffer,
16800                                loc.range.start,
16801                                cx,
16802                            )?;
16803                            let end = multi_buffer.buffer_anchor_to_anchor(
16804                                &loc.buffer,
16805                                loc.range.end,
16806                                cx,
16807                            )?;
16808                            Some(start..end)
16809                        })
16810                        .collect::<Vec<_>>();
16811
16812                    // There is an O(n) implementation, but given this list will be
16813                    // small (usually <100 items), the extra O(log(n)) factor isn't
16814                    // worth the (surprisingly large amount of) extra complexity.
16815                    locations
16816                        .sort_unstable_by(|l, r| l.start.cmp(&r.start, &multi_buffer_snapshot));
16817
16818                    let head_offset = head.to_offset(&multi_buffer_snapshot);
16819
16820                    let current_location_index = locations.iter().position(|loc| {
16821                        loc.start.to_offset(&multi_buffer_snapshot) <= head_offset
16822                            && loc.end.to_offset(&multi_buffer_snapshot) >= head_offset
16823                    });
16824
16825                    (locations, current_location_index)
16826                })?;
16827
16828            let Some(current_location_index) = current_location_index else {
16829                // This indicates something has gone wrong, because we already
16830                // handle the "no references" case above
16831                log::error!(
16832                    "failed to find current reference under cursor. Total references: {}",
16833                    locations.len()
16834                );
16835                return Ok(());
16836            };
16837
16838            let destination_location_index = match direction {
16839                Direction::Next => (current_location_index + count) % locations.len(),
16840                Direction::Prev => {
16841                    (current_location_index + locations.len() - count % locations.len())
16842                        % locations.len()
16843                }
16844            };
16845
16846            // TODO(cameron): is this needed?
16847            // the thinking is to avoid "jumping to the current location" (avoid
16848            // polluting "jumplist" in vim terms)
16849            if current_location_index == destination_location_index {
16850                return Ok(());
16851            }
16852
16853            let Range { start, end } = locations[destination_location_index];
16854
16855            editor.update_in(cx, |editor, window, cx| {
16856                let effects = SelectionEffects::default();
16857
16858                editor.unfold_ranges(&[start..end], false, false, cx);
16859                editor.change_selections(effects, window, cx, |s| {
16860                    s.select_ranges([start..start]);
16861                });
16862            })?;
16863
16864            Ok(())
16865        }))
16866    }
16867
16868    pub fn find_all_references(
16869        &mut self,
16870        _: &FindAllReferences,
16871        window: &mut Window,
16872        cx: &mut Context<Self>,
16873    ) -> Option<Task<Result<Navigated>>> {
16874        let selection = self.selections.newest::<usize>(&self.display_snapshot(cx));
16875        let multi_buffer = self.buffer.read(cx);
16876        let head = selection.head();
16877
16878        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
16879        let head_anchor = multi_buffer_snapshot.anchor_at(
16880            head,
16881            if head < selection.tail() {
16882                Bias::Right
16883            } else {
16884                Bias::Left
16885            },
16886        );
16887
16888        match self
16889            .find_all_references_task_sources
16890            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16891        {
16892            Ok(_) => {
16893                log::info!(
16894                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
16895                );
16896                return None;
16897            }
16898            Err(i) => {
16899                self.find_all_references_task_sources.insert(i, head_anchor);
16900            }
16901        }
16902
16903        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
16904        let workspace = self.workspace()?;
16905        let project = workspace.read(cx).project().clone();
16906        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
16907        Some(cx.spawn_in(window, async move |editor, cx| {
16908            let _cleanup = cx.on_drop(&editor, move |editor, _| {
16909                if let Ok(i) = editor
16910                    .find_all_references_task_sources
16911                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16912                {
16913                    editor.find_all_references_task_sources.remove(i);
16914                }
16915            });
16916
16917            let Some(locations) = references.await? else {
16918                return anyhow::Ok(Navigated::No);
16919            };
16920            let mut locations = cx.update(|_, cx| {
16921                locations
16922                    .into_iter()
16923                    .map(|location| {
16924                        let buffer = location.buffer.read(cx);
16925                        (location.buffer, location.range.to_point(buffer))
16926                    })
16927                    .into_group_map()
16928            })?;
16929            if locations.is_empty() {
16930                return anyhow::Ok(Navigated::No);
16931            }
16932            for ranges in locations.values_mut() {
16933                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
16934                ranges.dedup();
16935            }
16936
16937            workspace.update_in(cx, |workspace, window, cx| {
16938                let target = locations
16939                    .iter()
16940                    .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
16941                    .map(|(buffer, location)| {
16942                        buffer
16943                            .read(cx)
16944                            .text_for_range(location.clone())
16945                            .collect::<String>()
16946                    })
16947                    .filter(|text| !text.contains('\n'))
16948                    .unique()
16949                    .take(3)
16950                    .join(", ");
16951                let title = if target.is_empty() {
16952                    "References".to_owned()
16953                } else {
16954                    format!("References to {target}")
16955                };
16956                Self::open_locations_in_multibuffer(
16957                    workspace,
16958                    locations,
16959                    title,
16960                    false,
16961                    MultibufferSelectionMode::First,
16962                    window,
16963                    cx,
16964                );
16965                Navigated::Yes
16966            })
16967        }))
16968    }
16969
16970    /// Opens a multibuffer with the given project locations in it
16971    pub fn open_locations_in_multibuffer(
16972        workspace: &mut Workspace,
16973        locations: std::collections::HashMap<Entity<Buffer>, Vec<Range<Point>>>,
16974        title: String,
16975        split: bool,
16976        multibuffer_selection_mode: MultibufferSelectionMode,
16977        window: &mut Window,
16978        cx: &mut Context<Workspace>,
16979    ) {
16980        if locations.is_empty() {
16981            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
16982            return;
16983        }
16984
16985        let capability = workspace.project().read(cx).capability();
16986        let mut ranges = <Vec<Range<Anchor>>>::new();
16987
16988        // a key to find existing multibuffer editors with the same set of locations
16989        // to prevent us from opening more and more multibuffer tabs for searches and the like
16990        let mut key = (title.clone(), vec![]);
16991        let excerpt_buffer = cx.new(|cx| {
16992            let key = &mut key.1;
16993            let mut multibuffer = MultiBuffer::new(capability);
16994            for (buffer, mut ranges_for_buffer) in locations {
16995                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
16996                key.push((buffer.read(cx).remote_id(), ranges_for_buffer.clone()));
16997                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
16998                    PathKey::for_buffer(&buffer, cx),
16999                    buffer.clone(),
17000                    ranges_for_buffer,
17001                    multibuffer_context_lines(cx),
17002                    cx,
17003                );
17004                ranges.extend(new_ranges)
17005            }
17006
17007            multibuffer.with_title(title)
17008        });
17009        let existing = workspace.active_pane().update(cx, |pane, cx| {
17010            pane.items()
17011                .filter_map(|item| item.downcast::<Editor>())
17012                .find(|editor| {
17013                    editor
17014                        .read(cx)
17015                        .lookup_key
17016                        .as_ref()
17017                        .and_then(|it| {
17018                            it.downcast_ref::<(String, Vec<(BufferId, Vec<Range<Point>>)>)>()
17019                        })
17020                        .is_some_and(|it| *it == key)
17021                })
17022        });
17023        let editor = existing.unwrap_or_else(|| {
17024            cx.new(|cx| {
17025                let mut editor = Editor::for_multibuffer(
17026                    excerpt_buffer,
17027                    Some(workspace.project().clone()),
17028                    window,
17029                    cx,
17030                );
17031                editor.lookup_key = Some(Box::new(key));
17032                editor
17033            })
17034        });
17035        editor.update(cx, |editor, cx| match multibuffer_selection_mode {
17036            MultibufferSelectionMode::First => {
17037                if let Some(first_range) = ranges.first() {
17038                    editor.change_selections(
17039                        SelectionEffects::no_scroll(),
17040                        window,
17041                        cx,
17042                        |selections| {
17043                            selections.clear_disjoint();
17044                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
17045                        },
17046                    );
17047                }
17048                editor.highlight_background::<Self>(
17049                    &ranges,
17050                    |theme| theme.colors().editor_highlighted_line_background,
17051                    cx,
17052                );
17053            }
17054            MultibufferSelectionMode::All => {
17055                editor.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
17056                    selections.clear_disjoint();
17057                    selections.select_anchor_ranges(ranges);
17058                });
17059            }
17060        });
17061
17062        let item = Box::new(editor);
17063        let item_id = item.item_id();
17064
17065        if split {
17066            let pane = workspace.adjacent_pane(window, cx);
17067            workspace.add_item(pane, item, None, true, true, window, cx);
17068        } else if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
17069            let (preview_item_id, preview_item_idx) =
17070                workspace.active_pane().read_with(cx, |pane, _| {
17071                    (pane.preview_item_id(), pane.preview_item_idx())
17072                });
17073
17074            workspace.add_item_to_active_pane(item, preview_item_idx, true, window, cx);
17075
17076            if let Some(preview_item_id) = preview_item_id {
17077                workspace.active_pane().update(cx, |pane, cx| {
17078                    pane.remove_item(preview_item_id, false, false, window, cx);
17079                });
17080            }
17081        } else {
17082            workspace.add_item_to_active_pane(item, None, true, window, cx);
17083        }
17084        workspace.active_pane().update(cx, |pane, cx| {
17085            pane.set_preview_item_id(Some(item_id), cx);
17086        });
17087    }
17088
17089    pub fn rename(
17090        &mut self,
17091        _: &Rename,
17092        window: &mut Window,
17093        cx: &mut Context<Self>,
17094    ) -> Option<Task<Result<()>>> {
17095        use language::ToOffset as _;
17096
17097        let provider = self.semantics_provider.clone()?;
17098        let selection = self.selections.newest_anchor().clone();
17099        let (cursor_buffer, cursor_buffer_position) = self
17100            .buffer
17101            .read(cx)
17102            .text_anchor_for_position(selection.head(), cx)?;
17103        let (tail_buffer, cursor_buffer_position_end) = self
17104            .buffer
17105            .read(cx)
17106            .text_anchor_for_position(selection.tail(), cx)?;
17107        if tail_buffer != cursor_buffer {
17108            return None;
17109        }
17110
17111        let snapshot = cursor_buffer.read(cx).snapshot();
17112        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
17113        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
17114        let prepare_rename = provider
17115            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
17116            .unwrap_or_else(|| Task::ready(Ok(None)));
17117        drop(snapshot);
17118
17119        Some(cx.spawn_in(window, async move |this, cx| {
17120            let rename_range = if let Some(range) = prepare_rename.await? {
17121                Some(range)
17122            } else {
17123                this.update(cx, |this, cx| {
17124                    let buffer = this.buffer.read(cx).snapshot(cx);
17125                    let mut buffer_highlights = this
17126                        .document_highlights_for_position(selection.head(), &buffer)
17127                        .filter(|highlight| {
17128                            highlight.start.excerpt_id == selection.head().excerpt_id
17129                                && highlight.end.excerpt_id == selection.head().excerpt_id
17130                        });
17131                    buffer_highlights
17132                        .next()
17133                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
17134                })?
17135            };
17136            if let Some(rename_range) = rename_range {
17137                this.update_in(cx, |this, window, cx| {
17138                    let snapshot = cursor_buffer.read(cx).snapshot();
17139                    let rename_buffer_range = rename_range.to_offset(&snapshot);
17140                    let cursor_offset_in_rename_range =
17141                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
17142                    let cursor_offset_in_rename_range_end =
17143                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
17144
17145                    this.take_rename(false, window, cx);
17146                    let buffer = this.buffer.read(cx).read(cx);
17147                    let cursor_offset = selection.head().to_offset(&buffer);
17148                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
17149                    let rename_end = rename_start + rename_buffer_range.len();
17150                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
17151                    let mut old_highlight_id = None;
17152                    let old_name: Arc<str> = buffer
17153                        .chunks(rename_start..rename_end, true)
17154                        .map(|chunk| {
17155                            if old_highlight_id.is_none() {
17156                                old_highlight_id = chunk.syntax_highlight_id;
17157                            }
17158                            chunk.text
17159                        })
17160                        .collect::<String>()
17161                        .into();
17162
17163                    drop(buffer);
17164
17165                    // Position the selection in the rename editor so that it matches the current selection.
17166                    this.show_local_selections = false;
17167                    let rename_editor = cx.new(|cx| {
17168                        let mut editor = Editor::single_line(window, cx);
17169                        editor.buffer.update(cx, |buffer, cx| {
17170                            buffer.edit([(0..0, old_name.clone())], None, cx)
17171                        });
17172                        let rename_selection_range = match cursor_offset_in_rename_range
17173                            .cmp(&cursor_offset_in_rename_range_end)
17174                        {
17175                            Ordering::Equal => {
17176                                editor.select_all(&SelectAll, window, cx);
17177                                return editor;
17178                            }
17179                            Ordering::Less => {
17180                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
17181                            }
17182                            Ordering::Greater => {
17183                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
17184                            }
17185                        };
17186                        if rename_selection_range.end > old_name.len() {
17187                            editor.select_all(&SelectAll, window, cx);
17188                        } else {
17189                            editor.change_selections(Default::default(), window, cx, |s| {
17190                                s.select_ranges([rename_selection_range]);
17191                            });
17192                        }
17193                        editor
17194                    });
17195                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
17196                        if e == &EditorEvent::Focused {
17197                            cx.emit(EditorEvent::FocusedIn)
17198                        }
17199                    })
17200                    .detach();
17201
17202                    let write_highlights =
17203                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
17204                    let read_highlights =
17205                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
17206                    let ranges = write_highlights
17207                        .iter()
17208                        .flat_map(|(_, ranges)| ranges.iter())
17209                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
17210                        .cloned()
17211                        .collect();
17212
17213                    this.highlight_text::<Rename>(
17214                        ranges,
17215                        HighlightStyle {
17216                            fade_out: Some(0.6),
17217                            ..Default::default()
17218                        },
17219                        cx,
17220                    );
17221                    let rename_focus_handle = rename_editor.focus_handle(cx);
17222                    window.focus(&rename_focus_handle);
17223                    let block_id = this.insert_blocks(
17224                        [BlockProperties {
17225                            style: BlockStyle::Flex,
17226                            placement: BlockPlacement::Below(range.start),
17227                            height: Some(1),
17228                            render: Arc::new({
17229                                let rename_editor = rename_editor.clone();
17230                                move |cx: &mut BlockContext| {
17231                                    let mut text_style = cx.editor_style.text.clone();
17232                                    if let Some(highlight_style) = old_highlight_id
17233                                        .and_then(|h| h.style(&cx.editor_style.syntax))
17234                                    {
17235                                        text_style = text_style.highlight(highlight_style);
17236                                    }
17237                                    div()
17238                                        .block_mouse_except_scroll()
17239                                        .pl(cx.anchor_x)
17240                                        .child(EditorElement::new(
17241                                            &rename_editor,
17242                                            EditorStyle {
17243                                                background: cx.theme().system().transparent,
17244                                                local_player: cx.editor_style.local_player,
17245                                                text: text_style,
17246                                                scrollbar_width: cx.editor_style.scrollbar_width,
17247                                                syntax: cx.editor_style.syntax.clone(),
17248                                                status: cx.editor_style.status.clone(),
17249                                                inlay_hints_style: HighlightStyle {
17250                                                    font_weight: Some(FontWeight::BOLD),
17251                                                    ..make_inlay_hints_style(cx.app)
17252                                                },
17253                                                edit_prediction_styles: make_suggestion_styles(
17254                                                    cx.app,
17255                                                ),
17256                                                ..EditorStyle::default()
17257                                            },
17258                                        ))
17259                                        .into_any_element()
17260                                }
17261                            }),
17262                            priority: 0,
17263                        }],
17264                        Some(Autoscroll::fit()),
17265                        cx,
17266                    )[0];
17267                    this.pending_rename = Some(RenameState {
17268                        range,
17269                        old_name,
17270                        editor: rename_editor,
17271                        block_id,
17272                    });
17273                })?;
17274            }
17275
17276            Ok(())
17277        }))
17278    }
17279
17280    pub fn confirm_rename(
17281        &mut self,
17282        _: &ConfirmRename,
17283        window: &mut Window,
17284        cx: &mut Context<Self>,
17285    ) -> Option<Task<Result<()>>> {
17286        let rename = self.take_rename(false, window, cx)?;
17287        let workspace = self.workspace()?.downgrade();
17288        let (buffer, start) = self
17289            .buffer
17290            .read(cx)
17291            .text_anchor_for_position(rename.range.start, cx)?;
17292        let (end_buffer, _) = self
17293            .buffer
17294            .read(cx)
17295            .text_anchor_for_position(rename.range.end, cx)?;
17296        if buffer != end_buffer {
17297            return None;
17298        }
17299
17300        let old_name = rename.old_name;
17301        let new_name = rename.editor.read(cx).text(cx);
17302
17303        let rename = self.semantics_provider.as_ref()?.perform_rename(
17304            &buffer,
17305            start,
17306            new_name.clone(),
17307            cx,
17308        )?;
17309
17310        Some(cx.spawn_in(window, async move |editor, cx| {
17311            let project_transaction = rename.await?;
17312            Self::open_project_transaction(
17313                &editor,
17314                workspace,
17315                project_transaction,
17316                format!("Rename: {} → {}", old_name, new_name),
17317                cx,
17318            )
17319            .await?;
17320
17321            editor.update(cx, |editor, cx| {
17322                editor.refresh_document_highlights(cx);
17323            })?;
17324            Ok(())
17325        }))
17326    }
17327
17328    fn take_rename(
17329        &mut self,
17330        moving_cursor: bool,
17331        window: &mut Window,
17332        cx: &mut Context<Self>,
17333    ) -> Option<RenameState> {
17334        let rename = self.pending_rename.take()?;
17335        if rename.editor.focus_handle(cx).is_focused(window) {
17336            window.focus(&self.focus_handle);
17337        }
17338
17339        self.remove_blocks(
17340            [rename.block_id].into_iter().collect(),
17341            Some(Autoscroll::fit()),
17342            cx,
17343        );
17344        self.clear_highlights::<Rename>(cx);
17345        self.show_local_selections = true;
17346
17347        if moving_cursor {
17348            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
17349                editor
17350                    .selections
17351                    .newest::<usize>(&editor.display_snapshot(cx))
17352                    .head()
17353            });
17354
17355            // Update the selection to match the position of the selection inside
17356            // the rename editor.
17357            let snapshot = self.buffer.read(cx).read(cx);
17358            let rename_range = rename.range.to_offset(&snapshot);
17359            let cursor_in_editor = snapshot
17360                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
17361                .min(rename_range.end);
17362            drop(snapshot);
17363
17364            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17365                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
17366            });
17367        } else {
17368            self.refresh_document_highlights(cx);
17369        }
17370
17371        Some(rename)
17372    }
17373
17374    pub fn pending_rename(&self) -> Option<&RenameState> {
17375        self.pending_rename.as_ref()
17376    }
17377
17378    fn format(
17379        &mut self,
17380        _: &Format,
17381        window: &mut Window,
17382        cx: &mut Context<Self>,
17383    ) -> Option<Task<Result<()>>> {
17384        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17385
17386        let project = match &self.project {
17387            Some(project) => project.clone(),
17388            None => return None,
17389        };
17390
17391        Some(self.perform_format(
17392            project,
17393            FormatTrigger::Manual,
17394            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
17395            window,
17396            cx,
17397        ))
17398    }
17399
17400    fn format_selections(
17401        &mut self,
17402        _: &FormatSelections,
17403        window: &mut Window,
17404        cx: &mut Context<Self>,
17405    ) -> Option<Task<Result<()>>> {
17406        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17407
17408        let project = match &self.project {
17409            Some(project) => project.clone(),
17410            None => return None,
17411        };
17412
17413        let ranges = self
17414            .selections
17415            .all_adjusted(&self.display_snapshot(cx))
17416            .into_iter()
17417            .map(|selection| selection.range())
17418            .collect_vec();
17419
17420        Some(self.perform_format(
17421            project,
17422            FormatTrigger::Manual,
17423            FormatTarget::Ranges(ranges),
17424            window,
17425            cx,
17426        ))
17427    }
17428
17429    fn perform_format(
17430        &mut self,
17431        project: Entity<Project>,
17432        trigger: FormatTrigger,
17433        target: FormatTarget,
17434        window: &mut Window,
17435        cx: &mut Context<Self>,
17436    ) -> Task<Result<()>> {
17437        let buffer = self.buffer.clone();
17438        let (buffers, target) = match target {
17439            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
17440            FormatTarget::Ranges(selection_ranges) => {
17441                let multi_buffer = buffer.read(cx);
17442                let snapshot = multi_buffer.read(cx);
17443                let mut buffers = HashSet::default();
17444                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
17445                    BTreeMap::new();
17446                for selection_range in selection_ranges {
17447                    for (buffer, buffer_range, _) in
17448                        snapshot.range_to_buffer_ranges(selection_range)
17449                    {
17450                        let buffer_id = buffer.remote_id();
17451                        let start = buffer.anchor_before(buffer_range.start);
17452                        let end = buffer.anchor_after(buffer_range.end);
17453                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
17454                        buffer_id_to_ranges
17455                            .entry(buffer_id)
17456                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
17457                            .or_insert_with(|| vec![start..end]);
17458                    }
17459                }
17460                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
17461            }
17462        };
17463
17464        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
17465        let selections_prev = transaction_id_prev
17466            .and_then(|transaction_id_prev| {
17467                // default to selections as they were after the last edit, if we have them,
17468                // instead of how they are now.
17469                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
17470                // will take you back to where you made the last edit, instead of staying where you scrolled
17471                self.selection_history
17472                    .transaction(transaction_id_prev)
17473                    .map(|t| t.0.clone())
17474            })
17475            .unwrap_or_else(|| self.selections.disjoint_anchors_arc());
17476
17477        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
17478        let format = project.update(cx, |project, cx| {
17479            project.format(buffers, target, true, trigger, cx)
17480        });
17481
17482        cx.spawn_in(window, async move |editor, cx| {
17483            let transaction = futures::select_biased! {
17484                transaction = format.log_err().fuse() => transaction,
17485                () = timeout => {
17486                    log::warn!("timed out waiting for formatting");
17487                    None
17488                }
17489            };
17490
17491            buffer
17492                .update(cx, |buffer, cx| {
17493                    if let Some(transaction) = transaction
17494                        && !buffer.is_singleton()
17495                    {
17496                        buffer.push_transaction(&transaction.0, cx);
17497                    }
17498                    cx.notify();
17499                })
17500                .ok();
17501
17502            if let Some(transaction_id_now) =
17503                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
17504            {
17505                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
17506                if has_new_transaction {
17507                    _ = editor.update(cx, |editor, _| {
17508                        editor
17509                            .selection_history
17510                            .insert_transaction(transaction_id_now, selections_prev);
17511                    });
17512                }
17513            }
17514
17515            Ok(())
17516        })
17517    }
17518
17519    fn organize_imports(
17520        &mut self,
17521        _: &OrganizeImports,
17522        window: &mut Window,
17523        cx: &mut Context<Self>,
17524    ) -> Option<Task<Result<()>>> {
17525        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17526        let project = match &self.project {
17527            Some(project) => project.clone(),
17528            None => return None,
17529        };
17530        Some(self.perform_code_action_kind(
17531            project,
17532            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
17533            window,
17534            cx,
17535        ))
17536    }
17537
17538    fn perform_code_action_kind(
17539        &mut self,
17540        project: Entity<Project>,
17541        kind: CodeActionKind,
17542        window: &mut Window,
17543        cx: &mut Context<Self>,
17544    ) -> Task<Result<()>> {
17545        let buffer = self.buffer.clone();
17546        let buffers = buffer.read(cx).all_buffers();
17547        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
17548        let apply_action = project.update(cx, |project, cx| {
17549            project.apply_code_action_kind(buffers, kind, true, cx)
17550        });
17551        cx.spawn_in(window, async move |_, cx| {
17552            let transaction = futures::select_biased! {
17553                () = timeout => {
17554                    log::warn!("timed out waiting for executing code action");
17555                    None
17556                }
17557                transaction = apply_action.log_err().fuse() => transaction,
17558            };
17559            buffer
17560                .update(cx, |buffer, cx| {
17561                    // check if we need this
17562                    if let Some(transaction) = transaction
17563                        && !buffer.is_singleton()
17564                    {
17565                        buffer.push_transaction(&transaction.0, cx);
17566                    }
17567                    cx.notify();
17568                })
17569                .ok();
17570            Ok(())
17571        })
17572    }
17573
17574    pub fn restart_language_server(
17575        &mut self,
17576        _: &RestartLanguageServer,
17577        _: &mut Window,
17578        cx: &mut Context<Self>,
17579    ) {
17580        if let Some(project) = self.project.clone() {
17581            self.buffer.update(cx, |multi_buffer, cx| {
17582                project.update(cx, |project, cx| {
17583                    project.restart_language_servers_for_buffers(
17584                        multi_buffer.all_buffers().into_iter().collect(),
17585                        HashSet::default(),
17586                        cx,
17587                    );
17588                });
17589            })
17590        }
17591    }
17592
17593    pub fn stop_language_server(
17594        &mut self,
17595        _: &StopLanguageServer,
17596        _: &mut Window,
17597        cx: &mut Context<Self>,
17598    ) {
17599        if let Some(project) = self.project.clone() {
17600            self.buffer.update(cx, |multi_buffer, cx| {
17601                project.update(cx, |project, cx| {
17602                    project.stop_language_servers_for_buffers(
17603                        multi_buffer.all_buffers().into_iter().collect(),
17604                        HashSet::default(),
17605                        cx,
17606                    );
17607                });
17608            });
17609            self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
17610        }
17611    }
17612
17613    fn cancel_language_server_work(
17614        workspace: &mut Workspace,
17615        _: &actions::CancelLanguageServerWork,
17616        _: &mut Window,
17617        cx: &mut Context<Workspace>,
17618    ) {
17619        let project = workspace.project();
17620        let buffers = workspace
17621            .active_item(cx)
17622            .and_then(|item| item.act_as::<Editor>(cx))
17623            .map_or(HashSet::default(), |editor| {
17624                editor.read(cx).buffer.read(cx).all_buffers()
17625            });
17626        project.update(cx, |project, cx| {
17627            project.cancel_language_server_work_for_buffers(buffers, cx);
17628        });
17629    }
17630
17631    fn show_character_palette(
17632        &mut self,
17633        _: &ShowCharacterPalette,
17634        window: &mut Window,
17635        _: &mut Context<Self>,
17636    ) {
17637        window.show_character_palette();
17638    }
17639
17640    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
17641        if !self.diagnostics_enabled() {
17642            return;
17643        }
17644
17645        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
17646            let buffer = self.buffer.read(cx).snapshot(cx);
17647            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
17648            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
17649            let is_valid = buffer
17650                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
17651                .any(|entry| {
17652                    entry.diagnostic.is_primary
17653                        && !entry.range.is_empty()
17654                        && entry.range.start == primary_range_start
17655                        && entry.diagnostic.message == active_diagnostics.active_message
17656                });
17657
17658            if !is_valid {
17659                self.dismiss_diagnostics(cx);
17660            }
17661        }
17662    }
17663
17664    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
17665        match &self.active_diagnostics {
17666            ActiveDiagnostic::Group(group) => Some(group),
17667            _ => None,
17668        }
17669    }
17670
17671    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
17672        if !self.diagnostics_enabled() {
17673            return;
17674        }
17675        self.dismiss_diagnostics(cx);
17676        self.active_diagnostics = ActiveDiagnostic::All;
17677    }
17678
17679    fn activate_diagnostics(
17680        &mut self,
17681        buffer_id: BufferId,
17682        diagnostic: DiagnosticEntryRef<'_, usize>,
17683        window: &mut Window,
17684        cx: &mut Context<Self>,
17685    ) {
17686        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17687            return;
17688        }
17689        self.dismiss_diagnostics(cx);
17690        let snapshot = self.snapshot(window, cx);
17691        let buffer = self.buffer.read(cx).snapshot(cx);
17692        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
17693            return;
17694        };
17695
17696        let diagnostic_group = buffer
17697            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
17698            .collect::<Vec<_>>();
17699
17700        let blocks =
17701            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
17702
17703        let blocks = self.display_map.update(cx, |display_map, cx| {
17704            display_map.insert_blocks(blocks, cx).into_iter().collect()
17705        });
17706        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
17707            active_range: buffer.anchor_before(diagnostic.range.start)
17708                ..buffer.anchor_after(diagnostic.range.end),
17709            active_message: diagnostic.diagnostic.message.clone(),
17710            group_id: diagnostic.diagnostic.group_id,
17711            blocks,
17712        });
17713        cx.notify();
17714    }
17715
17716    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
17717        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17718            return;
17719        };
17720
17721        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
17722        if let ActiveDiagnostic::Group(group) = prev {
17723            self.display_map.update(cx, |display_map, cx| {
17724                display_map.remove_blocks(group.blocks, cx);
17725            });
17726            cx.notify();
17727        }
17728    }
17729
17730    /// Disable inline diagnostics rendering for this editor.
17731    pub fn disable_inline_diagnostics(&mut self) {
17732        self.inline_diagnostics_enabled = false;
17733        self.inline_diagnostics_update = Task::ready(());
17734        self.inline_diagnostics.clear();
17735    }
17736
17737    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
17738        self.diagnostics_enabled = false;
17739        self.dismiss_diagnostics(cx);
17740        self.inline_diagnostics_update = Task::ready(());
17741        self.inline_diagnostics.clear();
17742    }
17743
17744    pub fn disable_word_completions(&mut self) {
17745        self.word_completions_enabled = false;
17746    }
17747
17748    pub fn diagnostics_enabled(&self) -> bool {
17749        self.diagnostics_enabled && self.mode.is_full()
17750    }
17751
17752    pub fn inline_diagnostics_enabled(&self) -> bool {
17753        self.inline_diagnostics_enabled && self.diagnostics_enabled()
17754    }
17755
17756    pub fn show_inline_diagnostics(&self) -> bool {
17757        self.show_inline_diagnostics
17758    }
17759
17760    pub fn toggle_inline_diagnostics(
17761        &mut self,
17762        _: &ToggleInlineDiagnostics,
17763        window: &mut Window,
17764        cx: &mut Context<Editor>,
17765    ) {
17766        self.show_inline_diagnostics = !self.show_inline_diagnostics;
17767        self.refresh_inline_diagnostics(false, window, cx);
17768    }
17769
17770    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
17771        self.diagnostics_max_severity = severity;
17772        self.display_map.update(cx, |display_map, _| {
17773            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
17774        });
17775    }
17776
17777    pub fn toggle_diagnostics(
17778        &mut self,
17779        _: &ToggleDiagnostics,
17780        window: &mut Window,
17781        cx: &mut Context<Editor>,
17782    ) {
17783        if !self.diagnostics_enabled() {
17784            return;
17785        }
17786
17787        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17788            EditorSettings::get_global(cx)
17789                .diagnostics_max_severity
17790                .filter(|severity| severity != &DiagnosticSeverity::Off)
17791                .unwrap_or(DiagnosticSeverity::Hint)
17792        } else {
17793            DiagnosticSeverity::Off
17794        };
17795        self.set_max_diagnostics_severity(new_severity, cx);
17796        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17797            self.active_diagnostics = ActiveDiagnostic::None;
17798            self.inline_diagnostics_update = Task::ready(());
17799            self.inline_diagnostics.clear();
17800        } else {
17801            self.refresh_inline_diagnostics(false, window, cx);
17802        }
17803
17804        cx.notify();
17805    }
17806
17807    pub fn toggle_minimap(
17808        &mut self,
17809        _: &ToggleMinimap,
17810        window: &mut Window,
17811        cx: &mut Context<Editor>,
17812    ) {
17813        if self.supports_minimap(cx) {
17814            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
17815        }
17816    }
17817
17818    fn refresh_inline_diagnostics(
17819        &mut self,
17820        debounce: bool,
17821        window: &mut Window,
17822        cx: &mut Context<Self>,
17823    ) {
17824        let max_severity = ProjectSettings::get_global(cx)
17825            .diagnostics
17826            .inline
17827            .max_severity
17828            .unwrap_or(self.diagnostics_max_severity);
17829
17830        if !self.inline_diagnostics_enabled()
17831            || !self.show_inline_diagnostics
17832            || max_severity == DiagnosticSeverity::Off
17833        {
17834            self.inline_diagnostics_update = Task::ready(());
17835            self.inline_diagnostics.clear();
17836            return;
17837        }
17838
17839        let debounce_ms = ProjectSettings::get_global(cx)
17840            .diagnostics
17841            .inline
17842            .update_debounce_ms;
17843        let debounce = if debounce && debounce_ms > 0 {
17844            Some(Duration::from_millis(debounce_ms))
17845        } else {
17846            None
17847        };
17848        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
17849            if let Some(debounce) = debounce {
17850                cx.background_executor().timer(debounce).await;
17851            }
17852            let Some(snapshot) = editor.upgrade().and_then(|editor| {
17853                editor
17854                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
17855                    .ok()
17856            }) else {
17857                return;
17858            };
17859
17860            let new_inline_diagnostics = cx
17861                .background_spawn(async move {
17862                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
17863                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
17864                        let message = diagnostic_entry
17865                            .diagnostic
17866                            .message
17867                            .split_once('\n')
17868                            .map(|(line, _)| line)
17869                            .map(SharedString::new)
17870                            .unwrap_or_else(|| {
17871                                SharedString::new(&*diagnostic_entry.diagnostic.message)
17872                            });
17873                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
17874                        let (Ok(i) | Err(i)) = inline_diagnostics
17875                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
17876                        inline_diagnostics.insert(
17877                            i,
17878                            (
17879                                start_anchor,
17880                                InlineDiagnostic {
17881                                    message,
17882                                    group_id: diagnostic_entry.diagnostic.group_id,
17883                                    start: diagnostic_entry.range.start.to_point(&snapshot),
17884                                    is_primary: diagnostic_entry.diagnostic.is_primary,
17885                                    severity: diagnostic_entry.diagnostic.severity,
17886                                },
17887                            ),
17888                        );
17889                    }
17890                    inline_diagnostics
17891                })
17892                .await;
17893
17894            editor
17895                .update(cx, |editor, cx| {
17896                    editor.inline_diagnostics = new_inline_diagnostics;
17897                    cx.notify();
17898                })
17899                .ok();
17900        });
17901    }
17902
17903    fn pull_diagnostics(
17904        &mut self,
17905        buffer_id: Option<BufferId>,
17906        window: &Window,
17907        cx: &mut Context<Self>,
17908    ) -> Option<()> {
17909        if self.ignore_lsp_data() {
17910            return None;
17911        }
17912        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
17913            .diagnostics
17914            .lsp_pull_diagnostics;
17915        if !pull_diagnostics_settings.enabled {
17916            return None;
17917        }
17918        let project = self.project()?.downgrade();
17919        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
17920        let mut buffers = self.buffer.read(cx).all_buffers();
17921        buffers.retain(|buffer| {
17922            let buffer_id_to_retain = buffer.read(cx).remote_id();
17923            buffer_id.is_none_or(|buffer_id| buffer_id == buffer_id_to_retain)
17924                && self.registered_buffers.contains_key(&buffer_id_to_retain)
17925        });
17926        if buffers.is_empty() {
17927            self.pull_diagnostics_task = Task::ready(());
17928            return None;
17929        }
17930
17931        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
17932            cx.background_executor().timer(debounce).await;
17933
17934            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
17935                buffers
17936                    .into_iter()
17937                    .filter_map(|buffer| {
17938                        project
17939                            .update(cx, |project, cx| {
17940                                project.lsp_store().update(cx, |lsp_store, cx| {
17941                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
17942                                })
17943                            })
17944                            .ok()
17945                    })
17946                    .collect::<FuturesUnordered<_>>()
17947            }) else {
17948                return;
17949            };
17950
17951            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
17952                match pull_task {
17953                    Ok(()) => {
17954                        if editor
17955                            .update_in(cx, |editor, window, cx| {
17956                                editor.update_diagnostics_state(window, cx);
17957                            })
17958                            .is_err()
17959                        {
17960                            return;
17961                        }
17962                    }
17963                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
17964                }
17965            }
17966        });
17967
17968        Some(())
17969    }
17970
17971    pub fn set_selections_from_remote(
17972        &mut self,
17973        selections: Vec<Selection<Anchor>>,
17974        pending_selection: Option<Selection<Anchor>>,
17975        window: &mut Window,
17976        cx: &mut Context<Self>,
17977    ) {
17978        let old_cursor_position = self.selections.newest_anchor().head();
17979        self.selections.change_with(cx, |s| {
17980            s.select_anchors(selections);
17981            if let Some(pending_selection) = pending_selection {
17982                s.set_pending(pending_selection, SelectMode::Character);
17983            } else {
17984                s.clear_pending();
17985            }
17986        });
17987        self.selections_did_change(
17988            false,
17989            &old_cursor_position,
17990            SelectionEffects::default(),
17991            window,
17992            cx,
17993        );
17994    }
17995
17996    pub fn transact(
17997        &mut self,
17998        window: &mut Window,
17999        cx: &mut Context<Self>,
18000        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
18001    ) -> Option<TransactionId> {
18002        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
18003            this.start_transaction_at(Instant::now(), window, cx);
18004            update(this, window, cx);
18005            this.end_transaction_at(Instant::now(), cx)
18006        })
18007    }
18008
18009    pub fn start_transaction_at(
18010        &mut self,
18011        now: Instant,
18012        window: &mut Window,
18013        cx: &mut Context<Self>,
18014    ) -> Option<TransactionId> {
18015        self.end_selection(window, cx);
18016        if let Some(tx_id) = self
18017            .buffer
18018            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
18019        {
18020            self.selection_history
18021                .insert_transaction(tx_id, self.selections.disjoint_anchors_arc());
18022            cx.emit(EditorEvent::TransactionBegun {
18023                transaction_id: tx_id,
18024            });
18025            Some(tx_id)
18026        } else {
18027            None
18028        }
18029    }
18030
18031    pub fn end_transaction_at(
18032        &mut self,
18033        now: Instant,
18034        cx: &mut Context<Self>,
18035    ) -> Option<TransactionId> {
18036        if let Some(transaction_id) = self
18037            .buffer
18038            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
18039        {
18040            if let Some((_, end_selections)) =
18041                self.selection_history.transaction_mut(transaction_id)
18042            {
18043                *end_selections = Some(self.selections.disjoint_anchors_arc());
18044            } else {
18045                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
18046            }
18047
18048            cx.emit(EditorEvent::Edited { transaction_id });
18049            Some(transaction_id)
18050        } else {
18051            None
18052        }
18053    }
18054
18055    pub fn modify_transaction_selection_history(
18056        &mut self,
18057        transaction_id: TransactionId,
18058        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
18059    ) -> bool {
18060        self.selection_history
18061            .transaction_mut(transaction_id)
18062            .map(modify)
18063            .is_some()
18064    }
18065
18066    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
18067        if self.selection_mark_mode {
18068            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18069                s.move_with(|_, sel| {
18070                    sel.collapse_to(sel.head(), SelectionGoal::None);
18071                });
18072            })
18073        }
18074        self.selection_mark_mode = true;
18075        cx.notify();
18076    }
18077
18078    pub fn swap_selection_ends(
18079        &mut self,
18080        _: &actions::SwapSelectionEnds,
18081        window: &mut Window,
18082        cx: &mut Context<Self>,
18083    ) {
18084        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18085            s.move_with(|_, sel| {
18086                if sel.start != sel.end {
18087                    sel.reversed = !sel.reversed
18088                }
18089            });
18090        });
18091        self.request_autoscroll(Autoscroll::newest(), cx);
18092        cx.notify();
18093    }
18094
18095    pub fn toggle_focus(
18096        workspace: &mut Workspace,
18097        _: &actions::ToggleFocus,
18098        window: &mut Window,
18099        cx: &mut Context<Workspace>,
18100    ) {
18101        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
18102            return;
18103        };
18104        workspace.activate_item(&item, true, true, window, cx);
18105    }
18106
18107    pub fn toggle_fold(
18108        &mut self,
18109        _: &actions::ToggleFold,
18110        window: &mut Window,
18111        cx: &mut Context<Self>,
18112    ) {
18113        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18114            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18115            let selection = self.selections.newest::<Point>(&display_map);
18116
18117            let range = if selection.is_empty() {
18118                let point = selection.head().to_display_point(&display_map);
18119                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
18120                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
18121                    .to_point(&display_map);
18122                start..end
18123            } else {
18124                selection.range()
18125            };
18126            if display_map.folds_in_range(range).next().is_some() {
18127                self.unfold_lines(&Default::default(), window, cx)
18128            } else {
18129                self.fold(&Default::default(), window, cx)
18130            }
18131        } else {
18132            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18133            let buffer_ids: HashSet<_> = self
18134                .selections
18135                .disjoint_anchor_ranges()
18136                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18137                .collect();
18138
18139            let should_unfold = buffer_ids
18140                .iter()
18141                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18142
18143            for buffer_id in buffer_ids {
18144                if should_unfold {
18145                    self.unfold_buffer(buffer_id, cx);
18146                } else {
18147                    self.fold_buffer(buffer_id, cx);
18148                }
18149            }
18150        }
18151    }
18152
18153    pub fn toggle_fold_recursive(
18154        &mut self,
18155        _: &actions::ToggleFoldRecursive,
18156        window: &mut Window,
18157        cx: &mut Context<Self>,
18158    ) {
18159        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
18160
18161        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18162        let range = if selection.is_empty() {
18163            let point = selection.head().to_display_point(&display_map);
18164            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
18165            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
18166                .to_point(&display_map);
18167            start..end
18168        } else {
18169            selection.range()
18170        };
18171        if display_map.folds_in_range(range).next().is_some() {
18172            self.unfold_recursive(&Default::default(), window, cx)
18173        } else {
18174            self.fold_recursive(&Default::default(), window, cx)
18175        }
18176    }
18177
18178    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
18179        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18180            let mut to_fold = Vec::new();
18181            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18182            let selections = self.selections.all_adjusted(&display_map);
18183
18184            for selection in selections {
18185                let range = selection.range().sorted();
18186                let buffer_start_row = range.start.row;
18187
18188                if range.start.row != range.end.row {
18189                    let mut found = false;
18190                    let mut row = range.start.row;
18191                    while row <= range.end.row {
18192                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18193                        {
18194                            found = true;
18195                            row = crease.range().end.row + 1;
18196                            to_fold.push(crease);
18197                        } else {
18198                            row += 1
18199                        }
18200                    }
18201                    if found {
18202                        continue;
18203                    }
18204                }
18205
18206                for row in (0..=range.start.row).rev() {
18207                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18208                        && crease.range().end.row >= buffer_start_row
18209                    {
18210                        to_fold.push(crease);
18211                        if row <= range.start.row {
18212                            break;
18213                        }
18214                    }
18215                }
18216            }
18217
18218            self.fold_creases(to_fold, true, window, cx);
18219        } else {
18220            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18221            let buffer_ids = self
18222                .selections
18223                .disjoint_anchor_ranges()
18224                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18225                .collect::<HashSet<_>>();
18226            for buffer_id in buffer_ids {
18227                self.fold_buffer(buffer_id, cx);
18228            }
18229        }
18230    }
18231
18232    pub fn toggle_fold_all(
18233        &mut self,
18234        _: &actions::ToggleFoldAll,
18235        window: &mut Window,
18236        cx: &mut Context<Self>,
18237    ) {
18238        if self.buffer.read(cx).is_singleton() {
18239            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18240            let has_folds = display_map
18241                .folds_in_range(0..display_map.buffer_snapshot().len())
18242                .next()
18243                .is_some();
18244
18245            if has_folds {
18246                self.unfold_all(&actions::UnfoldAll, window, cx);
18247            } else {
18248                self.fold_all(&actions::FoldAll, window, cx);
18249            }
18250        } else {
18251            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
18252            let should_unfold = buffer_ids
18253                .iter()
18254                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18255
18256            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18257                editor
18258                    .update_in(cx, |editor, _, cx| {
18259                        for buffer_id in buffer_ids {
18260                            if should_unfold {
18261                                editor.unfold_buffer(buffer_id, cx);
18262                            } else {
18263                                editor.fold_buffer(buffer_id, cx);
18264                            }
18265                        }
18266                    })
18267                    .ok();
18268            });
18269        }
18270    }
18271
18272    fn fold_at_level(
18273        &mut self,
18274        fold_at: &FoldAtLevel,
18275        window: &mut Window,
18276        cx: &mut Context<Self>,
18277    ) {
18278        if !self.buffer.read(cx).is_singleton() {
18279            return;
18280        }
18281
18282        let fold_at_level = fold_at.0;
18283        let snapshot = self.buffer.read(cx).snapshot(cx);
18284        let mut to_fold = Vec::new();
18285        let mut stack = vec![(0, snapshot.max_row().0, 1)];
18286
18287        let row_ranges_to_keep: Vec<Range<u32>> = self
18288            .selections
18289            .all::<Point>(&self.display_snapshot(cx))
18290            .into_iter()
18291            .map(|sel| sel.start.row..sel.end.row)
18292            .collect();
18293
18294        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
18295            while start_row < end_row {
18296                match self
18297                    .snapshot(window, cx)
18298                    .crease_for_buffer_row(MultiBufferRow(start_row))
18299                {
18300                    Some(crease) => {
18301                        let nested_start_row = crease.range().start.row + 1;
18302                        let nested_end_row = crease.range().end.row;
18303
18304                        if current_level < fold_at_level {
18305                            stack.push((nested_start_row, nested_end_row, current_level + 1));
18306                        } else if current_level == fold_at_level {
18307                            // Fold iff there is no selection completely contained within the fold region
18308                            if !row_ranges_to_keep.iter().any(|selection| {
18309                                selection.end >= nested_start_row
18310                                    && selection.start <= nested_end_row
18311                            }) {
18312                                to_fold.push(crease);
18313                            }
18314                        }
18315
18316                        start_row = nested_end_row + 1;
18317                    }
18318                    None => start_row += 1,
18319                }
18320            }
18321        }
18322
18323        self.fold_creases(to_fold, true, window, cx);
18324    }
18325
18326    pub fn fold_at_level_1(
18327        &mut self,
18328        _: &actions::FoldAtLevel1,
18329        window: &mut Window,
18330        cx: &mut Context<Self>,
18331    ) {
18332        self.fold_at_level(&actions::FoldAtLevel(1), window, cx);
18333    }
18334
18335    pub fn fold_at_level_2(
18336        &mut self,
18337        _: &actions::FoldAtLevel2,
18338        window: &mut Window,
18339        cx: &mut Context<Self>,
18340    ) {
18341        self.fold_at_level(&actions::FoldAtLevel(2), window, cx);
18342    }
18343
18344    pub fn fold_at_level_3(
18345        &mut self,
18346        _: &actions::FoldAtLevel3,
18347        window: &mut Window,
18348        cx: &mut Context<Self>,
18349    ) {
18350        self.fold_at_level(&actions::FoldAtLevel(3), window, cx);
18351    }
18352
18353    pub fn fold_at_level_4(
18354        &mut self,
18355        _: &actions::FoldAtLevel4,
18356        window: &mut Window,
18357        cx: &mut Context<Self>,
18358    ) {
18359        self.fold_at_level(&actions::FoldAtLevel(4), window, cx);
18360    }
18361
18362    pub fn fold_at_level_5(
18363        &mut self,
18364        _: &actions::FoldAtLevel5,
18365        window: &mut Window,
18366        cx: &mut Context<Self>,
18367    ) {
18368        self.fold_at_level(&actions::FoldAtLevel(5), window, cx);
18369    }
18370
18371    pub fn fold_at_level_6(
18372        &mut self,
18373        _: &actions::FoldAtLevel6,
18374        window: &mut Window,
18375        cx: &mut Context<Self>,
18376    ) {
18377        self.fold_at_level(&actions::FoldAtLevel(6), window, cx);
18378    }
18379
18380    pub fn fold_at_level_7(
18381        &mut self,
18382        _: &actions::FoldAtLevel7,
18383        window: &mut Window,
18384        cx: &mut Context<Self>,
18385    ) {
18386        self.fold_at_level(&actions::FoldAtLevel(7), window, cx);
18387    }
18388
18389    pub fn fold_at_level_8(
18390        &mut self,
18391        _: &actions::FoldAtLevel8,
18392        window: &mut Window,
18393        cx: &mut Context<Self>,
18394    ) {
18395        self.fold_at_level(&actions::FoldAtLevel(8), window, cx);
18396    }
18397
18398    pub fn fold_at_level_9(
18399        &mut self,
18400        _: &actions::FoldAtLevel9,
18401        window: &mut Window,
18402        cx: &mut Context<Self>,
18403    ) {
18404        self.fold_at_level(&actions::FoldAtLevel(9), window, cx);
18405    }
18406
18407    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
18408        if self.buffer.read(cx).is_singleton() {
18409            let mut fold_ranges = Vec::new();
18410            let snapshot = self.buffer.read(cx).snapshot(cx);
18411
18412            for row in 0..snapshot.max_row().0 {
18413                if let Some(foldable_range) = self
18414                    .snapshot(window, cx)
18415                    .crease_for_buffer_row(MultiBufferRow(row))
18416                {
18417                    fold_ranges.push(foldable_range);
18418                }
18419            }
18420
18421            self.fold_creases(fold_ranges, true, window, cx);
18422        } else {
18423            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18424                editor
18425                    .update_in(cx, |editor, _, cx| {
18426                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18427                            editor.fold_buffer(buffer_id, cx);
18428                        }
18429                    })
18430                    .ok();
18431            });
18432        }
18433    }
18434
18435    pub fn fold_function_bodies(
18436        &mut self,
18437        _: &actions::FoldFunctionBodies,
18438        window: &mut Window,
18439        cx: &mut Context<Self>,
18440    ) {
18441        let snapshot = self.buffer.read(cx).snapshot(cx);
18442
18443        let ranges = snapshot
18444            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
18445            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
18446            .collect::<Vec<_>>();
18447
18448        let creases = ranges
18449            .into_iter()
18450            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
18451            .collect();
18452
18453        self.fold_creases(creases, true, window, cx);
18454    }
18455
18456    pub fn fold_recursive(
18457        &mut self,
18458        _: &actions::FoldRecursive,
18459        window: &mut Window,
18460        cx: &mut Context<Self>,
18461    ) {
18462        let mut to_fold = Vec::new();
18463        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18464        let selections = self.selections.all_adjusted(&display_map);
18465
18466        for selection in selections {
18467            let range = selection.range().sorted();
18468            let buffer_start_row = range.start.row;
18469
18470            if range.start.row != range.end.row {
18471                let mut found = false;
18472                for row in range.start.row..=range.end.row {
18473                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18474                        found = true;
18475                        to_fold.push(crease);
18476                    }
18477                }
18478                if found {
18479                    continue;
18480                }
18481            }
18482
18483            for row in (0..=range.start.row).rev() {
18484                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18485                    if crease.range().end.row >= buffer_start_row {
18486                        to_fold.push(crease);
18487                    } else {
18488                        break;
18489                    }
18490                }
18491            }
18492        }
18493
18494        self.fold_creases(to_fold, true, window, cx);
18495    }
18496
18497    pub fn fold_at(
18498        &mut self,
18499        buffer_row: MultiBufferRow,
18500        window: &mut Window,
18501        cx: &mut Context<Self>,
18502    ) {
18503        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18504
18505        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
18506            let autoscroll = self
18507                .selections
18508                .all::<Point>(&display_map)
18509                .iter()
18510                .any(|selection| crease.range().overlaps(&selection.range()));
18511
18512            self.fold_creases(vec![crease], autoscroll, window, cx);
18513        }
18514    }
18515
18516    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
18517        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18518            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18519            let buffer = display_map.buffer_snapshot();
18520            let selections = self.selections.all::<Point>(&display_map);
18521            let ranges = selections
18522                .iter()
18523                .map(|s| {
18524                    let range = s.display_range(&display_map).sorted();
18525                    let mut start = range.start.to_point(&display_map);
18526                    let mut end = range.end.to_point(&display_map);
18527                    start.column = 0;
18528                    end.column = buffer.line_len(MultiBufferRow(end.row));
18529                    start..end
18530                })
18531                .collect::<Vec<_>>();
18532
18533            self.unfold_ranges(&ranges, true, true, cx);
18534        } else {
18535            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18536            let buffer_ids = self
18537                .selections
18538                .disjoint_anchor_ranges()
18539                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18540                .collect::<HashSet<_>>();
18541            for buffer_id in buffer_ids {
18542                self.unfold_buffer(buffer_id, cx);
18543            }
18544        }
18545    }
18546
18547    pub fn unfold_recursive(
18548        &mut self,
18549        _: &UnfoldRecursive,
18550        _window: &mut Window,
18551        cx: &mut Context<Self>,
18552    ) {
18553        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18554        let selections = self.selections.all::<Point>(&display_map);
18555        let ranges = selections
18556            .iter()
18557            .map(|s| {
18558                let mut range = s.display_range(&display_map).sorted();
18559                *range.start.column_mut() = 0;
18560                *range.end.column_mut() = display_map.line_len(range.end.row());
18561                let start = range.start.to_point(&display_map);
18562                let end = range.end.to_point(&display_map);
18563                start..end
18564            })
18565            .collect::<Vec<_>>();
18566
18567        self.unfold_ranges(&ranges, true, true, cx);
18568    }
18569
18570    pub fn unfold_at(
18571        &mut self,
18572        buffer_row: MultiBufferRow,
18573        _window: &mut Window,
18574        cx: &mut Context<Self>,
18575    ) {
18576        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18577
18578        let intersection_range = Point::new(buffer_row.0, 0)
18579            ..Point::new(
18580                buffer_row.0,
18581                display_map.buffer_snapshot().line_len(buffer_row),
18582            );
18583
18584        let autoscroll = self
18585            .selections
18586            .all::<Point>(&display_map)
18587            .iter()
18588            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
18589
18590        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
18591    }
18592
18593    pub fn unfold_all(
18594        &mut self,
18595        _: &actions::UnfoldAll,
18596        _window: &mut Window,
18597        cx: &mut Context<Self>,
18598    ) {
18599        if self.buffer.read(cx).is_singleton() {
18600            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18601            self.unfold_ranges(&[0..display_map.buffer_snapshot().len()], true, true, cx);
18602        } else {
18603            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
18604                editor
18605                    .update(cx, |editor, cx| {
18606                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18607                            editor.unfold_buffer(buffer_id, cx);
18608                        }
18609                    })
18610                    .ok();
18611            });
18612        }
18613    }
18614
18615    pub fn fold_selected_ranges(
18616        &mut self,
18617        _: &FoldSelectedRanges,
18618        window: &mut Window,
18619        cx: &mut Context<Self>,
18620    ) {
18621        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18622        let selections = self.selections.all_adjusted(&display_map);
18623        let ranges = selections
18624            .into_iter()
18625            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
18626            .collect::<Vec<_>>();
18627        self.fold_creases(ranges, true, window, cx);
18628    }
18629
18630    pub fn fold_ranges<T: ToOffset + Clone>(
18631        &mut self,
18632        ranges: Vec<Range<T>>,
18633        auto_scroll: bool,
18634        window: &mut Window,
18635        cx: &mut Context<Self>,
18636    ) {
18637        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18638        let ranges = ranges
18639            .into_iter()
18640            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
18641            .collect::<Vec<_>>();
18642        self.fold_creases(ranges, auto_scroll, window, cx);
18643    }
18644
18645    pub fn fold_creases<T: ToOffset + Clone>(
18646        &mut self,
18647        creases: Vec<Crease<T>>,
18648        auto_scroll: bool,
18649        _window: &mut Window,
18650        cx: &mut Context<Self>,
18651    ) {
18652        if creases.is_empty() {
18653            return;
18654        }
18655
18656        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
18657
18658        if auto_scroll {
18659            self.request_autoscroll(Autoscroll::fit(), cx);
18660        }
18661
18662        cx.notify();
18663
18664        self.scrollbar_marker_state.dirty = true;
18665        self.folds_did_change(cx);
18666    }
18667
18668    /// Removes any folds whose ranges intersect any of the given ranges.
18669    pub fn unfold_ranges<T: ToOffset + Clone>(
18670        &mut self,
18671        ranges: &[Range<T>],
18672        inclusive: bool,
18673        auto_scroll: bool,
18674        cx: &mut Context<Self>,
18675    ) {
18676        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18677            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
18678        });
18679        self.folds_did_change(cx);
18680    }
18681
18682    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18683        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
18684            return;
18685        }
18686        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18687        self.display_map.update(cx, |display_map, cx| {
18688            display_map.fold_buffers([buffer_id], cx)
18689        });
18690        cx.emit(EditorEvent::BufferFoldToggled {
18691            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
18692            folded: true,
18693        });
18694        cx.notify();
18695    }
18696
18697    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18698        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
18699            return;
18700        }
18701        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18702        self.display_map.update(cx, |display_map, cx| {
18703            display_map.unfold_buffers([buffer_id], cx);
18704        });
18705        cx.emit(EditorEvent::BufferFoldToggled {
18706            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
18707            folded: false,
18708        });
18709        cx.notify();
18710    }
18711
18712    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
18713        self.display_map.read(cx).is_buffer_folded(buffer)
18714    }
18715
18716    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
18717        self.display_map.read(cx).folded_buffers()
18718    }
18719
18720    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18721        self.display_map.update(cx, |display_map, cx| {
18722            display_map.disable_header_for_buffer(buffer_id, cx);
18723        });
18724        cx.notify();
18725    }
18726
18727    /// Removes any folds with the given ranges.
18728    pub fn remove_folds_with_type<T: ToOffset + Clone>(
18729        &mut self,
18730        ranges: &[Range<T>],
18731        type_id: TypeId,
18732        auto_scroll: bool,
18733        cx: &mut Context<Self>,
18734    ) {
18735        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18736            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
18737        });
18738        self.folds_did_change(cx);
18739    }
18740
18741    fn remove_folds_with<T: ToOffset + Clone>(
18742        &mut self,
18743        ranges: &[Range<T>],
18744        auto_scroll: bool,
18745        cx: &mut Context<Self>,
18746        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
18747    ) {
18748        if ranges.is_empty() {
18749            return;
18750        }
18751
18752        let mut buffers_affected = HashSet::default();
18753        let multi_buffer = self.buffer().read(cx);
18754        for range in ranges {
18755            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
18756                buffers_affected.insert(buffer.read(cx).remote_id());
18757            };
18758        }
18759
18760        self.display_map.update(cx, update);
18761
18762        if auto_scroll {
18763            self.request_autoscroll(Autoscroll::fit(), cx);
18764        }
18765
18766        cx.notify();
18767        self.scrollbar_marker_state.dirty = true;
18768        self.active_indent_guides_state.dirty = true;
18769    }
18770
18771    pub fn update_renderer_widths(
18772        &mut self,
18773        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
18774        cx: &mut Context<Self>,
18775    ) -> bool {
18776        self.display_map
18777            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
18778    }
18779
18780    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
18781        self.display_map.read(cx).fold_placeholder.clone()
18782    }
18783
18784    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
18785        self.buffer.update(cx, |buffer, cx| {
18786            buffer.set_all_diff_hunks_expanded(cx);
18787        });
18788    }
18789
18790    pub fn expand_all_diff_hunks(
18791        &mut self,
18792        _: &ExpandAllDiffHunks,
18793        _window: &mut Window,
18794        cx: &mut Context<Self>,
18795    ) {
18796        self.buffer.update(cx, |buffer, cx| {
18797            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
18798        });
18799    }
18800
18801    pub fn collapse_all_diff_hunks(
18802        &mut self,
18803        _: &CollapseAllDiffHunks,
18804        _window: &mut Window,
18805        cx: &mut Context<Self>,
18806    ) {
18807        self.buffer.update(cx, |buffer, cx| {
18808            buffer.collapse_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
18809        });
18810    }
18811
18812    pub fn toggle_selected_diff_hunks(
18813        &mut self,
18814        _: &ToggleSelectedDiffHunks,
18815        _window: &mut Window,
18816        cx: &mut Context<Self>,
18817    ) {
18818        let ranges: Vec<_> = self
18819            .selections
18820            .disjoint_anchors()
18821            .iter()
18822            .map(|s| s.range())
18823            .collect();
18824        self.toggle_diff_hunks_in_ranges(ranges, cx);
18825    }
18826
18827    pub fn diff_hunks_in_ranges<'a>(
18828        &'a self,
18829        ranges: &'a [Range<Anchor>],
18830        buffer: &'a MultiBufferSnapshot,
18831    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
18832        ranges.iter().flat_map(move |range| {
18833            let end_excerpt_id = range.end.excerpt_id;
18834            let range = range.to_point(buffer);
18835            let mut peek_end = range.end;
18836            if range.end.row < buffer.max_row().0 {
18837                peek_end = Point::new(range.end.row + 1, 0);
18838            }
18839            buffer
18840                .diff_hunks_in_range(range.start..peek_end)
18841                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
18842        })
18843    }
18844
18845    pub fn has_stageable_diff_hunks_in_ranges(
18846        &self,
18847        ranges: &[Range<Anchor>],
18848        snapshot: &MultiBufferSnapshot,
18849    ) -> bool {
18850        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
18851        hunks.any(|hunk| hunk.status().has_secondary_hunk())
18852    }
18853
18854    pub fn toggle_staged_selected_diff_hunks(
18855        &mut self,
18856        _: &::git::ToggleStaged,
18857        _: &mut Window,
18858        cx: &mut Context<Self>,
18859    ) {
18860        let snapshot = self.buffer.read(cx).snapshot(cx);
18861        let ranges: Vec<_> = self
18862            .selections
18863            .disjoint_anchors()
18864            .iter()
18865            .map(|s| s.range())
18866            .collect();
18867        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
18868        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18869    }
18870
18871    pub fn set_render_diff_hunk_controls(
18872        &mut self,
18873        render_diff_hunk_controls: RenderDiffHunkControlsFn,
18874        cx: &mut Context<Self>,
18875    ) {
18876        self.render_diff_hunk_controls = render_diff_hunk_controls;
18877        cx.notify();
18878    }
18879
18880    pub fn stage_and_next(
18881        &mut self,
18882        _: &::git::StageAndNext,
18883        window: &mut Window,
18884        cx: &mut Context<Self>,
18885    ) {
18886        self.do_stage_or_unstage_and_next(true, window, cx);
18887    }
18888
18889    pub fn unstage_and_next(
18890        &mut self,
18891        _: &::git::UnstageAndNext,
18892        window: &mut Window,
18893        cx: &mut Context<Self>,
18894    ) {
18895        self.do_stage_or_unstage_and_next(false, window, cx);
18896    }
18897
18898    pub fn stage_or_unstage_diff_hunks(
18899        &mut self,
18900        stage: bool,
18901        ranges: Vec<Range<Anchor>>,
18902        cx: &mut Context<Self>,
18903    ) {
18904        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
18905        cx.spawn(async move |this, cx| {
18906            task.await?;
18907            this.update(cx, |this, cx| {
18908                let snapshot = this.buffer.read(cx).snapshot(cx);
18909                let chunk_by = this
18910                    .diff_hunks_in_ranges(&ranges, &snapshot)
18911                    .chunk_by(|hunk| hunk.buffer_id);
18912                for (buffer_id, hunks) in &chunk_by {
18913                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
18914                }
18915            })
18916        })
18917        .detach_and_log_err(cx);
18918    }
18919
18920    fn save_buffers_for_ranges_if_needed(
18921        &mut self,
18922        ranges: &[Range<Anchor>],
18923        cx: &mut Context<Editor>,
18924    ) -> Task<Result<()>> {
18925        let multibuffer = self.buffer.read(cx);
18926        let snapshot = multibuffer.read(cx);
18927        let buffer_ids: HashSet<_> = ranges
18928            .iter()
18929            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
18930            .collect();
18931        drop(snapshot);
18932
18933        let mut buffers = HashSet::default();
18934        for buffer_id in buffer_ids {
18935            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
18936                let buffer = buffer_entity.read(cx);
18937                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
18938                {
18939                    buffers.insert(buffer_entity);
18940                }
18941            }
18942        }
18943
18944        if let Some(project) = &self.project {
18945            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
18946        } else {
18947            Task::ready(Ok(()))
18948        }
18949    }
18950
18951    fn do_stage_or_unstage_and_next(
18952        &mut self,
18953        stage: bool,
18954        window: &mut Window,
18955        cx: &mut Context<Self>,
18956    ) {
18957        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
18958
18959        if ranges.iter().any(|range| range.start != range.end) {
18960            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18961            return;
18962        }
18963
18964        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18965        let snapshot = self.snapshot(window, cx);
18966        let position = self
18967            .selections
18968            .newest::<Point>(&snapshot.display_snapshot)
18969            .head();
18970        let mut row = snapshot
18971            .buffer_snapshot()
18972            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
18973            .find(|hunk| hunk.row_range.start.0 > position.row)
18974            .map(|hunk| hunk.row_range.start);
18975
18976        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
18977        // Outside of the project diff editor, wrap around to the beginning.
18978        if !all_diff_hunks_expanded {
18979            row = row.or_else(|| {
18980                snapshot
18981                    .buffer_snapshot()
18982                    .diff_hunks_in_range(Point::zero()..position)
18983                    .find(|hunk| hunk.row_range.end.0 < position.row)
18984                    .map(|hunk| hunk.row_range.start)
18985            });
18986        }
18987
18988        if let Some(row) = row {
18989            let destination = Point::new(row.0, 0);
18990            let autoscroll = Autoscroll::center();
18991
18992            self.unfold_ranges(&[destination..destination], false, false, cx);
18993            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
18994                s.select_ranges([destination..destination]);
18995            });
18996        }
18997    }
18998
18999    fn do_stage_or_unstage(
19000        &self,
19001        stage: bool,
19002        buffer_id: BufferId,
19003        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
19004        cx: &mut App,
19005    ) -> Option<()> {
19006        let project = self.project()?;
19007        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
19008        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
19009        let buffer_snapshot = buffer.read(cx).snapshot();
19010        let file_exists = buffer_snapshot
19011            .file()
19012            .is_some_and(|file| file.disk_state().exists());
19013        diff.update(cx, |diff, cx| {
19014            diff.stage_or_unstage_hunks(
19015                stage,
19016                &hunks
19017                    .map(|hunk| buffer_diff::DiffHunk {
19018                        buffer_range: hunk.buffer_range,
19019                        diff_base_byte_range: hunk.diff_base_byte_range,
19020                        secondary_status: hunk.secondary_status,
19021                        range: Point::zero()..Point::zero(), // unused
19022                    })
19023                    .collect::<Vec<_>>(),
19024                &buffer_snapshot,
19025                file_exists,
19026                cx,
19027            )
19028        });
19029        None
19030    }
19031
19032    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
19033        let ranges: Vec<_> = self
19034            .selections
19035            .disjoint_anchors()
19036            .iter()
19037            .map(|s| s.range())
19038            .collect();
19039        self.buffer
19040            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
19041    }
19042
19043    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
19044        self.buffer.update(cx, |buffer, cx| {
19045            let ranges = vec![Anchor::min()..Anchor::max()];
19046            if !buffer.all_diff_hunks_expanded()
19047                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
19048            {
19049                buffer.collapse_diff_hunks(ranges, cx);
19050                true
19051            } else {
19052                false
19053            }
19054        })
19055    }
19056
19057    fn toggle_diff_hunks_in_ranges(
19058        &mut self,
19059        ranges: Vec<Range<Anchor>>,
19060        cx: &mut Context<Editor>,
19061    ) {
19062        self.buffer.update(cx, |buffer, cx| {
19063            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
19064            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
19065        })
19066    }
19067
19068    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
19069        self.buffer.update(cx, |buffer, cx| {
19070            let snapshot = buffer.snapshot(cx);
19071            let excerpt_id = range.end.excerpt_id;
19072            let point_range = range.to_point(&snapshot);
19073            let expand = !buffer.single_hunk_is_expanded(range, cx);
19074            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
19075        })
19076    }
19077
19078    pub(crate) fn apply_all_diff_hunks(
19079        &mut self,
19080        _: &ApplyAllDiffHunks,
19081        window: &mut Window,
19082        cx: &mut Context<Self>,
19083    ) {
19084        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19085
19086        let buffers = self.buffer.read(cx).all_buffers();
19087        for branch_buffer in buffers {
19088            branch_buffer.update(cx, |branch_buffer, cx| {
19089                branch_buffer.merge_into_base(Vec::new(), cx);
19090            });
19091        }
19092
19093        if let Some(project) = self.project.clone() {
19094            self.save(
19095                SaveOptions {
19096                    format: true,
19097                    autosave: false,
19098                },
19099                project,
19100                window,
19101                cx,
19102            )
19103            .detach_and_log_err(cx);
19104        }
19105    }
19106
19107    pub(crate) fn apply_selected_diff_hunks(
19108        &mut self,
19109        _: &ApplyDiffHunk,
19110        window: &mut Window,
19111        cx: &mut Context<Self>,
19112    ) {
19113        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19114        let snapshot = self.snapshot(window, cx);
19115        let hunks = snapshot.hunks_for_ranges(
19116            self.selections
19117                .all(&snapshot.display_snapshot)
19118                .into_iter()
19119                .map(|selection| selection.range()),
19120        );
19121        let mut ranges_by_buffer = HashMap::default();
19122        self.transact(window, cx, |editor, _window, cx| {
19123            for hunk in hunks {
19124                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
19125                    ranges_by_buffer
19126                        .entry(buffer.clone())
19127                        .or_insert_with(Vec::new)
19128                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
19129                }
19130            }
19131
19132            for (buffer, ranges) in ranges_by_buffer {
19133                buffer.update(cx, |buffer, cx| {
19134                    buffer.merge_into_base(ranges, cx);
19135                });
19136            }
19137        });
19138
19139        if let Some(project) = self.project.clone() {
19140            self.save(
19141                SaveOptions {
19142                    format: true,
19143                    autosave: false,
19144                },
19145                project,
19146                window,
19147                cx,
19148            )
19149            .detach_and_log_err(cx);
19150        }
19151    }
19152
19153    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
19154        if hovered != self.gutter_hovered {
19155            self.gutter_hovered = hovered;
19156            cx.notify();
19157        }
19158    }
19159
19160    pub fn insert_blocks(
19161        &mut self,
19162        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
19163        autoscroll: Option<Autoscroll>,
19164        cx: &mut Context<Self>,
19165    ) -> Vec<CustomBlockId> {
19166        let blocks = self
19167            .display_map
19168            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
19169        if let Some(autoscroll) = autoscroll {
19170            self.request_autoscroll(autoscroll, cx);
19171        }
19172        cx.notify();
19173        blocks
19174    }
19175
19176    pub fn resize_blocks(
19177        &mut self,
19178        heights: HashMap<CustomBlockId, u32>,
19179        autoscroll: Option<Autoscroll>,
19180        cx: &mut Context<Self>,
19181    ) {
19182        self.display_map
19183            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
19184        if let Some(autoscroll) = autoscroll {
19185            self.request_autoscroll(autoscroll, cx);
19186        }
19187        cx.notify();
19188    }
19189
19190    pub fn replace_blocks(
19191        &mut self,
19192        renderers: HashMap<CustomBlockId, RenderBlock>,
19193        autoscroll: Option<Autoscroll>,
19194        cx: &mut Context<Self>,
19195    ) {
19196        self.display_map
19197            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
19198        if let Some(autoscroll) = autoscroll {
19199            self.request_autoscroll(autoscroll, cx);
19200        }
19201        cx.notify();
19202    }
19203
19204    pub fn remove_blocks(
19205        &mut self,
19206        block_ids: HashSet<CustomBlockId>,
19207        autoscroll: Option<Autoscroll>,
19208        cx: &mut Context<Self>,
19209    ) {
19210        self.display_map.update(cx, |display_map, cx| {
19211            display_map.remove_blocks(block_ids, cx)
19212        });
19213        if let Some(autoscroll) = autoscroll {
19214            self.request_autoscroll(autoscroll, cx);
19215        }
19216        cx.notify();
19217    }
19218
19219    pub fn row_for_block(
19220        &self,
19221        block_id: CustomBlockId,
19222        cx: &mut Context<Self>,
19223    ) -> Option<DisplayRow> {
19224        self.display_map
19225            .update(cx, |map, cx| map.row_for_block(block_id, cx))
19226    }
19227
19228    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
19229        self.focused_block = Some(focused_block);
19230    }
19231
19232    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
19233        self.focused_block.take()
19234    }
19235
19236    pub fn insert_creases(
19237        &mut self,
19238        creases: impl IntoIterator<Item = Crease<Anchor>>,
19239        cx: &mut Context<Self>,
19240    ) -> Vec<CreaseId> {
19241        self.display_map
19242            .update(cx, |map, cx| map.insert_creases(creases, cx))
19243    }
19244
19245    pub fn remove_creases(
19246        &mut self,
19247        ids: impl IntoIterator<Item = CreaseId>,
19248        cx: &mut Context<Self>,
19249    ) -> Vec<(CreaseId, Range<Anchor>)> {
19250        self.display_map
19251            .update(cx, |map, cx| map.remove_creases(ids, cx))
19252    }
19253
19254    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
19255        self.display_map
19256            .update(cx, |map, cx| map.snapshot(cx))
19257            .longest_row()
19258    }
19259
19260    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
19261        self.display_map
19262            .update(cx, |map, cx| map.snapshot(cx))
19263            .max_point()
19264    }
19265
19266    pub fn text(&self, cx: &App) -> String {
19267        self.buffer.read(cx).read(cx).text()
19268    }
19269
19270    pub fn is_empty(&self, cx: &App) -> bool {
19271        self.buffer.read(cx).read(cx).is_empty()
19272    }
19273
19274    pub fn text_option(&self, cx: &App) -> Option<String> {
19275        let text = self.text(cx);
19276        let text = text.trim();
19277
19278        if text.is_empty() {
19279            return None;
19280        }
19281
19282        Some(text.to_string())
19283    }
19284
19285    pub fn set_text(
19286        &mut self,
19287        text: impl Into<Arc<str>>,
19288        window: &mut Window,
19289        cx: &mut Context<Self>,
19290    ) {
19291        self.transact(window, cx, |this, _, cx| {
19292            this.buffer
19293                .read(cx)
19294                .as_singleton()
19295                .expect("you can only call set_text on editors for singleton buffers")
19296                .update(cx, |buffer, cx| buffer.set_text(text, cx));
19297        });
19298    }
19299
19300    pub fn display_text(&self, cx: &mut App) -> String {
19301        self.display_map
19302            .update(cx, |map, cx| map.snapshot(cx))
19303            .text()
19304    }
19305
19306    fn create_minimap(
19307        &self,
19308        minimap_settings: MinimapSettings,
19309        window: &mut Window,
19310        cx: &mut Context<Self>,
19311    ) -> Option<Entity<Self>> {
19312        (minimap_settings.minimap_enabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton)
19313            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
19314    }
19315
19316    fn initialize_new_minimap(
19317        &self,
19318        minimap_settings: MinimapSettings,
19319        window: &mut Window,
19320        cx: &mut Context<Self>,
19321    ) -> Entity<Self> {
19322        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
19323
19324        let mut minimap = Editor::new_internal(
19325            EditorMode::Minimap {
19326                parent: cx.weak_entity(),
19327            },
19328            self.buffer.clone(),
19329            None,
19330            Some(self.display_map.clone()),
19331            window,
19332            cx,
19333        );
19334        minimap.scroll_manager.clone_state(&self.scroll_manager);
19335        minimap.set_text_style_refinement(TextStyleRefinement {
19336            font_size: Some(MINIMAP_FONT_SIZE),
19337            font_weight: Some(MINIMAP_FONT_WEIGHT),
19338            ..Default::default()
19339        });
19340        minimap.update_minimap_configuration(minimap_settings, cx);
19341        cx.new(|_| minimap)
19342    }
19343
19344    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
19345        let current_line_highlight = minimap_settings
19346            .current_line_highlight
19347            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
19348        self.set_current_line_highlight(Some(current_line_highlight));
19349    }
19350
19351    pub fn minimap(&self) -> Option<&Entity<Self>> {
19352        self.minimap
19353            .as_ref()
19354            .filter(|_| self.minimap_visibility.visible())
19355    }
19356
19357    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
19358        let mut wrap_guides = smallvec![];
19359
19360        if self.show_wrap_guides == Some(false) {
19361            return wrap_guides;
19362        }
19363
19364        let settings = self.buffer.read(cx).language_settings(cx);
19365        if settings.show_wrap_guides {
19366            match self.soft_wrap_mode(cx) {
19367                SoftWrap::Column(soft_wrap) => {
19368                    wrap_guides.push((soft_wrap as usize, true));
19369                }
19370                SoftWrap::Bounded(soft_wrap) => {
19371                    wrap_guides.push((soft_wrap as usize, true));
19372                }
19373                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
19374            }
19375            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
19376        }
19377
19378        wrap_guides
19379    }
19380
19381    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
19382        let settings = self.buffer.read(cx).language_settings(cx);
19383        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
19384        match mode {
19385            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
19386                SoftWrap::None
19387            }
19388            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
19389            language_settings::SoftWrap::PreferredLineLength => {
19390                SoftWrap::Column(settings.preferred_line_length)
19391            }
19392            language_settings::SoftWrap::Bounded => {
19393                SoftWrap::Bounded(settings.preferred_line_length)
19394            }
19395        }
19396    }
19397
19398    pub fn set_soft_wrap_mode(
19399        &mut self,
19400        mode: language_settings::SoftWrap,
19401
19402        cx: &mut Context<Self>,
19403    ) {
19404        self.soft_wrap_mode_override = Some(mode);
19405        cx.notify();
19406    }
19407
19408    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
19409        self.hard_wrap = hard_wrap;
19410        cx.notify();
19411    }
19412
19413    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
19414        self.text_style_refinement = Some(style);
19415    }
19416
19417    /// called by the Element so we know what style we were most recently rendered with.
19418    pub fn set_style(&mut self, style: EditorStyle, window: &mut Window, cx: &mut Context<Self>) {
19419        // We intentionally do not inform the display map about the minimap style
19420        // so that wrapping is not recalculated and stays consistent for the editor
19421        // and its linked minimap.
19422        if !self.mode.is_minimap() {
19423            let font = style.text.font();
19424            let font_size = style.text.font_size.to_pixels(window.rem_size());
19425            let display_map = self
19426                .placeholder_display_map
19427                .as_ref()
19428                .filter(|_| self.is_empty(cx))
19429                .unwrap_or(&self.display_map);
19430
19431            display_map.update(cx, |map, cx| map.set_font(font, font_size, cx));
19432        }
19433        self.style = Some(style);
19434    }
19435
19436    pub fn style(&self) -> Option<&EditorStyle> {
19437        self.style.as_ref()
19438    }
19439
19440    // Called by the element. This method is not designed to be called outside of the editor
19441    // element's layout code because it does not notify when rewrapping is computed synchronously.
19442    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
19443        if self.is_empty(cx) {
19444            self.placeholder_display_map
19445                .as_ref()
19446                .map_or(false, |display_map| {
19447                    display_map.update(cx, |map, cx| map.set_wrap_width(width, cx))
19448                })
19449        } else {
19450            self.display_map
19451                .update(cx, |map, cx| map.set_wrap_width(width, cx))
19452        }
19453    }
19454
19455    pub fn set_soft_wrap(&mut self) {
19456        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
19457    }
19458
19459    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
19460        if self.soft_wrap_mode_override.is_some() {
19461            self.soft_wrap_mode_override.take();
19462        } else {
19463            let soft_wrap = match self.soft_wrap_mode(cx) {
19464                SoftWrap::GitDiff => return,
19465                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
19466                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
19467                    language_settings::SoftWrap::None
19468                }
19469            };
19470            self.soft_wrap_mode_override = Some(soft_wrap);
19471        }
19472        cx.notify();
19473    }
19474
19475    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
19476        let Some(workspace) = self.workspace() else {
19477            return;
19478        };
19479        let fs = workspace.read(cx).app_state().fs.clone();
19480        let current_show = TabBarSettings::get_global(cx).show;
19481        update_settings_file(fs, cx, move |setting, _| {
19482            setting.tab_bar.get_or_insert_default().show = Some(!current_show);
19483        });
19484    }
19485
19486    pub fn toggle_indent_guides(
19487        &mut self,
19488        _: &ToggleIndentGuides,
19489        _: &mut Window,
19490        cx: &mut Context<Self>,
19491    ) {
19492        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
19493            self.buffer
19494                .read(cx)
19495                .language_settings(cx)
19496                .indent_guides
19497                .enabled
19498        });
19499        self.show_indent_guides = Some(!currently_enabled);
19500        cx.notify();
19501    }
19502
19503    fn should_show_indent_guides(&self) -> Option<bool> {
19504        self.show_indent_guides
19505    }
19506
19507    pub fn toggle_line_numbers(
19508        &mut self,
19509        _: &ToggleLineNumbers,
19510        _: &mut Window,
19511        cx: &mut Context<Self>,
19512    ) {
19513        let mut editor_settings = EditorSettings::get_global(cx).clone();
19514        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
19515        EditorSettings::override_global(editor_settings, cx);
19516    }
19517
19518    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
19519        if let Some(show_line_numbers) = self.show_line_numbers {
19520            return show_line_numbers;
19521        }
19522        EditorSettings::get_global(cx).gutter.line_numbers
19523    }
19524
19525    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
19526        self.use_relative_line_numbers
19527            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
19528    }
19529
19530    pub fn toggle_relative_line_numbers(
19531        &mut self,
19532        _: &ToggleRelativeLineNumbers,
19533        _: &mut Window,
19534        cx: &mut Context<Self>,
19535    ) {
19536        let is_relative = self.should_use_relative_line_numbers(cx);
19537        self.set_relative_line_number(Some(!is_relative), cx)
19538    }
19539
19540    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
19541        self.use_relative_line_numbers = is_relative;
19542        cx.notify();
19543    }
19544
19545    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
19546        self.show_gutter = show_gutter;
19547        cx.notify();
19548    }
19549
19550    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
19551        self.show_scrollbars = ScrollbarAxes {
19552            horizontal: show,
19553            vertical: show,
19554        };
19555        cx.notify();
19556    }
19557
19558    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19559        self.show_scrollbars.vertical = show;
19560        cx.notify();
19561    }
19562
19563    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19564        self.show_scrollbars.horizontal = show;
19565        cx.notify();
19566    }
19567
19568    pub fn set_minimap_visibility(
19569        &mut self,
19570        minimap_visibility: MinimapVisibility,
19571        window: &mut Window,
19572        cx: &mut Context<Self>,
19573    ) {
19574        if self.minimap_visibility != minimap_visibility {
19575            if minimap_visibility.visible() && self.minimap.is_none() {
19576                let minimap_settings = EditorSettings::get_global(cx).minimap;
19577                self.minimap =
19578                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
19579            }
19580            self.minimap_visibility = minimap_visibility;
19581            cx.notify();
19582        }
19583    }
19584
19585    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19586        self.set_show_scrollbars(false, cx);
19587        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
19588    }
19589
19590    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19591        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
19592    }
19593
19594    /// Normally the text in full mode and auto height editors is padded on the
19595    /// left side by roughly half a character width for improved hit testing.
19596    ///
19597    /// Use this method to disable this for cases where this is not wanted (e.g.
19598    /// if you want to align the editor text with some other text above or below)
19599    /// or if you want to add this padding to single-line editors.
19600    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
19601        self.offset_content = offset_content;
19602        cx.notify();
19603    }
19604
19605    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
19606        self.show_line_numbers = Some(show_line_numbers);
19607        cx.notify();
19608    }
19609
19610    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
19611        self.disable_expand_excerpt_buttons = true;
19612        cx.notify();
19613    }
19614
19615    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
19616        self.show_git_diff_gutter = Some(show_git_diff_gutter);
19617        cx.notify();
19618    }
19619
19620    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
19621        self.show_code_actions = Some(show_code_actions);
19622        cx.notify();
19623    }
19624
19625    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
19626        self.show_runnables = Some(show_runnables);
19627        cx.notify();
19628    }
19629
19630    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
19631        self.show_breakpoints = Some(show_breakpoints);
19632        cx.notify();
19633    }
19634
19635    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
19636        if self.display_map.read(cx).masked != masked {
19637            self.display_map.update(cx, |map, _| map.masked = masked);
19638        }
19639        cx.notify()
19640    }
19641
19642    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
19643        self.show_wrap_guides = Some(show_wrap_guides);
19644        cx.notify();
19645    }
19646
19647    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
19648        self.show_indent_guides = Some(show_indent_guides);
19649        cx.notify();
19650    }
19651
19652    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
19653        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
19654            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
19655                && let Some(dir) = file.abs_path(cx).parent()
19656            {
19657                return Some(dir.to_owned());
19658            }
19659        }
19660
19661        None
19662    }
19663
19664    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
19665        self.active_excerpt(cx)?
19666            .1
19667            .read(cx)
19668            .file()
19669            .and_then(|f| f.as_local())
19670    }
19671
19672    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
19673        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19674            let buffer = buffer.read(cx);
19675            if let Some(project_path) = buffer.project_path(cx) {
19676                let project = self.project()?.read(cx);
19677                project.absolute_path(&project_path, cx)
19678            } else {
19679                buffer
19680                    .file()
19681                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
19682            }
19683        })
19684    }
19685
19686    pub fn reveal_in_finder(
19687        &mut self,
19688        _: &RevealInFileManager,
19689        _window: &mut Window,
19690        cx: &mut Context<Self>,
19691    ) {
19692        if let Some(target) = self.target_file(cx) {
19693            cx.reveal_path(&target.abs_path(cx));
19694        }
19695    }
19696
19697    pub fn copy_path(
19698        &mut self,
19699        _: &zed_actions::workspace::CopyPath,
19700        _window: &mut Window,
19701        cx: &mut Context<Self>,
19702    ) {
19703        if let Some(path) = self.target_file_abs_path(cx)
19704            && let Some(path) = path.to_str()
19705        {
19706            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19707        } else {
19708            cx.propagate();
19709        }
19710    }
19711
19712    pub fn copy_relative_path(
19713        &mut self,
19714        _: &zed_actions::workspace::CopyRelativePath,
19715        _window: &mut Window,
19716        cx: &mut Context<Self>,
19717    ) {
19718        if let Some(path) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19719            let project = self.project()?.read(cx);
19720            let path = buffer.read(cx).file()?.path();
19721            let path = path.display(project.path_style(cx));
19722            Some(path)
19723        }) {
19724            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19725        } else {
19726            cx.propagate();
19727        }
19728    }
19729
19730    /// Returns the project path for the editor's buffer, if any buffer is
19731    /// opened in the editor.
19732    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
19733        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
19734            buffer.read(cx).project_path(cx)
19735        } else {
19736            None
19737        }
19738    }
19739
19740    // Returns true if the editor handled a go-to-line request
19741    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
19742        maybe!({
19743            let breakpoint_store = self.breakpoint_store.as_ref()?;
19744
19745            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
19746            else {
19747                self.clear_row_highlights::<ActiveDebugLine>();
19748                return None;
19749            };
19750
19751            let position = active_stack_frame.position;
19752            let buffer_id = position.buffer_id?;
19753            let snapshot = self
19754                .project
19755                .as_ref()?
19756                .read(cx)
19757                .buffer_for_id(buffer_id, cx)?
19758                .read(cx)
19759                .snapshot();
19760
19761            let mut handled = false;
19762            for (id, ExcerptRange { context, .. }) in
19763                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
19764            {
19765                if context.start.cmp(&position, &snapshot).is_ge()
19766                    || context.end.cmp(&position, &snapshot).is_lt()
19767                {
19768                    continue;
19769                }
19770                let snapshot = self.buffer.read(cx).snapshot(cx);
19771                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
19772
19773                handled = true;
19774                self.clear_row_highlights::<ActiveDebugLine>();
19775
19776                self.go_to_line::<ActiveDebugLine>(
19777                    multibuffer_anchor,
19778                    Some(cx.theme().colors().editor_debugger_active_line_background),
19779                    window,
19780                    cx,
19781                );
19782
19783                cx.notify();
19784            }
19785
19786            handled.then_some(())
19787        })
19788        .is_some()
19789    }
19790
19791    pub fn copy_file_name_without_extension(
19792        &mut self,
19793        _: &CopyFileNameWithoutExtension,
19794        _: &mut Window,
19795        cx: &mut Context<Self>,
19796    ) {
19797        if let Some(file) = self.target_file(cx)
19798            && let Some(file_stem) = file.path().file_stem()
19799        {
19800            cx.write_to_clipboard(ClipboardItem::new_string(file_stem.to_string()));
19801        }
19802    }
19803
19804    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
19805        if let Some(file) = self.target_file(cx)
19806            && let Some(name) = file.path().file_name()
19807        {
19808            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
19809        }
19810    }
19811
19812    pub fn toggle_git_blame(
19813        &mut self,
19814        _: &::git::Blame,
19815        window: &mut Window,
19816        cx: &mut Context<Self>,
19817    ) {
19818        self.show_git_blame_gutter = !self.show_git_blame_gutter;
19819
19820        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
19821            self.start_git_blame(true, window, cx);
19822        }
19823
19824        cx.notify();
19825    }
19826
19827    pub fn toggle_git_blame_inline(
19828        &mut self,
19829        _: &ToggleGitBlameInline,
19830        window: &mut Window,
19831        cx: &mut Context<Self>,
19832    ) {
19833        self.toggle_git_blame_inline_internal(true, window, cx);
19834        cx.notify();
19835    }
19836
19837    pub fn open_git_blame_commit(
19838        &mut self,
19839        _: &OpenGitBlameCommit,
19840        window: &mut Window,
19841        cx: &mut Context<Self>,
19842    ) {
19843        self.open_git_blame_commit_internal(window, cx);
19844    }
19845
19846    fn open_git_blame_commit_internal(
19847        &mut self,
19848        window: &mut Window,
19849        cx: &mut Context<Self>,
19850    ) -> Option<()> {
19851        let blame = self.blame.as_ref()?;
19852        let snapshot = self.snapshot(window, cx);
19853        let cursor = self
19854            .selections
19855            .newest::<Point>(&snapshot.display_snapshot)
19856            .head();
19857        let (buffer, point, _) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)?;
19858        let (_, blame_entry) = blame
19859            .update(cx, |blame, cx| {
19860                blame
19861                    .blame_for_rows(
19862                        &[RowInfo {
19863                            buffer_id: Some(buffer.remote_id()),
19864                            buffer_row: Some(point.row),
19865                            ..Default::default()
19866                        }],
19867                        cx,
19868                    )
19869                    .next()
19870            })
19871            .flatten()?;
19872        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
19873        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
19874        let workspace = self.workspace()?.downgrade();
19875        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
19876        None
19877    }
19878
19879    pub fn git_blame_inline_enabled(&self) -> bool {
19880        self.git_blame_inline_enabled
19881    }
19882
19883    pub fn toggle_selection_menu(
19884        &mut self,
19885        _: &ToggleSelectionMenu,
19886        _: &mut Window,
19887        cx: &mut Context<Self>,
19888    ) {
19889        self.show_selection_menu = self
19890            .show_selection_menu
19891            .map(|show_selections_menu| !show_selections_menu)
19892            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
19893
19894        cx.notify();
19895    }
19896
19897    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
19898        self.show_selection_menu
19899            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
19900    }
19901
19902    fn start_git_blame(
19903        &mut self,
19904        user_triggered: bool,
19905        window: &mut Window,
19906        cx: &mut Context<Self>,
19907    ) {
19908        if let Some(project) = self.project() {
19909            if let Some(buffer) = self.buffer().read(cx).as_singleton()
19910                && buffer.read(cx).file().is_none()
19911            {
19912                return;
19913            }
19914
19915            let focused = self.focus_handle(cx).contains_focused(window, cx);
19916
19917            let project = project.clone();
19918            let blame = cx
19919                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
19920            self.blame_subscription =
19921                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
19922            self.blame = Some(blame);
19923        }
19924    }
19925
19926    fn toggle_git_blame_inline_internal(
19927        &mut self,
19928        user_triggered: bool,
19929        window: &mut Window,
19930        cx: &mut Context<Self>,
19931    ) {
19932        if self.git_blame_inline_enabled {
19933            self.git_blame_inline_enabled = false;
19934            self.show_git_blame_inline = false;
19935            self.show_git_blame_inline_delay_task.take();
19936        } else {
19937            self.git_blame_inline_enabled = true;
19938            self.start_git_blame_inline(user_triggered, window, cx);
19939        }
19940
19941        cx.notify();
19942    }
19943
19944    fn start_git_blame_inline(
19945        &mut self,
19946        user_triggered: bool,
19947        window: &mut Window,
19948        cx: &mut Context<Self>,
19949    ) {
19950        self.start_git_blame(user_triggered, window, cx);
19951
19952        if ProjectSettings::get_global(cx)
19953            .git
19954            .inline_blame_delay()
19955            .is_some()
19956        {
19957            self.start_inline_blame_timer(window, cx);
19958        } else {
19959            self.show_git_blame_inline = true
19960        }
19961    }
19962
19963    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
19964        self.blame.as_ref()
19965    }
19966
19967    pub fn show_git_blame_gutter(&self) -> bool {
19968        self.show_git_blame_gutter
19969    }
19970
19971    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
19972        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
19973    }
19974
19975    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
19976        self.show_git_blame_inline
19977            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
19978            && !self.newest_selection_head_on_empty_line(cx)
19979            && self.has_blame_entries(cx)
19980    }
19981
19982    fn has_blame_entries(&self, cx: &App) -> bool {
19983        self.blame()
19984            .is_some_and(|blame| blame.read(cx).has_generated_entries())
19985    }
19986
19987    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
19988        let cursor_anchor = self.selections.newest_anchor().head();
19989
19990        let snapshot = self.buffer.read(cx).snapshot(cx);
19991        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
19992
19993        snapshot.line_len(buffer_row) == 0
19994    }
19995
19996    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
19997        let buffer_and_selection = maybe!({
19998            let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
19999            let selection_range = selection.range();
20000
20001            let multi_buffer = self.buffer().read(cx);
20002            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
20003            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
20004
20005            let (buffer, range, _) = if selection.reversed {
20006                buffer_ranges.first()
20007            } else {
20008                buffer_ranges.last()
20009            }?;
20010
20011            let selection = text::ToPoint::to_point(&range.start, buffer).row
20012                ..text::ToPoint::to_point(&range.end, buffer).row;
20013            Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection))
20014        });
20015
20016        let Some((buffer, selection)) = buffer_and_selection else {
20017            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
20018        };
20019
20020        let Some(project) = self.project() else {
20021            return Task::ready(Err(anyhow!("editor does not have project")));
20022        };
20023
20024        project.update(cx, |project, cx| {
20025            project.get_permalink_to_line(&buffer, selection, cx)
20026        })
20027    }
20028
20029    pub fn copy_permalink_to_line(
20030        &mut self,
20031        _: &CopyPermalinkToLine,
20032        window: &mut Window,
20033        cx: &mut Context<Self>,
20034    ) {
20035        let permalink_task = self.get_permalink_to_line(cx);
20036        let workspace = self.workspace();
20037
20038        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
20039            Ok(permalink) => {
20040                cx.update(|_, cx| {
20041                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
20042                })
20043                .ok();
20044            }
20045            Err(err) => {
20046                let message = format!("Failed to copy permalink: {err}");
20047
20048                anyhow::Result::<()>::Err(err).log_err();
20049
20050                if let Some(workspace) = workspace {
20051                    workspace
20052                        .update_in(cx, |workspace, _, cx| {
20053                            struct CopyPermalinkToLine;
20054
20055                            workspace.show_toast(
20056                                Toast::new(
20057                                    NotificationId::unique::<CopyPermalinkToLine>(),
20058                                    message,
20059                                ),
20060                                cx,
20061                            )
20062                        })
20063                        .ok();
20064                }
20065            }
20066        })
20067        .detach();
20068    }
20069
20070    pub fn copy_file_location(
20071        &mut self,
20072        _: &CopyFileLocation,
20073        _: &mut Window,
20074        cx: &mut Context<Self>,
20075    ) {
20076        let selection = self
20077            .selections
20078            .newest::<Point>(&self.display_snapshot(cx))
20079            .start
20080            .row
20081            + 1;
20082        if let Some(file) = self.target_file(cx) {
20083            let path = file.path().display(file.path_style(cx));
20084            cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
20085        }
20086    }
20087
20088    pub fn open_permalink_to_line(
20089        &mut self,
20090        _: &OpenPermalinkToLine,
20091        window: &mut Window,
20092        cx: &mut Context<Self>,
20093    ) {
20094        let permalink_task = self.get_permalink_to_line(cx);
20095        let workspace = self.workspace();
20096
20097        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
20098            Ok(permalink) => {
20099                cx.update(|_, cx| {
20100                    cx.open_url(permalink.as_ref());
20101                })
20102                .ok();
20103            }
20104            Err(err) => {
20105                let message = format!("Failed to open permalink: {err}");
20106
20107                anyhow::Result::<()>::Err(err).log_err();
20108
20109                if let Some(workspace) = workspace {
20110                    workspace
20111                        .update(cx, |workspace, cx| {
20112                            struct OpenPermalinkToLine;
20113
20114                            workspace.show_toast(
20115                                Toast::new(
20116                                    NotificationId::unique::<OpenPermalinkToLine>(),
20117                                    message,
20118                                ),
20119                                cx,
20120                            )
20121                        })
20122                        .ok();
20123                }
20124            }
20125        })
20126        .detach();
20127    }
20128
20129    pub fn insert_uuid_v4(
20130        &mut self,
20131        _: &InsertUuidV4,
20132        window: &mut Window,
20133        cx: &mut Context<Self>,
20134    ) {
20135        self.insert_uuid(UuidVersion::V4, window, cx);
20136    }
20137
20138    pub fn insert_uuid_v7(
20139        &mut self,
20140        _: &InsertUuidV7,
20141        window: &mut Window,
20142        cx: &mut Context<Self>,
20143    ) {
20144        self.insert_uuid(UuidVersion::V7, window, cx);
20145    }
20146
20147    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
20148        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
20149        self.transact(window, cx, |this, window, cx| {
20150            let edits = this
20151                .selections
20152                .all::<Point>(&this.display_snapshot(cx))
20153                .into_iter()
20154                .map(|selection| {
20155                    let uuid = match version {
20156                        UuidVersion::V4 => uuid::Uuid::new_v4(),
20157                        UuidVersion::V7 => uuid::Uuid::now_v7(),
20158                    };
20159
20160                    (selection.range(), uuid.to_string())
20161                });
20162            this.edit(edits, cx);
20163            this.refresh_edit_prediction(true, false, window, cx);
20164        });
20165    }
20166
20167    pub fn open_selections_in_multibuffer(
20168        &mut self,
20169        _: &OpenSelectionsInMultibuffer,
20170        window: &mut Window,
20171        cx: &mut Context<Self>,
20172    ) {
20173        let multibuffer = self.buffer.read(cx);
20174
20175        let Some(buffer) = multibuffer.as_singleton() else {
20176            return;
20177        };
20178
20179        let Some(workspace) = self.workspace() else {
20180            return;
20181        };
20182
20183        let title = multibuffer.title(cx).to_string();
20184
20185        let locations = self
20186            .selections
20187            .all_anchors(cx)
20188            .iter()
20189            .map(|selection| {
20190                (
20191                    buffer.clone(),
20192                    (selection.start.text_anchor..selection.end.text_anchor)
20193                        .to_point(buffer.read(cx)),
20194                )
20195            })
20196            .into_group_map();
20197
20198        cx.spawn_in(window, async move |_, cx| {
20199            workspace.update_in(cx, |workspace, window, cx| {
20200                Self::open_locations_in_multibuffer(
20201                    workspace,
20202                    locations,
20203                    format!("Selections for '{title}'"),
20204                    false,
20205                    MultibufferSelectionMode::All,
20206                    window,
20207                    cx,
20208                );
20209            })
20210        })
20211        .detach();
20212    }
20213
20214    /// Adds a row highlight for the given range. If a row has multiple highlights, the
20215    /// last highlight added will be used.
20216    ///
20217    /// If the range ends at the beginning of a line, then that line will not be highlighted.
20218    pub fn highlight_rows<T: 'static>(
20219        &mut self,
20220        range: Range<Anchor>,
20221        color: Hsla,
20222        options: RowHighlightOptions,
20223        cx: &mut Context<Self>,
20224    ) {
20225        let snapshot = self.buffer().read(cx).snapshot(cx);
20226        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20227        let ix = row_highlights.binary_search_by(|highlight| {
20228            Ordering::Equal
20229                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
20230                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
20231        });
20232
20233        if let Err(mut ix) = ix {
20234            let index = post_inc(&mut self.highlight_order);
20235
20236            // If this range intersects with the preceding highlight, then merge it with
20237            // the preceding highlight. Otherwise insert a new highlight.
20238            let mut merged = false;
20239            if ix > 0 {
20240                let prev_highlight = &mut row_highlights[ix - 1];
20241                if prev_highlight
20242                    .range
20243                    .end
20244                    .cmp(&range.start, &snapshot)
20245                    .is_ge()
20246                {
20247                    ix -= 1;
20248                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
20249                        prev_highlight.range.end = range.end;
20250                    }
20251                    merged = true;
20252                    prev_highlight.index = index;
20253                    prev_highlight.color = color;
20254                    prev_highlight.options = options;
20255                }
20256            }
20257
20258            if !merged {
20259                row_highlights.insert(
20260                    ix,
20261                    RowHighlight {
20262                        range,
20263                        index,
20264                        color,
20265                        options,
20266                        type_id: TypeId::of::<T>(),
20267                    },
20268                );
20269            }
20270
20271            // If any of the following highlights intersect with this one, merge them.
20272            while let Some(next_highlight) = row_highlights.get(ix + 1) {
20273                let highlight = &row_highlights[ix];
20274                if next_highlight
20275                    .range
20276                    .start
20277                    .cmp(&highlight.range.end, &snapshot)
20278                    .is_le()
20279                {
20280                    if next_highlight
20281                        .range
20282                        .end
20283                        .cmp(&highlight.range.end, &snapshot)
20284                        .is_gt()
20285                    {
20286                        row_highlights[ix].range.end = next_highlight.range.end;
20287                    }
20288                    row_highlights.remove(ix + 1);
20289                } else {
20290                    break;
20291                }
20292            }
20293        }
20294    }
20295
20296    /// Remove any highlighted row ranges of the given type that intersect the
20297    /// given ranges.
20298    pub fn remove_highlighted_rows<T: 'static>(
20299        &mut self,
20300        ranges_to_remove: Vec<Range<Anchor>>,
20301        cx: &mut Context<Self>,
20302    ) {
20303        let snapshot = self.buffer().read(cx).snapshot(cx);
20304        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20305        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20306        row_highlights.retain(|highlight| {
20307            while let Some(range_to_remove) = ranges_to_remove.peek() {
20308                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
20309                    Ordering::Less | Ordering::Equal => {
20310                        ranges_to_remove.next();
20311                    }
20312                    Ordering::Greater => {
20313                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
20314                            Ordering::Less | Ordering::Equal => {
20315                                return false;
20316                            }
20317                            Ordering::Greater => break,
20318                        }
20319                    }
20320                }
20321            }
20322
20323            true
20324        })
20325    }
20326
20327    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
20328    pub fn clear_row_highlights<T: 'static>(&mut self) {
20329        self.highlighted_rows.remove(&TypeId::of::<T>());
20330    }
20331
20332    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
20333    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
20334        self.highlighted_rows
20335            .get(&TypeId::of::<T>())
20336            .map_or(&[] as &[_], |vec| vec.as_slice())
20337            .iter()
20338            .map(|highlight| (highlight.range.clone(), highlight.color))
20339    }
20340
20341    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
20342    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
20343    /// Allows to ignore certain kinds of highlights.
20344    pub fn highlighted_display_rows(
20345        &self,
20346        window: &mut Window,
20347        cx: &mut App,
20348    ) -> BTreeMap<DisplayRow, LineHighlight> {
20349        let snapshot = self.snapshot(window, cx);
20350        let mut used_highlight_orders = HashMap::default();
20351        self.highlighted_rows
20352            .iter()
20353            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
20354            .fold(
20355                BTreeMap::<DisplayRow, LineHighlight>::new(),
20356                |mut unique_rows, highlight| {
20357                    let start = highlight.range.start.to_display_point(&snapshot);
20358                    let end = highlight.range.end.to_display_point(&snapshot);
20359                    let start_row = start.row().0;
20360                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
20361                        && end.column() == 0
20362                    {
20363                        end.row().0.saturating_sub(1)
20364                    } else {
20365                        end.row().0
20366                    };
20367                    for row in start_row..=end_row {
20368                        let used_index =
20369                            used_highlight_orders.entry(row).or_insert(highlight.index);
20370                        if highlight.index >= *used_index {
20371                            *used_index = highlight.index;
20372                            unique_rows.insert(
20373                                DisplayRow(row),
20374                                LineHighlight {
20375                                    include_gutter: highlight.options.include_gutter,
20376                                    border: None,
20377                                    background: highlight.color.into(),
20378                                    type_id: Some(highlight.type_id),
20379                                },
20380                            );
20381                        }
20382                    }
20383                    unique_rows
20384                },
20385            )
20386    }
20387
20388    pub fn highlighted_display_row_for_autoscroll(
20389        &self,
20390        snapshot: &DisplaySnapshot,
20391    ) -> Option<DisplayRow> {
20392        self.highlighted_rows
20393            .values()
20394            .flat_map(|highlighted_rows| highlighted_rows.iter())
20395            .filter_map(|highlight| {
20396                if highlight.options.autoscroll {
20397                    Some(highlight.range.start.to_display_point(snapshot).row())
20398                } else {
20399                    None
20400                }
20401            })
20402            .min()
20403    }
20404
20405    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
20406        self.highlight_background::<SearchWithinRange>(
20407            ranges,
20408            |colors| colors.colors().editor_document_highlight_read_background,
20409            cx,
20410        )
20411    }
20412
20413    pub fn set_breadcrumb_header(&mut self, new_header: String) {
20414        self.breadcrumb_header = Some(new_header);
20415    }
20416
20417    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
20418        self.clear_background_highlights::<SearchWithinRange>(cx);
20419    }
20420
20421    pub fn highlight_background<T: 'static>(
20422        &mut self,
20423        ranges: &[Range<Anchor>],
20424        color_fetcher: fn(&Theme) -> Hsla,
20425        cx: &mut Context<Self>,
20426    ) {
20427        self.background_highlights.insert(
20428            HighlightKey::Type(TypeId::of::<T>()),
20429            (color_fetcher, Arc::from(ranges)),
20430        );
20431        self.scrollbar_marker_state.dirty = true;
20432        cx.notify();
20433    }
20434
20435    pub fn highlight_background_key<T: 'static>(
20436        &mut self,
20437        key: usize,
20438        ranges: &[Range<Anchor>],
20439        color_fetcher: fn(&Theme) -> Hsla,
20440        cx: &mut Context<Self>,
20441    ) {
20442        self.background_highlights.insert(
20443            HighlightKey::TypePlus(TypeId::of::<T>(), key),
20444            (color_fetcher, Arc::from(ranges)),
20445        );
20446        self.scrollbar_marker_state.dirty = true;
20447        cx.notify();
20448    }
20449
20450    pub fn clear_background_highlights<T: 'static>(
20451        &mut self,
20452        cx: &mut Context<Self>,
20453    ) -> Option<BackgroundHighlight> {
20454        let text_highlights = self
20455            .background_highlights
20456            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
20457        if !text_highlights.1.is_empty() {
20458            self.scrollbar_marker_state.dirty = true;
20459            cx.notify();
20460        }
20461        Some(text_highlights)
20462    }
20463
20464    pub fn highlight_gutter<T: 'static>(
20465        &mut self,
20466        ranges: impl Into<Vec<Range<Anchor>>>,
20467        color_fetcher: fn(&App) -> Hsla,
20468        cx: &mut Context<Self>,
20469    ) {
20470        self.gutter_highlights
20471            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
20472        cx.notify();
20473    }
20474
20475    pub fn clear_gutter_highlights<T: 'static>(
20476        &mut self,
20477        cx: &mut Context<Self>,
20478    ) -> Option<GutterHighlight> {
20479        cx.notify();
20480        self.gutter_highlights.remove(&TypeId::of::<T>())
20481    }
20482
20483    pub fn insert_gutter_highlight<T: 'static>(
20484        &mut self,
20485        range: Range<Anchor>,
20486        color_fetcher: fn(&App) -> Hsla,
20487        cx: &mut Context<Self>,
20488    ) {
20489        let snapshot = self.buffer().read(cx).snapshot(cx);
20490        let mut highlights = self
20491            .gutter_highlights
20492            .remove(&TypeId::of::<T>())
20493            .map(|(_, highlights)| highlights)
20494            .unwrap_or_default();
20495        let ix = highlights.binary_search_by(|highlight| {
20496            Ordering::Equal
20497                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
20498                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
20499        });
20500        if let Err(ix) = ix {
20501            highlights.insert(ix, range);
20502        }
20503        self.gutter_highlights
20504            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
20505    }
20506
20507    pub fn remove_gutter_highlights<T: 'static>(
20508        &mut self,
20509        ranges_to_remove: Vec<Range<Anchor>>,
20510        cx: &mut Context<Self>,
20511    ) {
20512        let snapshot = self.buffer().read(cx).snapshot(cx);
20513        let Some((color_fetcher, mut gutter_highlights)) =
20514            self.gutter_highlights.remove(&TypeId::of::<T>())
20515        else {
20516            return;
20517        };
20518        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20519        gutter_highlights.retain(|highlight| {
20520            while let Some(range_to_remove) = ranges_to_remove.peek() {
20521                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
20522                    Ordering::Less | Ordering::Equal => {
20523                        ranges_to_remove.next();
20524                    }
20525                    Ordering::Greater => {
20526                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
20527                            Ordering::Less | Ordering::Equal => {
20528                                return false;
20529                            }
20530                            Ordering::Greater => break,
20531                        }
20532                    }
20533                }
20534            }
20535
20536            true
20537        });
20538        self.gutter_highlights
20539            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
20540    }
20541
20542    #[cfg(feature = "test-support")]
20543    pub fn all_text_highlights(
20544        &self,
20545        window: &mut Window,
20546        cx: &mut Context<Self>,
20547    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
20548        let snapshot = self.snapshot(window, cx);
20549        self.display_map.update(cx, |display_map, _| {
20550            display_map
20551                .all_text_highlights()
20552                .map(|highlight| {
20553                    let (style, ranges) = highlight.as_ref();
20554                    (
20555                        *style,
20556                        ranges
20557                            .iter()
20558                            .map(|range| range.clone().to_display_points(&snapshot))
20559                            .collect(),
20560                    )
20561                })
20562                .collect()
20563        })
20564    }
20565
20566    #[cfg(feature = "test-support")]
20567    pub fn all_text_background_highlights(
20568        &self,
20569        window: &mut Window,
20570        cx: &mut Context<Self>,
20571    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20572        let snapshot = self.snapshot(window, cx);
20573        let buffer = &snapshot.buffer_snapshot();
20574        let start = buffer.anchor_before(0);
20575        let end = buffer.anchor_after(buffer.len());
20576        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
20577    }
20578
20579    #[cfg(any(test, feature = "test-support"))]
20580    pub fn sorted_background_highlights_in_range(
20581        &self,
20582        search_range: Range<Anchor>,
20583        display_snapshot: &DisplaySnapshot,
20584        theme: &Theme,
20585    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20586        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
20587        res.sort_by(|a, b| {
20588            a.0.start
20589                .cmp(&b.0.start)
20590                .then_with(|| a.0.end.cmp(&b.0.end))
20591                .then_with(|| a.1.cmp(&b.1))
20592        });
20593        res
20594    }
20595
20596    #[cfg(feature = "test-support")]
20597    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
20598        let snapshot = self.buffer().read(cx).snapshot(cx);
20599
20600        let highlights = self
20601            .background_highlights
20602            .get(&HighlightKey::Type(TypeId::of::<
20603                items::BufferSearchHighlights,
20604            >()));
20605
20606        if let Some((_color, ranges)) = highlights {
20607            ranges
20608                .iter()
20609                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
20610                .collect_vec()
20611        } else {
20612            vec![]
20613        }
20614    }
20615
20616    fn document_highlights_for_position<'a>(
20617        &'a self,
20618        position: Anchor,
20619        buffer: &'a MultiBufferSnapshot,
20620    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
20621        let read_highlights = self
20622            .background_highlights
20623            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
20624            .map(|h| &h.1);
20625        let write_highlights = self
20626            .background_highlights
20627            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
20628            .map(|h| &h.1);
20629        let left_position = position.bias_left(buffer);
20630        let right_position = position.bias_right(buffer);
20631        read_highlights
20632            .into_iter()
20633            .chain(write_highlights)
20634            .flat_map(move |ranges| {
20635                let start_ix = match ranges.binary_search_by(|probe| {
20636                    let cmp = probe.end.cmp(&left_position, buffer);
20637                    if cmp.is_ge() {
20638                        Ordering::Greater
20639                    } else {
20640                        Ordering::Less
20641                    }
20642                }) {
20643                    Ok(i) | Err(i) => i,
20644                };
20645
20646                ranges[start_ix..]
20647                    .iter()
20648                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
20649            })
20650    }
20651
20652    pub fn has_background_highlights<T: 'static>(&self) -> bool {
20653        self.background_highlights
20654            .get(&HighlightKey::Type(TypeId::of::<T>()))
20655            .is_some_and(|(_, highlights)| !highlights.is_empty())
20656    }
20657
20658    /// Returns all background highlights for a given range.
20659    ///
20660    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
20661    pub fn background_highlights_in_range(
20662        &self,
20663        search_range: Range<Anchor>,
20664        display_snapshot: &DisplaySnapshot,
20665        theme: &Theme,
20666    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20667        let mut results = Vec::new();
20668        for (color_fetcher, ranges) in self.background_highlights.values() {
20669            let color = color_fetcher(theme);
20670            let start_ix = match ranges.binary_search_by(|probe| {
20671                let cmp = probe
20672                    .end
20673                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
20674                if cmp.is_gt() {
20675                    Ordering::Greater
20676                } else {
20677                    Ordering::Less
20678                }
20679            }) {
20680                Ok(i) | Err(i) => i,
20681            };
20682            for range in &ranges[start_ix..] {
20683                if range
20684                    .start
20685                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
20686                    .is_ge()
20687                {
20688                    break;
20689                }
20690
20691                let start = range.start.to_display_point(display_snapshot);
20692                let end = range.end.to_display_point(display_snapshot);
20693                results.push((start..end, color))
20694            }
20695        }
20696        results
20697    }
20698
20699    pub fn gutter_highlights_in_range(
20700        &self,
20701        search_range: Range<Anchor>,
20702        display_snapshot: &DisplaySnapshot,
20703        cx: &App,
20704    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20705        let mut results = Vec::new();
20706        for (color_fetcher, ranges) in self.gutter_highlights.values() {
20707            let color = color_fetcher(cx);
20708            let start_ix = match ranges.binary_search_by(|probe| {
20709                let cmp = probe
20710                    .end
20711                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
20712                if cmp.is_gt() {
20713                    Ordering::Greater
20714                } else {
20715                    Ordering::Less
20716                }
20717            }) {
20718                Ok(i) | Err(i) => i,
20719            };
20720            for range in &ranges[start_ix..] {
20721                if range
20722                    .start
20723                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
20724                    .is_ge()
20725                {
20726                    break;
20727                }
20728
20729                let start = range.start.to_display_point(display_snapshot);
20730                let end = range.end.to_display_point(display_snapshot);
20731                results.push((start..end, color))
20732            }
20733        }
20734        results
20735    }
20736
20737    /// Get the text ranges corresponding to the redaction query
20738    pub fn redacted_ranges(
20739        &self,
20740        search_range: Range<Anchor>,
20741        display_snapshot: &DisplaySnapshot,
20742        cx: &App,
20743    ) -> Vec<Range<DisplayPoint>> {
20744        display_snapshot
20745            .buffer_snapshot()
20746            .redacted_ranges(search_range, |file| {
20747                if let Some(file) = file {
20748                    file.is_private()
20749                        && EditorSettings::get(
20750                            Some(SettingsLocation {
20751                                worktree_id: file.worktree_id(cx),
20752                                path: file.path().as_ref(),
20753                            }),
20754                            cx,
20755                        )
20756                        .redact_private_values
20757                } else {
20758                    false
20759                }
20760            })
20761            .map(|range| {
20762                range.start.to_display_point(display_snapshot)
20763                    ..range.end.to_display_point(display_snapshot)
20764            })
20765            .collect()
20766    }
20767
20768    pub fn highlight_text_key<T: 'static>(
20769        &mut self,
20770        key: usize,
20771        ranges: Vec<Range<Anchor>>,
20772        style: HighlightStyle,
20773        cx: &mut Context<Self>,
20774    ) {
20775        self.display_map.update(cx, |map, _| {
20776            map.highlight_text(
20777                HighlightKey::TypePlus(TypeId::of::<T>(), key),
20778                ranges,
20779                style,
20780            );
20781        });
20782        cx.notify();
20783    }
20784
20785    pub fn highlight_text<T: 'static>(
20786        &mut self,
20787        ranges: Vec<Range<Anchor>>,
20788        style: HighlightStyle,
20789        cx: &mut Context<Self>,
20790    ) {
20791        self.display_map.update(cx, |map, _| {
20792            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
20793        });
20794        cx.notify();
20795    }
20796
20797    pub fn text_highlights<'a, T: 'static>(
20798        &'a self,
20799        cx: &'a App,
20800    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
20801        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
20802    }
20803
20804    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
20805        let cleared = self
20806            .display_map
20807            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
20808        if cleared {
20809            cx.notify();
20810        }
20811    }
20812
20813    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
20814        (self.read_only(cx) || self.blink_manager.read(cx).visible())
20815            && self.focus_handle.is_focused(window)
20816    }
20817
20818    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
20819        self.show_cursor_when_unfocused = is_enabled;
20820        cx.notify();
20821    }
20822
20823    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
20824        cx.notify();
20825    }
20826
20827    fn on_debug_session_event(
20828        &mut self,
20829        _session: Entity<Session>,
20830        event: &SessionEvent,
20831        cx: &mut Context<Self>,
20832    ) {
20833        if let SessionEvent::InvalidateInlineValue = event {
20834            self.refresh_inline_values(cx);
20835        }
20836    }
20837
20838    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
20839        let Some(project) = self.project.clone() else {
20840            return;
20841        };
20842
20843        if !self.inline_value_cache.enabled {
20844            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
20845            self.splice_inlays(&inlays, Vec::new(), cx);
20846            return;
20847        }
20848
20849        let current_execution_position = self
20850            .highlighted_rows
20851            .get(&TypeId::of::<ActiveDebugLine>())
20852            .and_then(|lines| lines.last().map(|line| line.range.end));
20853
20854        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
20855            let inline_values = editor
20856                .update(cx, |editor, cx| {
20857                    let Some(current_execution_position) = current_execution_position else {
20858                        return Some(Task::ready(Ok(Vec::new())));
20859                    };
20860
20861                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
20862                        let snapshot = buffer.snapshot(cx);
20863
20864                        let excerpt = snapshot.excerpt_containing(
20865                            current_execution_position..current_execution_position,
20866                        )?;
20867
20868                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
20869                    })?;
20870
20871                    let range =
20872                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
20873
20874                    project.inline_values(buffer, range, cx)
20875                })
20876                .ok()
20877                .flatten()?
20878                .await
20879                .context("refreshing debugger inlays")
20880                .log_err()?;
20881
20882            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
20883
20884            for (buffer_id, inline_value) in inline_values
20885                .into_iter()
20886                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
20887            {
20888                buffer_inline_values
20889                    .entry(buffer_id)
20890                    .or_default()
20891                    .push(inline_value);
20892            }
20893
20894            editor
20895                .update(cx, |editor, cx| {
20896                    let snapshot = editor.buffer.read(cx).snapshot(cx);
20897                    let mut new_inlays = Vec::default();
20898
20899                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
20900                        let buffer_id = buffer_snapshot.remote_id();
20901                        buffer_inline_values
20902                            .get(&buffer_id)
20903                            .into_iter()
20904                            .flatten()
20905                            .for_each(|hint| {
20906                                let inlay = Inlay::debugger(
20907                                    post_inc(&mut editor.next_inlay_id),
20908                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
20909                                    hint.text(),
20910                                );
20911                                if !inlay.text().chars().contains(&'\n') {
20912                                    new_inlays.push(inlay);
20913                                }
20914                            });
20915                    }
20916
20917                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
20918                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
20919
20920                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
20921                })
20922                .ok()?;
20923            Some(())
20924        });
20925    }
20926
20927    fn on_buffer_event(
20928        &mut self,
20929        multibuffer: &Entity<MultiBuffer>,
20930        event: &multi_buffer::Event,
20931        window: &mut Window,
20932        cx: &mut Context<Self>,
20933    ) {
20934        match event {
20935            multi_buffer::Event::Edited { edited_buffer } => {
20936                self.scrollbar_marker_state.dirty = true;
20937                self.active_indent_guides_state.dirty = true;
20938                self.refresh_active_diagnostics(cx);
20939                self.refresh_code_actions(window, cx);
20940                self.refresh_selected_text_highlights(true, window, cx);
20941                self.refresh_single_line_folds(window, cx);
20942                self.refresh_matching_bracket_highlights(window, cx);
20943                if self.has_active_edit_prediction() {
20944                    self.update_visible_edit_prediction(window, cx);
20945                }
20946
20947                if let Some(buffer) = edited_buffer {
20948                    if buffer.read(cx).file().is_none() {
20949                        cx.emit(EditorEvent::TitleChanged);
20950                    }
20951
20952                    if self.project.is_some() {
20953                        let buffer_id = buffer.read(cx).remote_id();
20954                        self.register_buffer(buffer_id, cx);
20955                        self.update_lsp_data(Some(buffer_id), window, cx);
20956                        self.refresh_inlay_hints(
20957                            InlayHintRefreshReason::BufferEdited(buffer_id),
20958                            cx,
20959                        );
20960                    }
20961                }
20962
20963                cx.emit(EditorEvent::BufferEdited);
20964                cx.emit(SearchEvent::MatchesInvalidated);
20965
20966                let Some(project) = &self.project else { return };
20967                let (telemetry, is_via_ssh) = {
20968                    let project = project.read(cx);
20969                    let telemetry = project.client().telemetry().clone();
20970                    let is_via_ssh = project.is_via_remote_server();
20971                    (telemetry, is_via_ssh)
20972                };
20973                telemetry.log_edit_event("editor", is_via_ssh);
20974            }
20975            multi_buffer::Event::ExcerptsAdded {
20976                buffer,
20977                predecessor,
20978                excerpts,
20979            } => {
20980                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20981                let buffer_id = buffer.read(cx).remote_id();
20982                if self.buffer.read(cx).diff_for(buffer_id).is_none()
20983                    && let Some(project) = &self.project
20984                {
20985                    update_uncommitted_diff_for_buffer(
20986                        cx.entity(),
20987                        project,
20988                        [buffer.clone()],
20989                        self.buffer.clone(),
20990                        cx,
20991                    )
20992                    .detach();
20993                }
20994                self.update_lsp_data(Some(buffer_id), window, cx);
20995                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20996                cx.emit(EditorEvent::ExcerptsAdded {
20997                    buffer: buffer.clone(),
20998                    predecessor: *predecessor,
20999                    excerpts: excerpts.clone(),
21000                });
21001            }
21002            multi_buffer::Event::ExcerptsRemoved {
21003                ids,
21004                removed_buffer_ids,
21005            } => {
21006                if let Some(inlay_hints) = &mut self.inlay_hints {
21007                    inlay_hints.remove_inlay_chunk_data(removed_buffer_ids);
21008                }
21009                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
21010                for buffer_id in removed_buffer_ids {
21011                    self.registered_buffers.remove(buffer_id);
21012                }
21013                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21014                cx.emit(EditorEvent::ExcerptsRemoved {
21015                    ids: ids.clone(),
21016                    removed_buffer_ids: removed_buffer_ids.clone(),
21017                });
21018            }
21019            multi_buffer::Event::ExcerptsEdited {
21020                excerpt_ids,
21021                buffer_ids,
21022            } => {
21023                self.display_map.update(cx, |map, cx| {
21024                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
21025                });
21026                cx.emit(EditorEvent::ExcerptsEdited {
21027                    ids: excerpt_ids.clone(),
21028                });
21029            }
21030            multi_buffer::Event::ExcerptsExpanded { ids } => {
21031                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
21032                self.refresh_document_highlights(cx);
21033                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
21034            }
21035            multi_buffer::Event::Reparsed(buffer_id) => {
21036                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21037                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21038
21039                cx.emit(EditorEvent::Reparsed(*buffer_id));
21040            }
21041            multi_buffer::Event::DiffHunksToggled => {
21042                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21043            }
21044            multi_buffer::Event::LanguageChanged(buffer_id) => {
21045                self.registered_buffers.remove(&buffer_id);
21046                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21047                cx.emit(EditorEvent::Reparsed(*buffer_id));
21048                cx.notify();
21049            }
21050            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
21051            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
21052            multi_buffer::Event::FileHandleChanged
21053            | multi_buffer::Event::Reloaded
21054            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
21055            multi_buffer::Event::DiagnosticsUpdated => {
21056                self.update_diagnostics_state(window, cx);
21057            }
21058            _ => {}
21059        };
21060    }
21061
21062    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
21063        if !self.diagnostics_enabled() {
21064            return;
21065        }
21066        self.refresh_active_diagnostics(cx);
21067        self.refresh_inline_diagnostics(true, window, cx);
21068        self.scrollbar_marker_state.dirty = true;
21069        cx.notify();
21070    }
21071
21072    pub fn start_temporary_diff_override(&mut self) {
21073        self.load_diff_task.take();
21074        self.temporary_diff_override = true;
21075    }
21076
21077    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
21078        self.temporary_diff_override = false;
21079        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
21080        self.buffer.update(cx, |buffer, cx| {
21081            buffer.set_all_diff_hunks_collapsed(cx);
21082        });
21083
21084        if let Some(project) = self.project.clone() {
21085            self.load_diff_task = Some(
21086                update_uncommitted_diff_for_buffer(
21087                    cx.entity(),
21088                    &project,
21089                    self.buffer.read(cx).all_buffers(),
21090                    self.buffer.clone(),
21091                    cx,
21092                )
21093                .shared(),
21094            );
21095        }
21096    }
21097
21098    fn on_display_map_changed(
21099        &mut self,
21100        _: Entity<DisplayMap>,
21101        _: &mut Window,
21102        cx: &mut Context<Self>,
21103    ) {
21104        cx.notify();
21105    }
21106
21107    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21108        if self.diagnostics_enabled() {
21109            let new_severity = EditorSettings::get_global(cx)
21110                .diagnostics_max_severity
21111                .unwrap_or(DiagnosticSeverity::Hint);
21112            self.set_max_diagnostics_severity(new_severity, cx);
21113        }
21114        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21115        self.update_edit_prediction_settings(cx);
21116        self.refresh_edit_prediction(true, false, window, cx);
21117        self.refresh_inline_values(cx);
21118        self.refresh_inlay_hints(
21119            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
21120                self.selections.newest_anchor().head(),
21121                &self.buffer.read(cx).snapshot(cx),
21122                cx,
21123            )),
21124            cx,
21125        );
21126
21127        let old_cursor_shape = self.cursor_shape;
21128        let old_show_breadcrumbs = self.show_breadcrumbs;
21129
21130        {
21131            let editor_settings = EditorSettings::get_global(cx);
21132            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
21133            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
21134            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
21135            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
21136        }
21137
21138        if old_cursor_shape != self.cursor_shape {
21139            cx.emit(EditorEvent::CursorShapeChanged);
21140        }
21141
21142        if old_show_breadcrumbs != self.show_breadcrumbs {
21143            cx.emit(EditorEvent::BreadcrumbsChanged);
21144        }
21145
21146        let project_settings = ProjectSettings::get_global(cx);
21147        self.serialize_dirty_buffers =
21148            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
21149
21150        if self.mode.is_full() {
21151            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
21152            let inline_blame_enabled = project_settings.git.inline_blame.enabled;
21153            if self.show_inline_diagnostics != show_inline_diagnostics {
21154                self.show_inline_diagnostics = show_inline_diagnostics;
21155                self.refresh_inline_diagnostics(false, window, cx);
21156            }
21157
21158            if self.git_blame_inline_enabled != inline_blame_enabled {
21159                self.toggle_git_blame_inline_internal(false, window, cx);
21160            }
21161
21162            let minimap_settings = EditorSettings::get_global(cx).minimap;
21163            if self.minimap_visibility != MinimapVisibility::Disabled {
21164                if self.minimap_visibility.settings_visibility()
21165                    != minimap_settings.minimap_enabled()
21166                {
21167                    self.set_minimap_visibility(
21168                        MinimapVisibility::for_mode(self.mode(), cx),
21169                        window,
21170                        cx,
21171                    );
21172                } else if let Some(minimap_entity) = self.minimap.as_ref() {
21173                    minimap_entity.update(cx, |minimap_editor, cx| {
21174                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
21175                    })
21176                }
21177            }
21178        }
21179
21180        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
21181            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
21182        }) {
21183            if !inlay_splice.is_empty() {
21184                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
21185            }
21186            self.refresh_colors_for_visible_range(None, window, cx);
21187        }
21188
21189        cx.notify();
21190    }
21191
21192    pub fn set_searchable(&mut self, searchable: bool) {
21193        self.searchable = searchable;
21194    }
21195
21196    pub fn searchable(&self) -> bool {
21197        self.searchable
21198    }
21199
21200    pub fn open_excerpts_in_split(
21201        &mut self,
21202        _: &OpenExcerptsSplit,
21203        window: &mut Window,
21204        cx: &mut Context<Self>,
21205    ) {
21206        self.open_excerpts_common(None, true, window, cx)
21207    }
21208
21209    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
21210        self.open_excerpts_common(None, false, window, cx)
21211    }
21212
21213    fn open_excerpts_common(
21214        &mut self,
21215        jump_data: Option<JumpData>,
21216        split: bool,
21217        window: &mut Window,
21218        cx: &mut Context<Self>,
21219    ) {
21220        let Some(workspace) = self.workspace() else {
21221            cx.propagate();
21222            return;
21223        };
21224
21225        if self.buffer.read(cx).is_singleton() {
21226            cx.propagate();
21227            return;
21228        }
21229
21230        let mut new_selections_by_buffer = HashMap::default();
21231        match &jump_data {
21232            Some(JumpData::MultiBufferPoint {
21233                excerpt_id,
21234                position,
21235                anchor,
21236                line_offset_from_top,
21237            }) => {
21238                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
21239                if let Some(buffer) = multi_buffer_snapshot
21240                    .buffer_id_for_excerpt(*excerpt_id)
21241                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
21242                {
21243                    let buffer_snapshot = buffer.read(cx).snapshot();
21244                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
21245                        language::ToPoint::to_point(anchor, &buffer_snapshot)
21246                    } else {
21247                        buffer_snapshot.clip_point(*position, Bias::Left)
21248                    };
21249                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
21250                    new_selections_by_buffer.insert(
21251                        buffer,
21252                        (
21253                            vec![jump_to_offset..jump_to_offset],
21254                            Some(*line_offset_from_top),
21255                        ),
21256                    );
21257                }
21258            }
21259            Some(JumpData::MultiBufferRow {
21260                row,
21261                line_offset_from_top,
21262            }) => {
21263                let point = MultiBufferPoint::new(row.0, 0);
21264                if let Some((buffer, buffer_point, _)) =
21265                    self.buffer.read(cx).point_to_buffer_point(point, cx)
21266                {
21267                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
21268                    new_selections_by_buffer
21269                        .entry(buffer)
21270                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
21271                        .0
21272                        .push(buffer_offset..buffer_offset)
21273                }
21274            }
21275            None => {
21276                let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
21277                let multi_buffer = self.buffer.read(cx);
21278                for selection in selections {
21279                    for (snapshot, range, _, anchor) in multi_buffer
21280                        .snapshot(cx)
21281                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
21282                    {
21283                        if let Some(anchor) = anchor {
21284                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
21285                            else {
21286                                continue;
21287                            };
21288                            let offset = text::ToOffset::to_offset(
21289                                &anchor.text_anchor,
21290                                &buffer_handle.read(cx).snapshot(),
21291                            );
21292                            let range = offset..offset;
21293                            new_selections_by_buffer
21294                                .entry(buffer_handle)
21295                                .or_insert((Vec::new(), None))
21296                                .0
21297                                .push(range)
21298                        } else {
21299                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
21300                            else {
21301                                continue;
21302                            };
21303                            new_selections_by_buffer
21304                                .entry(buffer_handle)
21305                                .or_insert((Vec::new(), None))
21306                                .0
21307                                .push(range)
21308                        }
21309                    }
21310                }
21311            }
21312        }
21313
21314        new_selections_by_buffer
21315            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
21316
21317        if new_selections_by_buffer.is_empty() {
21318            return;
21319        }
21320
21321        // We defer the pane interaction because we ourselves are a workspace item
21322        // and activating a new item causes the pane to call a method on us reentrantly,
21323        // which panics if we're on the stack.
21324        window.defer(cx, move |window, cx| {
21325            workspace.update(cx, |workspace, cx| {
21326                let pane = if split {
21327                    workspace.adjacent_pane(window, cx)
21328                } else {
21329                    workspace.active_pane().clone()
21330                };
21331
21332                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
21333                    let editor = buffer
21334                        .read(cx)
21335                        .file()
21336                        .is_none()
21337                        .then(|| {
21338                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
21339                            // so `workspace.open_project_item` will never find them, always opening a new editor.
21340                            // Instead, we try to activate the existing editor in the pane first.
21341                            let (editor, pane_item_index) =
21342                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
21343                                    let editor = item.downcast::<Editor>()?;
21344                                    let singleton_buffer =
21345                                        editor.read(cx).buffer().read(cx).as_singleton()?;
21346                                    if singleton_buffer == buffer {
21347                                        Some((editor, i))
21348                                    } else {
21349                                        None
21350                                    }
21351                                })?;
21352                            pane.update(cx, |pane, cx| {
21353                                pane.activate_item(pane_item_index, true, true, window, cx)
21354                            });
21355                            Some(editor)
21356                        })
21357                        .flatten()
21358                        .unwrap_or_else(|| {
21359                            workspace.open_project_item::<Self>(
21360                                pane.clone(),
21361                                buffer,
21362                                true,
21363                                true,
21364                                window,
21365                                cx,
21366                            )
21367                        });
21368
21369                    editor.update(cx, |editor, cx| {
21370                        let autoscroll = match scroll_offset {
21371                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
21372                            None => Autoscroll::newest(),
21373                        };
21374                        let nav_history = editor.nav_history.take();
21375                        editor.change_selections(
21376                            SelectionEffects::scroll(autoscroll),
21377                            window,
21378                            cx,
21379                            |s| {
21380                                s.select_ranges(ranges);
21381                            },
21382                        );
21383                        editor.nav_history = nav_history;
21384                    });
21385                }
21386            })
21387        });
21388    }
21389
21390    // For now, don't allow opening excerpts in buffers that aren't backed by
21391    // regular project files.
21392    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
21393        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some())
21394    }
21395
21396    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
21397        let snapshot = self.buffer.read(cx).read(cx);
21398        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
21399        Some(
21400            ranges
21401                .iter()
21402                .map(move |range| {
21403                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
21404                })
21405                .collect(),
21406        )
21407    }
21408
21409    fn selection_replacement_ranges(
21410        &self,
21411        range: Range<OffsetUtf16>,
21412        cx: &mut App,
21413    ) -> Vec<Range<OffsetUtf16>> {
21414        let selections = self
21415            .selections
21416            .all::<OffsetUtf16>(&self.display_snapshot(cx));
21417        let newest_selection = selections
21418            .iter()
21419            .max_by_key(|selection| selection.id)
21420            .unwrap();
21421        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
21422        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
21423        let snapshot = self.buffer.read(cx).read(cx);
21424        selections
21425            .into_iter()
21426            .map(|mut selection| {
21427                selection.start.0 =
21428                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
21429                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
21430                snapshot.clip_offset_utf16(selection.start, Bias::Left)
21431                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
21432            })
21433            .collect()
21434    }
21435
21436    fn report_editor_event(
21437        &self,
21438        reported_event: ReportEditorEvent,
21439        file_extension: Option<String>,
21440        cx: &App,
21441    ) {
21442        if cfg!(any(test, feature = "test-support")) {
21443            return;
21444        }
21445
21446        let Some(project) = &self.project else { return };
21447
21448        // If None, we are in a file without an extension
21449        let file = self
21450            .buffer
21451            .read(cx)
21452            .as_singleton()
21453            .and_then(|b| b.read(cx).file());
21454        let file_extension = file_extension.or(file
21455            .as_ref()
21456            .and_then(|file| Path::new(file.file_name(cx)).extension())
21457            .and_then(|e| e.to_str())
21458            .map(|a| a.to_string()));
21459
21460        let vim_mode = vim_enabled(cx);
21461
21462        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
21463        let copilot_enabled = edit_predictions_provider
21464            == language::language_settings::EditPredictionProvider::Copilot;
21465        let copilot_enabled_for_language = self
21466            .buffer
21467            .read(cx)
21468            .language_settings(cx)
21469            .show_edit_predictions;
21470
21471        let project = project.read(cx);
21472        let event_type = reported_event.event_type();
21473
21474        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
21475            telemetry::event!(
21476                event_type,
21477                type = if auto_saved {"autosave"} else {"manual"},
21478                file_extension,
21479                vim_mode,
21480                copilot_enabled,
21481                copilot_enabled_for_language,
21482                edit_predictions_provider,
21483                is_via_ssh = project.is_via_remote_server(),
21484            );
21485        } else {
21486            telemetry::event!(
21487                event_type,
21488                file_extension,
21489                vim_mode,
21490                copilot_enabled,
21491                copilot_enabled_for_language,
21492                edit_predictions_provider,
21493                is_via_ssh = project.is_via_remote_server(),
21494            );
21495        };
21496    }
21497
21498    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
21499    /// with each line being an array of {text, highlight} objects.
21500    fn copy_highlight_json(
21501        &mut self,
21502        _: &CopyHighlightJson,
21503        window: &mut Window,
21504        cx: &mut Context<Self>,
21505    ) {
21506        #[derive(Serialize)]
21507        struct Chunk<'a> {
21508            text: String,
21509            highlight: Option<&'a str>,
21510        }
21511
21512        let snapshot = self.buffer.read(cx).snapshot(cx);
21513        let range = self
21514            .selected_text_range(false, window, cx)
21515            .and_then(|selection| {
21516                if selection.range.is_empty() {
21517                    None
21518                } else {
21519                    Some(
21520                        snapshot.offset_utf16_to_offset(OffsetUtf16(selection.range.start))
21521                            ..snapshot.offset_utf16_to_offset(OffsetUtf16(selection.range.end)),
21522                    )
21523                }
21524            })
21525            .unwrap_or_else(|| 0..snapshot.len());
21526
21527        let chunks = snapshot.chunks(range, true);
21528        let mut lines = Vec::new();
21529        let mut line: VecDeque<Chunk> = VecDeque::new();
21530
21531        let Some(style) = self.style.as_ref() else {
21532            return;
21533        };
21534
21535        for chunk in chunks {
21536            let highlight = chunk
21537                .syntax_highlight_id
21538                .and_then(|id| id.name(&style.syntax));
21539            let mut chunk_lines = chunk.text.split('\n').peekable();
21540            while let Some(text) = chunk_lines.next() {
21541                let mut merged_with_last_token = false;
21542                if let Some(last_token) = line.back_mut()
21543                    && last_token.highlight == highlight
21544                {
21545                    last_token.text.push_str(text);
21546                    merged_with_last_token = true;
21547                }
21548
21549                if !merged_with_last_token {
21550                    line.push_back(Chunk {
21551                        text: text.into(),
21552                        highlight,
21553                    });
21554                }
21555
21556                if chunk_lines.peek().is_some() {
21557                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
21558                        line.pop_front();
21559                    }
21560                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
21561                        line.pop_back();
21562                    }
21563
21564                    lines.push(mem::take(&mut line));
21565                }
21566            }
21567        }
21568
21569        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
21570            return;
21571        };
21572        cx.write_to_clipboard(ClipboardItem::new_string(lines));
21573    }
21574
21575    pub fn open_context_menu(
21576        &mut self,
21577        _: &OpenContextMenu,
21578        window: &mut Window,
21579        cx: &mut Context<Self>,
21580    ) {
21581        self.request_autoscroll(Autoscroll::newest(), cx);
21582        let position = self
21583            .selections
21584            .newest_display(&self.display_snapshot(cx))
21585            .start;
21586        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
21587    }
21588
21589    pub fn replay_insert_event(
21590        &mut self,
21591        text: &str,
21592        relative_utf16_range: Option<Range<isize>>,
21593        window: &mut Window,
21594        cx: &mut Context<Self>,
21595    ) {
21596        if !self.input_enabled {
21597            cx.emit(EditorEvent::InputIgnored { text: text.into() });
21598            return;
21599        }
21600        if let Some(relative_utf16_range) = relative_utf16_range {
21601            let selections = self
21602                .selections
21603                .all::<OffsetUtf16>(&self.display_snapshot(cx));
21604            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21605                let new_ranges = selections.into_iter().map(|range| {
21606                    let start = OffsetUtf16(
21607                        range
21608                            .head()
21609                            .0
21610                            .saturating_add_signed(relative_utf16_range.start),
21611                    );
21612                    let end = OffsetUtf16(
21613                        range
21614                            .head()
21615                            .0
21616                            .saturating_add_signed(relative_utf16_range.end),
21617                    );
21618                    start..end
21619                });
21620                s.select_ranges(new_ranges);
21621            });
21622        }
21623
21624        self.handle_input(text, window, cx);
21625    }
21626
21627    pub fn is_focused(&self, window: &Window) -> bool {
21628        self.focus_handle.is_focused(window)
21629    }
21630
21631    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21632        cx.emit(EditorEvent::Focused);
21633
21634        if let Some(descendant) = self
21635            .last_focused_descendant
21636            .take()
21637            .and_then(|descendant| descendant.upgrade())
21638        {
21639            window.focus(&descendant);
21640        } else {
21641            if let Some(blame) = self.blame.as_ref() {
21642                blame.update(cx, GitBlame::focus)
21643            }
21644
21645            self.blink_manager.update(cx, BlinkManager::enable);
21646            self.show_cursor_names(window, cx);
21647            self.buffer.update(cx, |buffer, cx| {
21648                buffer.finalize_last_transaction(cx);
21649                if self.leader_id.is_none() {
21650                    buffer.set_active_selections(
21651                        &self.selections.disjoint_anchors_arc(),
21652                        self.selections.line_mode(),
21653                        self.cursor_shape,
21654                        cx,
21655                    );
21656                }
21657            });
21658        }
21659    }
21660
21661    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
21662        cx.emit(EditorEvent::FocusedIn)
21663    }
21664
21665    fn handle_focus_out(
21666        &mut self,
21667        event: FocusOutEvent,
21668        _window: &mut Window,
21669        cx: &mut Context<Self>,
21670    ) {
21671        if event.blurred != self.focus_handle {
21672            self.last_focused_descendant = Some(event.blurred);
21673        }
21674        self.selection_drag_state = SelectionDragState::None;
21675        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
21676    }
21677
21678    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21679        self.blink_manager.update(cx, BlinkManager::disable);
21680        self.buffer
21681            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
21682
21683        if let Some(blame) = self.blame.as_ref() {
21684            blame.update(cx, GitBlame::blur)
21685        }
21686        if !self.hover_state.focused(window, cx) {
21687            hide_hover(self, cx);
21688        }
21689        if !self
21690            .context_menu
21691            .borrow()
21692            .as_ref()
21693            .is_some_and(|context_menu| context_menu.focused(window, cx))
21694        {
21695            self.hide_context_menu(window, cx);
21696        }
21697        self.take_active_edit_prediction(cx);
21698        cx.emit(EditorEvent::Blurred);
21699        cx.notify();
21700    }
21701
21702    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21703        let mut pending: String = window
21704            .pending_input_keystrokes()
21705            .into_iter()
21706            .flatten()
21707            .filter_map(|keystroke| {
21708                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
21709                    keystroke.key_char.clone()
21710                } else {
21711                    None
21712                }
21713            })
21714            .collect();
21715
21716        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
21717            pending = "".to_string();
21718        }
21719
21720        let existing_pending = self
21721            .text_highlights::<PendingInput>(cx)
21722            .map(|(_, ranges)| ranges.to_vec());
21723        if existing_pending.is_none() && pending.is_empty() {
21724            return;
21725        }
21726        let transaction =
21727            self.transact(window, cx, |this, window, cx| {
21728                let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
21729                let edits = selections
21730                    .iter()
21731                    .map(|selection| (selection.end..selection.end, pending.clone()));
21732                this.edit(edits, cx);
21733                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21734                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
21735                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
21736                    }));
21737                });
21738                if let Some(existing_ranges) = existing_pending {
21739                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
21740                    this.edit(edits, cx);
21741                }
21742            });
21743
21744        let snapshot = self.snapshot(window, cx);
21745        let ranges = self
21746            .selections
21747            .all::<usize>(&snapshot.display_snapshot)
21748            .into_iter()
21749            .map(|selection| {
21750                snapshot.buffer_snapshot().anchor_after(selection.end)
21751                    ..snapshot
21752                        .buffer_snapshot()
21753                        .anchor_before(selection.end + pending.len())
21754            })
21755            .collect();
21756
21757        if pending.is_empty() {
21758            self.clear_highlights::<PendingInput>(cx);
21759        } else {
21760            self.highlight_text::<PendingInput>(
21761                ranges,
21762                HighlightStyle {
21763                    underline: Some(UnderlineStyle {
21764                        thickness: px(1.),
21765                        color: None,
21766                        wavy: false,
21767                    }),
21768                    ..Default::default()
21769                },
21770                cx,
21771            );
21772        }
21773
21774        self.ime_transaction = self.ime_transaction.or(transaction);
21775        if let Some(transaction) = self.ime_transaction {
21776            self.buffer.update(cx, |buffer, cx| {
21777                buffer.group_until_transaction(transaction, cx);
21778            });
21779        }
21780
21781        if self.text_highlights::<PendingInput>(cx).is_none() {
21782            self.ime_transaction.take();
21783        }
21784    }
21785
21786    pub fn register_action_renderer(
21787        &mut self,
21788        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
21789    ) -> Subscription {
21790        let id = self.next_editor_action_id.post_inc();
21791        self.editor_actions
21792            .borrow_mut()
21793            .insert(id, Box::new(listener));
21794
21795        let editor_actions = self.editor_actions.clone();
21796        Subscription::new(move || {
21797            editor_actions.borrow_mut().remove(&id);
21798        })
21799    }
21800
21801    pub fn register_action<A: Action>(
21802        &mut self,
21803        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
21804    ) -> Subscription {
21805        let id = self.next_editor_action_id.post_inc();
21806        let listener = Arc::new(listener);
21807        self.editor_actions.borrow_mut().insert(
21808            id,
21809            Box::new(move |_, window, _| {
21810                let listener = listener.clone();
21811                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
21812                    let action = action.downcast_ref().unwrap();
21813                    if phase == DispatchPhase::Bubble {
21814                        listener(action, window, cx)
21815                    }
21816                })
21817            }),
21818        );
21819
21820        let editor_actions = self.editor_actions.clone();
21821        Subscription::new(move || {
21822            editor_actions.borrow_mut().remove(&id);
21823        })
21824    }
21825
21826    pub fn file_header_size(&self) -> u32 {
21827        FILE_HEADER_HEIGHT
21828    }
21829
21830    pub fn restore(
21831        &mut self,
21832        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
21833        window: &mut Window,
21834        cx: &mut Context<Self>,
21835    ) {
21836        let workspace = self.workspace();
21837        let project = self.project();
21838        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
21839            let mut tasks = Vec::new();
21840            for (buffer_id, changes) in revert_changes {
21841                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
21842                    buffer.update(cx, |buffer, cx| {
21843                        buffer.edit(
21844                            changes
21845                                .into_iter()
21846                                .map(|(range, text)| (range, text.to_string())),
21847                            None,
21848                            cx,
21849                        );
21850                    });
21851
21852                    if let Some(project) =
21853                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
21854                    {
21855                        project.update(cx, |project, cx| {
21856                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
21857                        })
21858                    }
21859                }
21860            }
21861            tasks
21862        });
21863        cx.spawn_in(window, async move |_, cx| {
21864            for (buffer, task) in save_tasks {
21865                let result = task.await;
21866                if result.is_err() {
21867                    let Some(path) = buffer
21868                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
21869                        .ok()
21870                    else {
21871                        continue;
21872                    };
21873                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
21874                        let Some(task) = cx
21875                            .update_window_entity(workspace, |workspace, window, cx| {
21876                                workspace
21877                                    .open_path_preview(path, None, false, false, false, window, cx)
21878                            })
21879                            .ok()
21880                        else {
21881                            continue;
21882                        };
21883                        task.await.log_err();
21884                    }
21885                }
21886            }
21887        })
21888        .detach();
21889        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
21890            selections.refresh()
21891        });
21892    }
21893
21894    pub fn to_pixel_point(
21895        &self,
21896        source: multi_buffer::Anchor,
21897        editor_snapshot: &EditorSnapshot,
21898        window: &mut Window,
21899    ) -> Option<gpui::Point<Pixels>> {
21900        let source_point = source.to_display_point(editor_snapshot);
21901        self.display_to_pixel_point(source_point, editor_snapshot, window)
21902    }
21903
21904    pub fn display_to_pixel_point(
21905        &self,
21906        source: DisplayPoint,
21907        editor_snapshot: &EditorSnapshot,
21908        window: &mut Window,
21909    ) -> Option<gpui::Point<Pixels>> {
21910        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
21911        let text_layout_details = self.text_layout_details(window);
21912        let scroll_top = text_layout_details
21913            .scroll_anchor
21914            .scroll_position(editor_snapshot)
21915            .y;
21916
21917        if source.row().as_f64() < scroll_top.floor() {
21918            return None;
21919        }
21920        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
21921        let source_y = line_height * (source.row().as_f64() - scroll_top) as f32;
21922        Some(gpui::Point::new(source_x, source_y))
21923    }
21924
21925    pub fn has_visible_completions_menu(&self) -> bool {
21926        !self.edit_prediction_preview_is_active()
21927            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
21928                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
21929            })
21930    }
21931
21932    pub fn register_addon<T: Addon>(&mut self, instance: T) {
21933        if self.mode.is_minimap() {
21934            return;
21935        }
21936        self.addons
21937            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
21938    }
21939
21940    pub fn unregister_addon<T: Addon>(&mut self) {
21941        self.addons.remove(&std::any::TypeId::of::<T>());
21942    }
21943
21944    pub fn addon<T: Addon>(&self) -> Option<&T> {
21945        let type_id = std::any::TypeId::of::<T>();
21946        self.addons
21947            .get(&type_id)
21948            .and_then(|item| item.to_any().downcast_ref::<T>())
21949    }
21950
21951    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
21952        let type_id = std::any::TypeId::of::<T>();
21953        self.addons
21954            .get_mut(&type_id)
21955            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
21956    }
21957
21958    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
21959        let text_layout_details = self.text_layout_details(window);
21960        let style = &text_layout_details.editor_style;
21961        let font_id = window.text_system().resolve_font(&style.text.font());
21962        let font_size = style.text.font_size.to_pixels(window.rem_size());
21963        let line_height = style.text.line_height_in_pixels(window.rem_size());
21964        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
21965        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
21966
21967        CharacterDimensions {
21968            em_width,
21969            em_advance,
21970            line_height,
21971        }
21972    }
21973
21974    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
21975        self.load_diff_task.clone()
21976    }
21977
21978    fn read_metadata_from_db(
21979        &mut self,
21980        item_id: u64,
21981        workspace_id: WorkspaceId,
21982        window: &mut Window,
21983        cx: &mut Context<Editor>,
21984    ) {
21985        if self.buffer_kind(cx) == ItemBufferKind::Singleton
21986            && !self.mode.is_minimap()
21987            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
21988        {
21989            let buffer_snapshot = OnceCell::new();
21990
21991            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
21992                && !folds.is_empty()
21993            {
21994                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21995                self.fold_ranges(
21996                    folds
21997                        .into_iter()
21998                        .map(|(start, end)| {
21999                            snapshot.clip_offset(start, Bias::Left)
22000                                ..snapshot.clip_offset(end, Bias::Right)
22001                        })
22002                        .collect(),
22003                    false,
22004                    window,
22005                    cx,
22006                );
22007            }
22008
22009            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
22010                && !selections.is_empty()
22011            {
22012                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
22013                // skip adding the initial selection to selection history
22014                self.selection_history.mode = SelectionHistoryMode::Skipping;
22015                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22016                    s.select_ranges(selections.into_iter().map(|(start, end)| {
22017                        snapshot.clip_offset(start, Bias::Left)
22018                            ..snapshot.clip_offset(end, Bias::Right)
22019                    }));
22020                });
22021                self.selection_history.mode = SelectionHistoryMode::Normal;
22022            };
22023        }
22024
22025        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
22026    }
22027
22028    fn update_lsp_data(
22029        &mut self,
22030        for_buffer: Option<BufferId>,
22031        window: &mut Window,
22032        cx: &mut Context<'_, Self>,
22033    ) {
22034        self.pull_diagnostics(for_buffer, window, cx);
22035        self.refresh_colors_for_visible_range(for_buffer, window, cx);
22036    }
22037
22038    fn register_visible_buffers(&mut self, cx: &mut Context<Self>) {
22039        if self.ignore_lsp_data() {
22040            return;
22041        }
22042        for (_, (visible_buffer, _, _)) in self.visible_excerpts(cx) {
22043            self.register_buffer(visible_buffer.read(cx).remote_id(), cx);
22044        }
22045    }
22046
22047    fn register_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
22048        if !self.registered_buffers.contains_key(&buffer_id)
22049            && let Some(project) = self.project.as_ref()
22050        {
22051            if let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) {
22052                project.update(cx, |project, cx| {
22053                    self.registered_buffers.insert(
22054                        buffer_id,
22055                        project.register_buffer_with_language_servers(&buffer, cx),
22056                    );
22057                });
22058            } else {
22059                self.registered_buffers.remove(&buffer_id);
22060            }
22061        }
22062    }
22063
22064    fn ignore_lsp_data(&self) -> bool {
22065        // `ActiveDiagnostic::All` is a special mode where editor's diagnostics are managed by the external view,
22066        // skip any LSP updates for it.
22067        self.active_diagnostics == ActiveDiagnostic::All || !self.mode().is_full()
22068    }
22069}
22070
22071fn edit_for_markdown_paste<'a>(
22072    buffer: &MultiBufferSnapshot,
22073    range: Range<usize>,
22074    to_insert: &'a str,
22075    url: Option<url::Url>,
22076) -> (Range<usize>, Cow<'a, str>) {
22077    if url.is_none() {
22078        return (range, Cow::Borrowed(to_insert));
22079    };
22080
22081    let old_text = buffer.text_for_range(range.clone()).collect::<String>();
22082
22083    let new_text = if range.is_empty() || url::Url::parse(&old_text).is_ok() {
22084        Cow::Borrowed(to_insert)
22085    } else {
22086        Cow::Owned(format!("[{old_text}]({to_insert})"))
22087    };
22088    (range, new_text)
22089}
22090
22091fn vim_enabled(cx: &App) -> bool {
22092    vim_mode_setting::VimModeSetting::try_get(cx)
22093        .map(|vim_mode| vim_mode.0)
22094        .unwrap_or(false)
22095}
22096
22097fn process_completion_for_edit(
22098    completion: &Completion,
22099    intent: CompletionIntent,
22100    buffer: &Entity<Buffer>,
22101    cursor_position: &text::Anchor,
22102    cx: &mut Context<Editor>,
22103) -> CompletionEdit {
22104    let buffer = buffer.read(cx);
22105    let buffer_snapshot = buffer.snapshot();
22106    let (snippet, new_text) = if completion.is_snippet() {
22107        let mut snippet_source = completion.new_text.clone();
22108        // Workaround for typescript language server issues so that methods don't expand within
22109        // strings and functions with type expressions. The previous point is used because the query
22110        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
22111        let previous_point = text::ToPoint::to_point(cursor_position, &buffer_snapshot);
22112        let previous_point = if previous_point.column > 0 {
22113            cursor_position.to_previous_offset(&buffer_snapshot)
22114        } else {
22115            cursor_position.to_offset(&buffer_snapshot)
22116        };
22117        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
22118            && scope.prefers_label_for_snippet_in_completion()
22119            && let Some(label) = completion.label()
22120            && matches!(
22121                completion.kind(),
22122                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
22123            )
22124        {
22125            snippet_source = label;
22126        }
22127        match Snippet::parse(&snippet_source).log_err() {
22128            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
22129            None => (None, completion.new_text.clone()),
22130        }
22131    } else {
22132        (None, completion.new_text.clone())
22133    };
22134
22135    let mut range_to_replace = {
22136        let replace_range = &completion.replace_range;
22137        if let CompletionSource::Lsp {
22138            insert_range: Some(insert_range),
22139            ..
22140        } = &completion.source
22141        {
22142            debug_assert_eq!(
22143                insert_range.start, replace_range.start,
22144                "insert_range and replace_range should start at the same position"
22145            );
22146            debug_assert!(
22147                insert_range
22148                    .start
22149                    .cmp(cursor_position, &buffer_snapshot)
22150                    .is_le(),
22151                "insert_range should start before or at cursor position"
22152            );
22153            debug_assert!(
22154                replace_range
22155                    .start
22156                    .cmp(cursor_position, &buffer_snapshot)
22157                    .is_le(),
22158                "replace_range should start before or at cursor position"
22159            );
22160
22161            let should_replace = match intent {
22162                CompletionIntent::CompleteWithInsert => false,
22163                CompletionIntent::CompleteWithReplace => true,
22164                CompletionIntent::Complete | CompletionIntent::Compose => {
22165                    let insert_mode =
22166                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
22167                            .completions
22168                            .lsp_insert_mode;
22169                    match insert_mode {
22170                        LspInsertMode::Insert => false,
22171                        LspInsertMode::Replace => true,
22172                        LspInsertMode::ReplaceSubsequence => {
22173                            let mut text_to_replace = buffer.chars_for_range(
22174                                buffer.anchor_before(replace_range.start)
22175                                    ..buffer.anchor_after(replace_range.end),
22176                            );
22177                            let mut current_needle = text_to_replace.next();
22178                            for haystack_ch in completion.label.text.chars() {
22179                                if let Some(needle_ch) = current_needle
22180                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
22181                                {
22182                                    current_needle = text_to_replace.next();
22183                                }
22184                            }
22185                            current_needle.is_none()
22186                        }
22187                        LspInsertMode::ReplaceSuffix => {
22188                            if replace_range
22189                                .end
22190                                .cmp(cursor_position, &buffer_snapshot)
22191                                .is_gt()
22192                            {
22193                                let range_after_cursor = *cursor_position..replace_range.end;
22194                                let text_after_cursor = buffer
22195                                    .text_for_range(
22196                                        buffer.anchor_before(range_after_cursor.start)
22197                                            ..buffer.anchor_after(range_after_cursor.end),
22198                                    )
22199                                    .collect::<String>()
22200                                    .to_ascii_lowercase();
22201                                completion
22202                                    .label
22203                                    .text
22204                                    .to_ascii_lowercase()
22205                                    .ends_with(&text_after_cursor)
22206                            } else {
22207                                true
22208                            }
22209                        }
22210                    }
22211                }
22212            };
22213
22214            if should_replace {
22215                replace_range.clone()
22216            } else {
22217                insert_range.clone()
22218            }
22219        } else {
22220            replace_range.clone()
22221        }
22222    };
22223
22224    if range_to_replace
22225        .end
22226        .cmp(cursor_position, &buffer_snapshot)
22227        .is_lt()
22228    {
22229        range_to_replace.end = *cursor_position;
22230    }
22231
22232    CompletionEdit {
22233        new_text,
22234        replace_range: range_to_replace.to_offset(buffer),
22235        snippet,
22236    }
22237}
22238
22239struct CompletionEdit {
22240    new_text: String,
22241    replace_range: Range<usize>,
22242    snippet: Option<Snippet>,
22243}
22244
22245fn insert_extra_newline_brackets(
22246    buffer: &MultiBufferSnapshot,
22247    range: Range<usize>,
22248    language: &language::LanguageScope,
22249) -> bool {
22250    let leading_whitespace_len = buffer
22251        .reversed_chars_at(range.start)
22252        .take_while(|c| c.is_whitespace() && *c != '\n')
22253        .map(|c| c.len_utf8())
22254        .sum::<usize>();
22255    let trailing_whitespace_len = buffer
22256        .chars_at(range.end)
22257        .take_while(|c| c.is_whitespace() && *c != '\n')
22258        .map(|c| c.len_utf8())
22259        .sum::<usize>();
22260    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
22261
22262    language.brackets().any(|(pair, enabled)| {
22263        let pair_start = pair.start.trim_end();
22264        let pair_end = pair.end.trim_start();
22265
22266        enabled
22267            && pair.newline
22268            && buffer.contains_str_at(range.end, pair_end)
22269            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
22270    })
22271}
22272
22273fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
22274    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
22275        [(buffer, range, _)] => (*buffer, range.clone()),
22276        _ => return false,
22277    };
22278    let pair = {
22279        let mut result: Option<BracketMatch> = None;
22280
22281        for pair in buffer
22282            .all_bracket_ranges(range.clone())
22283            .filter(move |pair| {
22284                pair.open_range.start <= range.start && pair.close_range.end >= range.end
22285            })
22286        {
22287            let len = pair.close_range.end - pair.open_range.start;
22288
22289            if let Some(existing) = &result {
22290                let existing_len = existing.close_range.end - existing.open_range.start;
22291                if len > existing_len {
22292                    continue;
22293                }
22294            }
22295
22296            result = Some(pair);
22297        }
22298
22299        result
22300    };
22301    let Some(pair) = pair else {
22302        return false;
22303    };
22304    pair.newline_only
22305        && buffer
22306            .chars_for_range(pair.open_range.end..range.start)
22307            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
22308            .all(|c| c.is_whitespace() && c != '\n')
22309}
22310
22311fn update_uncommitted_diff_for_buffer(
22312    editor: Entity<Editor>,
22313    project: &Entity<Project>,
22314    buffers: impl IntoIterator<Item = Entity<Buffer>>,
22315    buffer: Entity<MultiBuffer>,
22316    cx: &mut App,
22317) -> Task<()> {
22318    let mut tasks = Vec::new();
22319    project.update(cx, |project, cx| {
22320        for buffer in buffers {
22321            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
22322                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
22323            }
22324        }
22325    });
22326    cx.spawn(async move |cx| {
22327        let diffs = future::join_all(tasks).await;
22328        if editor
22329            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
22330            .unwrap_or(false)
22331        {
22332            return;
22333        }
22334
22335        buffer
22336            .update(cx, |buffer, cx| {
22337                for diff in diffs.into_iter().flatten() {
22338                    buffer.add_diff(diff, cx);
22339                }
22340            })
22341            .ok();
22342    })
22343}
22344
22345fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
22346    let tab_size = tab_size.get() as usize;
22347    let mut width = offset;
22348
22349    for ch in text.chars() {
22350        width += if ch == '\t' {
22351            tab_size - (width % tab_size)
22352        } else {
22353            1
22354        };
22355    }
22356
22357    width - offset
22358}
22359
22360#[cfg(test)]
22361mod tests {
22362    use super::*;
22363
22364    #[test]
22365    fn test_string_size_with_expanded_tabs() {
22366        let nz = |val| NonZeroU32::new(val).unwrap();
22367        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
22368        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
22369        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
22370        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
22371        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
22372        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
22373        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
22374        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
22375    }
22376}
22377
22378/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
22379struct WordBreakingTokenizer<'a> {
22380    input: &'a str,
22381}
22382
22383impl<'a> WordBreakingTokenizer<'a> {
22384    fn new(input: &'a str) -> Self {
22385        Self { input }
22386    }
22387}
22388
22389fn is_char_ideographic(ch: char) -> bool {
22390    use unicode_script::Script::*;
22391    use unicode_script::UnicodeScript;
22392    matches!(ch.script(), Han | Tangut | Yi)
22393}
22394
22395fn is_grapheme_ideographic(text: &str) -> bool {
22396    text.chars().any(is_char_ideographic)
22397}
22398
22399fn is_grapheme_whitespace(text: &str) -> bool {
22400    text.chars().any(|x| x.is_whitespace())
22401}
22402
22403fn should_stay_with_preceding_ideograph(text: &str) -> bool {
22404    text.chars()
22405        .next()
22406        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
22407}
22408
22409#[derive(PartialEq, Eq, Debug, Clone, Copy)]
22410enum WordBreakToken<'a> {
22411    Word { token: &'a str, grapheme_len: usize },
22412    InlineWhitespace { token: &'a str, grapheme_len: usize },
22413    Newline,
22414}
22415
22416impl<'a> Iterator for WordBreakingTokenizer<'a> {
22417    /// Yields a span, the count of graphemes in the token, and whether it was
22418    /// whitespace. Note that it also breaks at word boundaries.
22419    type Item = WordBreakToken<'a>;
22420
22421    fn next(&mut self) -> Option<Self::Item> {
22422        use unicode_segmentation::UnicodeSegmentation;
22423        if self.input.is_empty() {
22424            return None;
22425        }
22426
22427        let mut iter = self.input.graphemes(true).peekable();
22428        let mut offset = 0;
22429        let mut grapheme_len = 0;
22430        if let Some(first_grapheme) = iter.next() {
22431            let is_newline = first_grapheme == "\n";
22432            let is_whitespace = is_grapheme_whitespace(first_grapheme);
22433            offset += first_grapheme.len();
22434            grapheme_len += 1;
22435            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
22436                if let Some(grapheme) = iter.peek().copied()
22437                    && should_stay_with_preceding_ideograph(grapheme)
22438                {
22439                    offset += grapheme.len();
22440                    grapheme_len += 1;
22441                }
22442            } else {
22443                let mut words = self.input[offset..].split_word_bound_indices().peekable();
22444                let mut next_word_bound = words.peek().copied();
22445                if next_word_bound.is_some_and(|(i, _)| i == 0) {
22446                    next_word_bound = words.next();
22447                }
22448                while let Some(grapheme) = iter.peek().copied() {
22449                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
22450                        break;
22451                    };
22452                    if is_grapheme_whitespace(grapheme) != is_whitespace
22453                        || (grapheme == "\n") != is_newline
22454                    {
22455                        break;
22456                    };
22457                    offset += grapheme.len();
22458                    grapheme_len += 1;
22459                    iter.next();
22460                }
22461            }
22462            let token = &self.input[..offset];
22463            self.input = &self.input[offset..];
22464            if token == "\n" {
22465                Some(WordBreakToken::Newline)
22466            } else if is_whitespace {
22467                Some(WordBreakToken::InlineWhitespace {
22468                    token,
22469                    grapheme_len,
22470                })
22471            } else {
22472                Some(WordBreakToken::Word {
22473                    token,
22474                    grapheme_len,
22475                })
22476            }
22477        } else {
22478            None
22479        }
22480    }
22481}
22482
22483#[test]
22484fn test_word_breaking_tokenizer() {
22485    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
22486        ("", &[]),
22487        ("  ", &[whitespace("  ", 2)]),
22488        ("Ʒ", &[word("Ʒ", 1)]),
22489        ("Ǽ", &[word("Ǽ", 1)]),
22490        ("⋑", &[word("⋑", 1)]),
22491        ("⋑⋑", &[word("⋑⋑", 2)]),
22492        (
22493            "原理,进而",
22494            &[word("原", 1), word("理,", 2), word("进", 1), word("而", 1)],
22495        ),
22496        (
22497            "hello world",
22498            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
22499        ),
22500        (
22501            "hello, world",
22502            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
22503        ),
22504        (
22505            "  hello world",
22506            &[
22507                whitespace("  ", 2),
22508                word("hello", 5),
22509                whitespace(" ", 1),
22510                word("world", 5),
22511            ],
22512        ),
22513        (
22514            "这是什么 \n 钢笔",
22515            &[
22516                word("这", 1),
22517                word("是", 1),
22518                word("什", 1),
22519                word("么", 1),
22520                whitespace(" ", 1),
22521                newline(),
22522                whitespace(" ", 1),
22523                word("钢", 1),
22524                word("笔", 1),
22525            ],
22526        ),
22527        (" mutton", &[whitespace(" ", 1), word("mutton", 6)]),
22528    ];
22529
22530    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22531        WordBreakToken::Word {
22532            token,
22533            grapheme_len,
22534        }
22535    }
22536
22537    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22538        WordBreakToken::InlineWhitespace {
22539            token,
22540            grapheme_len,
22541        }
22542    }
22543
22544    fn newline() -> WordBreakToken<'static> {
22545        WordBreakToken::Newline
22546    }
22547
22548    for (input, result) in tests {
22549        assert_eq!(
22550            WordBreakingTokenizer::new(input)
22551                .collect::<Vec<_>>()
22552                .as_slice(),
22553            *result,
22554        );
22555    }
22556}
22557
22558fn wrap_with_prefix(
22559    first_line_prefix: String,
22560    subsequent_lines_prefix: String,
22561    unwrapped_text: String,
22562    wrap_column: usize,
22563    tab_size: NonZeroU32,
22564    preserve_existing_whitespace: bool,
22565) -> String {
22566    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
22567    let subsequent_lines_prefix_len =
22568        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
22569    let mut wrapped_text = String::new();
22570    let mut current_line = first_line_prefix;
22571    let mut is_first_line = true;
22572
22573    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
22574    let mut current_line_len = first_line_prefix_len;
22575    let mut in_whitespace = false;
22576    for token in tokenizer {
22577        let have_preceding_whitespace = in_whitespace;
22578        match token {
22579            WordBreakToken::Word {
22580                token,
22581                grapheme_len,
22582            } => {
22583                in_whitespace = false;
22584                let current_prefix_len = if is_first_line {
22585                    first_line_prefix_len
22586                } else {
22587                    subsequent_lines_prefix_len
22588                };
22589                if current_line_len + grapheme_len > wrap_column
22590                    && current_line_len != current_prefix_len
22591                {
22592                    wrapped_text.push_str(current_line.trim_end());
22593                    wrapped_text.push('\n');
22594                    is_first_line = false;
22595                    current_line = subsequent_lines_prefix.clone();
22596                    current_line_len = subsequent_lines_prefix_len;
22597                }
22598                current_line.push_str(token);
22599                current_line_len += grapheme_len;
22600            }
22601            WordBreakToken::InlineWhitespace {
22602                mut token,
22603                mut grapheme_len,
22604            } => {
22605                in_whitespace = true;
22606                if have_preceding_whitespace && !preserve_existing_whitespace {
22607                    continue;
22608                }
22609                if !preserve_existing_whitespace {
22610                    // Keep a single whitespace grapheme as-is
22611                    if let Some(first) =
22612                        unicode_segmentation::UnicodeSegmentation::graphemes(token, true).next()
22613                    {
22614                        token = first;
22615                    } else {
22616                        token = " ";
22617                    }
22618                    grapheme_len = 1;
22619                }
22620                let current_prefix_len = if is_first_line {
22621                    first_line_prefix_len
22622                } else {
22623                    subsequent_lines_prefix_len
22624                };
22625                if current_line_len + grapheme_len > wrap_column {
22626                    wrapped_text.push_str(current_line.trim_end());
22627                    wrapped_text.push('\n');
22628                    is_first_line = false;
22629                    current_line = subsequent_lines_prefix.clone();
22630                    current_line_len = subsequent_lines_prefix_len;
22631                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
22632                    current_line.push_str(token);
22633                    current_line_len += grapheme_len;
22634                }
22635            }
22636            WordBreakToken::Newline => {
22637                in_whitespace = true;
22638                let current_prefix_len = if is_first_line {
22639                    first_line_prefix_len
22640                } else {
22641                    subsequent_lines_prefix_len
22642                };
22643                if preserve_existing_whitespace {
22644                    wrapped_text.push_str(current_line.trim_end());
22645                    wrapped_text.push('\n');
22646                    is_first_line = false;
22647                    current_line = subsequent_lines_prefix.clone();
22648                    current_line_len = subsequent_lines_prefix_len;
22649                } else if have_preceding_whitespace {
22650                    continue;
22651                } else if current_line_len + 1 > wrap_column
22652                    && current_line_len != current_prefix_len
22653                {
22654                    wrapped_text.push_str(current_line.trim_end());
22655                    wrapped_text.push('\n');
22656                    is_first_line = false;
22657                    current_line = subsequent_lines_prefix.clone();
22658                    current_line_len = subsequent_lines_prefix_len;
22659                } else if current_line_len != current_prefix_len {
22660                    current_line.push(' ');
22661                    current_line_len += 1;
22662                }
22663            }
22664        }
22665    }
22666
22667    if !current_line.is_empty() {
22668        wrapped_text.push_str(¤t_line);
22669    }
22670    wrapped_text
22671}
22672
22673#[test]
22674fn test_wrap_with_prefix() {
22675    assert_eq!(
22676        wrap_with_prefix(
22677            "# ".to_string(),
22678            "# ".to_string(),
22679            "abcdefg".to_string(),
22680            4,
22681            NonZeroU32::new(4).unwrap(),
22682            false,
22683        ),
22684        "# abcdefg"
22685    );
22686    assert_eq!(
22687        wrap_with_prefix(
22688            "".to_string(),
22689            "".to_string(),
22690            "\thello world".to_string(),
22691            8,
22692            NonZeroU32::new(4).unwrap(),
22693            false,
22694        ),
22695        "hello\nworld"
22696    );
22697    assert_eq!(
22698        wrap_with_prefix(
22699            "// ".to_string(),
22700            "// ".to_string(),
22701            "xx \nyy zz aa bb cc".to_string(),
22702            12,
22703            NonZeroU32::new(4).unwrap(),
22704            false,
22705        ),
22706        "// xx yy zz\n// aa bb cc"
22707    );
22708    assert_eq!(
22709        wrap_with_prefix(
22710            String::new(),
22711            String::new(),
22712            "这是什么 \n 钢笔".to_string(),
22713            3,
22714            NonZeroU32::new(4).unwrap(),
22715            false,
22716        ),
22717        "这是什\n么 钢\n笔"
22718    );
22719    assert_eq!(
22720        wrap_with_prefix(
22721            String::new(),
22722            String::new(),
22723            format!("foo{}bar", '\u{2009}'), // thin space
22724            80,
22725            NonZeroU32::new(4).unwrap(),
22726            false,
22727        ),
22728        format!("foo{}bar", '\u{2009}')
22729    );
22730}
22731
22732pub trait CollaborationHub {
22733    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
22734    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
22735    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
22736}
22737
22738impl CollaborationHub for Entity<Project> {
22739    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
22740        self.read(cx).collaborators()
22741    }
22742
22743    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
22744        self.read(cx).user_store().read(cx).participant_indices()
22745    }
22746
22747    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
22748        let this = self.read(cx);
22749        let user_ids = this.collaborators().values().map(|c| c.user_id);
22750        this.user_store().read(cx).participant_names(user_ids, cx)
22751    }
22752}
22753
22754pub trait SemanticsProvider {
22755    fn hover(
22756        &self,
22757        buffer: &Entity<Buffer>,
22758        position: text::Anchor,
22759        cx: &mut App,
22760    ) -> Option<Task<Option<Vec<project::Hover>>>>;
22761
22762    fn inline_values(
22763        &self,
22764        buffer_handle: Entity<Buffer>,
22765        range: Range<text::Anchor>,
22766        cx: &mut App,
22767    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22768
22769    fn applicable_inlay_chunks(
22770        &self,
22771        buffer: &Entity<Buffer>,
22772        ranges: &[Range<text::Anchor>],
22773        cx: &mut App,
22774    ) -> Vec<Range<BufferRow>>;
22775
22776    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App);
22777
22778    fn inlay_hints(
22779        &self,
22780        invalidate: InvalidationStrategy,
22781        buffer: Entity<Buffer>,
22782        ranges: Vec<Range<text::Anchor>>,
22783        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
22784        cx: &mut App,
22785    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>>;
22786
22787    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
22788
22789    fn document_highlights(
22790        &self,
22791        buffer: &Entity<Buffer>,
22792        position: text::Anchor,
22793        cx: &mut App,
22794    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
22795
22796    fn definitions(
22797        &self,
22798        buffer: &Entity<Buffer>,
22799        position: text::Anchor,
22800        kind: GotoDefinitionKind,
22801        cx: &mut App,
22802    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
22803
22804    fn range_for_rename(
22805        &self,
22806        buffer: &Entity<Buffer>,
22807        position: text::Anchor,
22808        cx: &mut App,
22809    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
22810
22811    fn perform_rename(
22812        &self,
22813        buffer: &Entity<Buffer>,
22814        position: text::Anchor,
22815        new_name: String,
22816        cx: &mut App,
22817    ) -> Option<Task<Result<ProjectTransaction>>>;
22818}
22819
22820pub trait CompletionProvider {
22821    fn completions(
22822        &self,
22823        excerpt_id: ExcerptId,
22824        buffer: &Entity<Buffer>,
22825        buffer_position: text::Anchor,
22826        trigger: CompletionContext,
22827        window: &mut Window,
22828        cx: &mut Context<Editor>,
22829    ) -> Task<Result<Vec<CompletionResponse>>>;
22830
22831    fn resolve_completions(
22832        &self,
22833        _buffer: Entity<Buffer>,
22834        _completion_indices: Vec<usize>,
22835        _completions: Rc<RefCell<Box<[Completion]>>>,
22836        _cx: &mut Context<Editor>,
22837    ) -> Task<Result<bool>> {
22838        Task::ready(Ok(false))
22839    }
22840
22841    fn apply_additional_edits_for_completion(
22842        &self,
22843        _buffer: Entity<Buffer>,
22844        _completions: Rc<RefCell<Box<[Completion]>>>,
22845        _completion_index: usize,
22846        _push_to_history: bool,
22847        _cx: &mut Context<Editor>,
22848    ) -> Task<Result<Option<language::Transaction>>> {
22849        Task::ready(Ok(None))
22850    }
22851
22852    fn is_completion_trigger(
22853        &self,
22854        buffer: &Entity<Buffer>,
22855        position: language::Anchor,
22856        text: &str,
22857        trigger_in_words: bool,
22858        menu_is_open: bool,
22859        cx: &mut Context<Editor>,
22860    ) -> bool;
22861
22862    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
22863
22864    fn sort_completions(&self) -> bool {
22865        true
22866    }
22867
22868    fn filter_completions(&self) -> bool {
22869        true
22870    }
22871}
22872
22873pub trait CodeActionProvider {
22874    fn id(&self) -> Arc<str>;
22875
22876    fn code_actions(
22877        &self,
22878        buffer: &Entity<Buffer>,
22879        range: Range<text::Anchor>,
22880        window: &mut Window,
22881        cx: &mut App,
22882    ) -> Task<Result<Vec<CodeAction>>>;
22883
22884    fn apply_code_action(
22885        &self,
22886        buffer_handle: Entity<Buffer>,
22887        action: CodeAction,
22888        excerpt_id: ExcerptId,
22889        push_to_history: bool,
22890        window: &mut Window,
22891        cx: &mut App,
22892    ) -> Task<Result<ProjectTransaction>>;
22893}
22894
22895impl CodeActionProvider for Entity<Project> {
22896    fn id(&self) -> Arc<str> {
22897        "project".into()
22898    }
22899
22900    fn code_actions(
22901        &self,
22902        buffer: &Entity<Buffer>,
22903        range: Range<text::Anchor>,
22904        _window: &mut Window,
22905        cx: &mut App,
22906    ) -> Task<Result<Vec<CodeAction>>> {
22907        self.update(cx, |project, cx| {
22908            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
22909            let code_actions = project.code_actions(buffer, range, None, cx);
22910            cx.background_spawn(async move {
22911                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
22912                Ok(code_lens_actions
22913                    .context("code lens fetch")?
22914                    .into_iter()
22915                    .flatten()
22916                    .chain(
22917                        code_actions
22918                            .context("code action fetch")?
22919                            .into_iter()
22920                            .flatten(),
22921                    )
22922                    .collect())
22923            })
22924        })
22925    }
22926
22927    fn apply_code_action(
22928        &self,
22929        buffer_handle: Entity<Buffer>,
22930        action: CodeAction,
22931        _excerpt_id: ExcerptId,
22932        push_to_history: bool,
22933        _window: &mut Window,
22934        cx: &mut App,
22935    ) -> Task<Result<ProjectTransaction>> {
22936        self.update(cx, |project, cx| {
22937            project.apply_code_action(buffer_handle, action, push_to_history, cx)
22938        })
22939    }
22940}
22941
22942fn snippet_completions(
22943    project: &Project,
22944    buffer: &Entity<Buffer>,
22945    buffer_position: text::Anchor,
22946    cx: &mut App,
22947) -> Task<Result<CompletionResponse>> {
22948    let languages = buffer.read(cx).languages_at(buffer_position);
22949    let snippet_store = project.snippets().read(cx);
22950
22951    let scopes: Vec<_> = languages
22952        .iter()
22953        .filter_map(|language| {
22954            let language_name = language.lsp_id();
22955            let snippets = snippet_store.snippets_for(Some(language_name), cx);
22956
22957            if snippets.is_empty() {
22958                None
22959            } else {
22960                Some((language.default_scope(), snippets))
22961            }
22962        })
22963        .collect();
22964
22965    if scopes.is_empty() {
22966        return Task::ready(Ok(CompletionResponse {
22967            completions: vec![],
22968            display_options: CompletionDisplayOptions::default(),
22969            is_incomplete: false,
22970        }));
22971    }
22972
22973    let snapshot = buffer.read(cx).text_snapshot();
22974    let executor = cx.background_executor().clone();
22975
22976    cx.background_spawn(async move {
22977        let mut is_incomplete = false;
22978        let mut completions: Vec<Completion> = Vec::new();
22979        for (scope, snippets) in scopes.into_iter() {
22980            let classifier =
22981                CharClassifier::new(Some(scope)).scope_context(Some(CharScopeContext::Completion));
22982
22983            const MAX_WORD_PREFIX_LEN: usize = 128;
22984            let last_word: String = snapshot
22985                .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
22986                .take(MAX_WORD_PREFIX_LEN)
22987                .take_while(|c| classifier.is_word(*c))
22988                .collect::<String>()
22989                .chars()
22990                .rev()
22991                .collect();
22992
22993            if last_word.is_empty() {
22994                return Ok(CompletionResponse {
22995                    completions: vec![],
22996                    display_options: CompletionDisplayOptions::default(),
22997                    is_incomplete: true,
22998                });
22999            }
23000
23001            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
23002            let to_lsp = |point: &text::Anchor| {
23003                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
23004                point_to_lsp(end)
23005            };
23006            let lsp_end = to_lsp(&buffer_position);
23007
23008            let candidates = snippets
23009                .iter()
23010                .enumerate()
23011                .flat_map(|(ix, snippet)| {
23012                    snippet
23013                        .prefix
23014                        .iter()
23015                        .map(move |prefix| StringMatchCandidate::new(ix, prefix))
23016                })
23017                .collect::<Vec<StringMatchCandidate>>();
23018
23019            const MAX_RESULTS: usize = 100;
23020            let mut matches = fuzzy::match_strings(
23021                &candidates,
23022                &last_word,
23023                last_word.chars().any(|c| c.is_uppercase()),
23024                true,
23025                MAX_RESULTS,
23026                &Default::default(),
23027                executor.clone(),
23028            )
23029            .await;
23030
23031            if matches.len() >= MAX_RESULTS {
23032                is_incomplete = true;
23033            }
23034
23035            // Remove all candidates where the query's start does not match the start of any word in the candidate
23036            if let Some(query_start) = last_word.chars().next() {
23037                matches.retain(|string_match| {
23038                    split_words(&string_match.string).any(|word| {
23039                        // Check that the first codepoint of the word as lowercase matches the first
23040                        // codepoint of the query as lowercase
23041                        word.chars()
23042                            .flat_map(|codepoint| codepoint.to_lowercase())
23043                            .zip(query_start.to_lowercase())
23044                            .all(|(word_cp, query_cp)| word_cp == query_cp)
23045                    })
23046                });
23047            }
23048
23049            let matched_strings = matches
23050                .into_iter()
23051                .map(|m| m.string)
23052                .collect::<HashSet<_>>();
23053
23054            completions.extend(snippets.iter().filter_map(|snippet| {
23055                let matching_prefix = snippet
23056                    .prefix
23057                    .iter()
23058                    .find(|prefix| matched_strings.contains(*prefix))?;
23059                let start = as_offset - last_word.len();
23060                let start = snapshot.anchor_before(start);
23061                let range = start..buffer_position;
23062                let lsp_start = to_lsp(&start);
23063                let lsp_range = lsp::Range {
23064                    start: lsp_start,
23065                    end: lsp_end,
23066                };
23067                Some(Completion {
23068                    replace_range: range,
23069                    new_text: snippet.body.clone(),
23070                    source: CompletionSource::Lsp {
23071                        insert_range: None,
23072                        server_id: LanguageServerId(usize::MAX),
23073                        resolved: true,
23074                        lsp_completion: Box::new(lsp::CompletionItem {
23075                            label: snippet.prefix.first().unwrap().clone(),
23076                            kind: Some(CompletionItemKind::SNIPPET),
23077                            label_details: snippet.description.as_ref().map(|description| {
23078                                lsp::CompletionItemLabelDetails {
23079                                    detail: Some(description.clone()),
23080                                    description: None,
23081                                }
23082                            }),
23083                            insert_text_format: Some(InsertTextFormat::SNIPPET),
23084                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
23085                                lsp::InsertReplaceEdit {
23086                                    new_text: snippet.body.clone(),
23087                                    insert: lsp_range,
23088                                    replace: lsp_range,
23089                                },
23090                            )),
23091                            filter_text: Some(snippet.body.clone()),
23092                            sort_text: Some(char::MAX.to_string()),
23093                            ..lsp::CompletionItem::default()
23094                        }),
23095                        lsp_defaults: None,
23096                    },
23097                    label: CodeLabel::plain(matching_prefix.clone(), None),
23098                    icon_path: None,
23099                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
23100                        single_line: snippet.name.clone().into(),
23101                        plain_text: snippet
23102                            .description
23103                            .clone()
23104                            .map(|description| description.into()),
23105                    }),
23106                    insert_text_mode: None,
23107                    confirm: None,
23108                })
23109            }))
23110        }
23111
23112        Ok(CompletionResponse {
23113            completions,
23114            display_options: CompletionDisplayOptions::default(),
23115            is_incomplete,
23116        })
23117    })
23118}
23119
23120impl CompletionProvider for Entity<Project> {
23121    fn completions(
23122        &self,
23123        _excerpt_id: ExcerptId,
23124        buffer: &Entity<Buffer>,
23125        buffer_position: text::Anchor,
23126        options: CompletionContext,
23127        _window: &mut Window,
23128        cx: &mut Context<Editor>,
23129    ) -> Task<Result<Vec<CompletionResponse>>> {
23130        self.update(cx, |project, cx| {
23131            let snippets = snippet_completions(project, buffer, buffer_position, cx);
23132            let project_completions = project.completions(buffer, buffer_position, options, cx);
23133            cx.background_spawn(async move {
23134                let mut responses = project_completions.await?;
23135                let snippets = snippets.await?;
23136                if !snippets.completions.is_empty() {
23137                    responses.push(snippets);
23138                }
23139                Ok(responses)
23140            })
23141        })
23142    }
23143
23144    fn resolve_completions(
23145        &self,
23146        buffer: Entity<Buffer>,
23147        completion_indices: Vec<usize>,
23148        completions: Rc<RefCell<Box<[Completion]>>>,
23149        cx: &mut Context<Editor>,
23150    ) -> Task<Result<bool>> {
23151        self.update(cx, |project, cx| {
23152            project.lsp_store().update(cx, |lsp_store, cx| {
23153                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
23154            })
23155        })
23156    }
23157
23158    fn apply_additional_edits_for_completion(
23159        &self,
23160        buffer: Entity<Buffer>,
23161        completions: Rc<RefCell<Box<[Completion]>>>,
23162        completion_index: usize,
23163        push_to_history: bool,
23164        cx: &mut Context<Editor>,
23165    ) -> Task<Result<Option<language::Transaction>>> {
23166        self.update(cx, |project, cx| {
23167            project.lsp_store().update(cx, |lsp_store, cx| {
23168                lsp_store.apply_additional_edits_for_completion(
23169                    buffer,
23170                    completions,
23171                    completion_index,
23172                    push_to_history,
23173                    cx,
23174                )
23175            })
23176        })
23177    }
23178
23179    fn is_completion_trigger(
23180        &self,
23181        buffer: &Entity<Buffer>,
23182        position: language::Anchor,
23183        text: &str,
23184        trigger_in_words: bool,
23185        menu_is_open: bool,
23186        cx: &mut Context<Editor>,
23187    ) -> bool {
23188        let mut chars = text.chars();
23189        let char = if let Some(char) = chars.next() {
23190            char
23191        } else {
23192            return false;
23193        };
23194        if chars.next().is_some() {
23195            return false;
23196        }
23197
23198        let buffer = buffer.read(cx);
23199        let snapshot = buffer.snapshot();
23200        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
23201            return false;
23202        }
23203        let classifier = snapshot
23204            .char_classifier_at(position)
23205            .scope_context(Some(CharScopeContext::Completion));
23206        if trigger_in_words && classifier.is_word(char) {
23207            return true;
23208        }
23209
23210        buffer.completion_triggers().contains(text)
23211    }
23212}
23213
23214impl SemanticsProvider for Entity<Project> {
23215    fn hover(
23216        &self,
23217        buffer: &Entity<Buffer>,
23218        position: text::Anchor,
23219        cx: &mut App,
23220    ) -> Option<Task<Option<Vec<project::Hover>>>> {
23221        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
23222    }
23223
23224    fn document_highlights(
23225        &self,
23226        buffer: &Entity<Buffer>,
23227        position: text::Anchor,
23228        cx: &mut App,
23229    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
23230        Some(self.update(cx, |project, cx| {
23231            project.document_highlights(buffer, position, cx)
23232        }))
23233    }
23234
23235    fn definitions(
23236        &self,
23237        buffer: &Entity<Buffer>,
23238        position: text::Anchor,
23239        kind: GotoDefinitionKind,
23240        cx: &mut App,
23241    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
23242        Some(self.update(cx, |project, cx| match kind {
23243            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
23244            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
23245            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
23246            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
23247        }))
23248    }
23249
23250    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
23251        self.update(cx, |project, cx| {
23252            if project
23253                .active_debug_session(cx)
23254                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
23255            {
23256                return true;
23257            }
23258
23259            buffer.update(cx, |buffer, cx| {
23260                project.any_language_server_supports_inlay_hints(buffer, cx)
23261            })
23262        })
23263    }
23264
23265    fn inline_values(
23266        &self,
23267        buffer_handle: Entity<Buffer>,
23268        range: Range<text::Anchor>,
23269        cx: &mut App,
23270    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
23271        self.update(cx, |project, cx| {
23272            let (session, active_stack_frame) = project.active_debug_session(cx)?;
23273
23274            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
23275        })
23276    }
23277
23278    fn applicable_inlay_chunks(
23279        &self,
23280        buffer: &Entity<Buffer>,
23281        ranges: &[Range<text::Anchor>],
23282        cx: &mut App,
23283    ) -> Vec<Range<BufferRow>> {
23284        self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
23285            lsp_store.applicable_inlay_chunks(buffer, ranges, cx)
23286        })
23287    }
23288
23289    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App) {
23290        self.read(cx).lsp_store().update(cx, |lsp_store, _| {
23291            lsp_store.invalidate_inlay_hints(for_buffers)
23292        });
23293    }
23294
23295    fn inlay_hints(
23296        &self,
23297        invalidate: InvalidationStrategy,
23298        buffer: Entity<Buffer>,
23299        ranges: Vec<Range<text::Anchor>>,
23300        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
23301        cx: &mut App,
23302    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>> {
23303        Some(self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
23304            lsp_store.inlay_hints(invalidate, buffer, ranges, known_chunks, cx)
23305        }))
23306    }
23307
23308    fn range_for_rename(
23309        &self,
23310        buffer: &Entity<Buffer>,
23311        position: text::Anchor,
23312        cx: &mut App,
23313    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
23314        Some(self.update(cx, |project, cx| {
23315            let buffer = buffer.clone();
23316            let task = project.prepare_rename(buffer.clone(), position, cx);
23317            cx.spawn(async move |_, cx| {
23318                Ok(match task.await? {
23319                    PrepareRenameResponse::Success(range) => Some(range),
23320                    PrepareRenameResponse::InvalidPosition => None,
23321                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
23322                        // Fallback on using TreeSitter info to determine identifier range
23323                        buffer.read_with(cx, |buffer, _| {
23324                            let snapshot = buffer.snapshot();
23325                            let (range, kind) = snapshot.surrounding_word(position, None);
23326                            if kind != Some(CharKind::Word) {
23327                                return None;
23328                            }
23329                            Some(
23330                                snapshot.anchor_before(range.start)
23331                                    ..snapshot.anchor_after(range.end),
23332                            )
23333                        })?
23334                    }
23335                })
23336            })
23337        }))
23338    }
23339
23340    fn perform_rename(
23341        &self,
23342        buffer: &Entity<Buffer>,
23343        position: text::Anchor,
23344        new_name: String,
23345        cx: &mut App,
23346    ) -> Option<Task<Result<ProjectTransaction>>> {
23347        Some(self.update(cx, |project, cx| {
23348            project.perform_rename(buffer.clone(), position, new_name, cx)
23349        }))
23350    }
23351}
23352
23353fn consume_contiguous_rows(
23354    contiguous_row_selections: &mut Vec<Selection<Point>>,
23355    selection: &Selection<Point>,
23356    display_map: &DisplaySnapshot,
23357    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
23358) -> (MultiBufferRow, MultiBufferRow) {
23359    contiguous_row_selections.push(selection.clone());
23360    let start_row = starting_row(selection, display_map);
23361    let mut end_row = ending_row(selection, display_map);
23362
23363    while let Some(next_selection) = selections.peek() {
23364        if next_selection.start.row <= end_row.0 {
23365            end_row = ending_row(next_selection, display_map);
23366            contiguous_row_selections.push(selections.next().unwrap().clone());
23367        } else {
23368            break;
23369        }
23370    }
23371    (start_row, end_row)
23372}
23373
23374fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23375    if selection.start.column > 0 {
23376        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
23377    } else {
23378        MultiBufferRow(selection.start.row)
23379    }
23380}
23381
23382fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23383    if next_selection.end.column > 0 || next_selection.is_empty() {
23384        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
23385    } else {
23386        MultiBufferRow(next_selection.end.row)
23387    }
23388}
23389
23390impl EditorSnapshot {
23391    pub fn remote_selections_in_range<'a>(
23392        &'a self,
23393        range: &'a Range<Anchor>,
23394        collaboration_hub: &dyn CollaborationHub,
23395        cx: &'a App,
23396    ) -> impl 'a + Iterator<Item = RemoteSelection> {
23397        let participant_names = collaboration_hub.user_names(cx);
23398        let participant_indices = collaboration_hub.user_participant_indices(cx);
23399        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
23400        let collaborators_by_replica_id = collaborators_by_peer_id
23401            .values()
23402            .map(|collaborator| (collaborator.replica_id, collaborator))
23403            .collect::<HashMap<_, _>>();
23404        self.buffer_snapshot()
23405            .selections_in_range(range, false)
23406            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
23407                if replica_id == ReplicaId::AGENT {
23408                    Some(RemoteSelection {
23409                        replica_id,
23410                        selection,
23411                        cursor_shape,
23412                        line_mode,
23413                        collaborator_id: CollaboratorId::Agent,
23414                        user_name: Some("Agent".into()),
23415                        color: cx.theme().players().agent(),
23416                    })
23417                } else {
23418                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
23419                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
23420                    let user_name = participant_names.get(&collaborator.user_id).cloned();
23421                    Some(RemoteSelection {
23422                        replica_id,
23423                        selection,
23424                        cursor_shape,
23425                        line_mode,
23426                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
23427                        user_name,
23428                        color: if let Some(index) = participant_index {
23429                            cx.theme().players().color_for_participant(index.0)
23430                        } else {
23431                            cx.theme().players().absent()
23432                        },
23433                    })
23434                }
23435            })
23436    }
23437
23438    pub fn hunks_for_ranges(
23439        &self,
23440        ranges: impl IntoIterator<Item = Range<Point>>,
23441    ) -> Vec<MultiBufferDiffHunk> {
23442        let mut hunks = Vec::new();
23443        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
23444            HashMap::default();
23445        for query_range in ranges {
23446            let query_rows =
23447                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
23448            for hunk in self.buffer_snapshot().diff_hunks_in_range(
23449                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
23450            ) {
23451                // Include deleted hunks that are adjacent to the query range, because
23452                // otherwise they would be missed.
23453                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
23454                if hunk.status().is_deleted() {
23455                    intersects_range |= hunk.row_range.start == query_rows.end;
23456                    intersects_range |= hunk.row_range.end == query_rows.start;
23457                }
23458                if intersects_range {
23459                    if !processed_buffer_rows
23460                        .entry(hunk.buffer_id)
23461                        .or_default()
23462                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
23463                    {
23464                        continue;
23465                    }
23466                    hunks.push(hunk);
23467                }
23468            }
23469        }
23470
23471        hunks
23472    }
23473
23474    fn display_diff_hunks_for_rows<'a>(
23475        &'a self,
23476        display_rows: Range<DisplayRow>,
23477        folded_buffers: &'a HashSet<BufferId>,
23478    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
23479        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
23480        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
23481
23482        self.buffer_snapshot()
23483            .diff_hunks_in_range(buffer_start..buffer_end)
23484            .filter_map(|hunk| {
23485                if folded_buffers.contains(&hunk.buffer_id) {
23486                    return None;
23487                }
23488
23489                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
23490                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
23491
23492                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
23493                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
23494
23495                let display_hunk = if hunk_display_start.column() != 0 {
23496                    DisplayDiffHunk::Folded {
23497                        display_row: hunk_display_start.row(),
23498                    }
23499                } else {
23500                    let mut end_row = hunk_display_end.row();
23501                    if hunk_display_end.column() > 0 {
23502                        end_row.0 += 1;
23503                    }
23504                    let is_created_file = hunk.is_created_file();
23505                    DisplayDiffHunk::Unfolded {
23506                        status: hunk.status(),
23507                        diff_base_byte_range: hunk.diff_base_byte_range,
23508                        display_row_range: hunk_display_start.row()..end_row,
23509                        multi_buffer_range: Anchor::range_in_buffer(
23510                            hunk.excerpt_id,
23511                            hunk.buffer_id,
23512                            hunk.buffer_range,
23513                        ),
23514                        is_created_file,
23515                    }
23516                };
23517
23518                Some(display_hunk)
23519            })
23520    }
23521
23522    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
23523        self.display_snapshot
23524            .buffer_snapshot()
23525            .language_at(position)
23526    }
23527
23528    pub fn is_focused(&self) -> bool {
23529        self.is_focused
23530    }
23531
23532    pub fn placeholder_text(&self) -> Option<String> {
23533        self.placeholder_display_snapshot
23534            .as_ref()
23535            .map(|display_map| display_map.text())
23536    }
23537
23538    pub fn scroll_position(&self) -> gpui::Point<ScrollOffset> {
23539        self.scroll_anchor.scroll_position(&self.display_snapshot)
23540    }
23541
23542    fn gutter_dimensions(
23543        &self,
23544        font_id: FontId,
23545        font_size: Pixels,
23546        max_line_number_width: Pixels,
23547        cx: &App,
23548    ) -> Option<GutterDimensions> {
23549        if !self.show_gutter {
23550            return None;
23551        }
23552
23553        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
23554        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
23555
23556        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
23557            matches!(
23558                ProjectSettings::get_global(cx).git.git_gutter,
23559                GitGutterSetting::TrackedFiles
23560            )
23561        });
23562        let gutter_settings = EditorSettings::get_global(cx).gutter;
23563        let show_line_numbers = self
23564            .show_line_numbers
23565            .unwrap_or(gutter_settings.line_numbers);
23566        let line_gutter_width = if show_line_numbers {
23567            // Avoid flicker-like gutter resizes when the line number gains another digit by
23568            // only resizing the gutter on files with > 10**min_line_number_digits lines.
23569            let min_width_for_number_on_gutter =
23570                ch_advance * gutter_settings.min_line_number_digits as f32;
23571            max_line_number_width.max(min_width_for_number_on_gutter)
23572        } else {
23573            0.0.into()
23574        };
23575
23576        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
23577        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
23578
23579        let git_blame_entries_width =
23580            self.git_blame_gutter_max_author_length
23581                .map(|max_author_length| {
23582                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
23583                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
23584
23585                    /// The number of characters to dedicate to gaps and margins.
23586                    const SPACING_WIDTH: usize = 4;
23587
23588                    let max_char_count = max_author_length.min(renderer.max_author_length())
23589                        + ::git::SHORT_SHA_LENGTH
23590                        + MAX_RELATIVE_TIMESTAMP.len()
23591                        + SPACING_WIDTH;
23592
23593                    ch_advance * max_char_count
23594                });
23595
23596        let is_singleton = self.buffer_snapshot().is_singleton();
23597
23598        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
23599        left_padding += if !is_singleton {
23600            ch_width * 4.0
23601        } else if show_runnables || show_breakpoints {
23602            ch_width * 3.0
23603        } else if show_git_gutter && show_line_numbers {
23604            ch_width * 2.0
23605        } else if show_git_gutter || show_line_numbers {
23606            ch_width
23607        } else {
23608            px(0.)
23609        };
23610
23611        let shows_folds = is_singleton && gutter_settings.folds;
23612
23613        let right_padding = if shows_folds && show_line_numbers {
23614            ch_width * 4.0
23615        } else if shows_folds || (!is_singleton && show_line_numbers) {
23616            ch_width * 3.0
23617        } else if show_line_numbers {
23618            ch_width
23619        } else {
23620            px(0.)
23621        };
23622
23623        Some(GutterDimensions {
23624            left_padding,
23625            right_padding,
23626            width: line_gutter_width + left_padding + right_padding,
23627            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
23628            git_blame_entries_width,
23629        })
23630    }
23631
23632    pub fn render_crease_toggle(
23633        &self,
23634        buffer_row: MultiBufferRow,
23635        row_contains_cursor: bool,
23636        editor: Entity<Editor>,
23637        window: &mut Window,
23638        cx: &mut App,
23639    ) -> Option<AnyElement> {
23640        let folded = self.is_line_folded(buffer_row);
23641        let mut is_foldable = false;
23642
23643        if let Some(crease) = self
23644            .crease_snapshot
23645            .query_row(buffer_row, self.buffer_snapshot())
23646        {
23647            is_foldable = true;
23648            match crease {
23649                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
23650                    if let Some(render_toggle) = render_toggle {
23651                        let toggle_callback =
23652                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
23653                                if folded {
23654                                    editor.update(cx, |editor, cx| {
23655                                        editor.fold_at(buffer_row, window, cx)
23656                                    });
23657                                } else {
23658                                    editor.update(cx, |editor, cx| {
23659                                        editor.unfold_at(buffer_row, window, cx)
23660                                    });
23661                                }
23662                            });
23663                        return Some((render_toggle)(
23664                            buffer_row,
23665                            folded,
23666                            toggle_callback,
23667                            window,
23668                            cx,
23669                        ));
23670                    }
23671                }
23672            }
23673        }
23674
23675        is_foldable |= self.starts_indent(buffer_row);
23676
23677        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
23678            Some(
23679                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
23680                    .toggle_state(folded)
23681                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
23682                        if folded {
23683                            this.unfold_at(buffer_row, window, cx);
23684                        } else {
23685                            this.fold_at(buffer_row, window, cx);
23686                        }
23687                    }))
23688                    .into_any_element(),
23689            )
23690        } else {
23691            None
23692        }
23693    }
23694
23695    pub fn render_crease_trailer(
23696        &self,
23697        buffer_row: MultiBufferRow,
23698        window: &mut Window,
23699        cx: &mut App,
23700    ) -> Option<AnyElement> {
23701        let folded = self.is_line_folded(buffer_row);
23702        if let Crease::Inline { render_trailer, .. } = self
23703            .crease_snapshot
23704            .query_row(buffer_row, self.buffer_snapshot())?
23705        {
23706            let render_trailer = render_trailer.as_ref()?;
23707            Some(render_trailer(buffer_row, folded, window, cx))
23708        } else {
23709            None
23710        }
23711    }
23712}
23713
23714impl Deref for EditorSnapshot {
23715    type Target = DisplaySnapshot;
23716
23717    fn deref(&self) -> &Self::Target {
23718        &self.display_snapshot
23719    }
23720}
23721
23722#[derive(Clone, Debug, PartialEq, Eq)]
23723pub enum EditorEvent {
23724    InputIgnored {
23725        text: Arc<str>,
23726    },
23727    InputHandled {
23728        utf16_range_to_replace: Option<Range<isize>>,
23729        text: Arc<str>,
23730    },
23731    ExcerptsAdded {
23732        buffer: Entity<Buffer>,
23733        predecessor: ExcerptId,
23734        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
23735    },
23736    ExcerptsRemoved {
23737        ids: Vec<ExcerptId>,
23738        removed_buffer_ids: Vec<BufferId>,
23739    },
23740    BufferFoldToggled {
23741        ids: Vec<ExcerptId>,
23742        folded: bool,
23743    },
23744    ExcerptsEdited {
23745        ids: Vec<ExcerptId>,
23746    },
23747    ExcerptsExpanded {
23748        ids: Vec<ExcerptId>,
23749    },
23750    BufferEdited,
23751    Edited {
23752        transaction_id: clock::Lamport,
23753    },
23754    Reparsed(BufferId),
23755    Focused,
23756    FocusedIn,
23757    Blurred,
23758    DirtyChanged,
23759    Saved,
23760    TitleChanged,
23761    SelectionsChanged {
23762        local: bool,
23763    },
23764    ScrollPositionChanged {
23765        local: bool,
23766        autoscroll: bool,
23767    },
23768    TransactionUndone {
23769        transaction_id: clock::Lamport,
23770    },
23771    TransactionBegun {
23772        transaction_id: clock::Lamport,
23773    },
23774    CursorShapeChanged,
23775    BreadcrumbsChanged,
23776    PushedToNavHistory {
23777        anchor: Anchor,
23778        is_deactivate: bool,
23779    },
23780}
23781
23782impl EventEmitter<EditorEvent> for Editor {}
23783
23784impl Focusable for Editor {
23785    fn focus_handle(&self, _cx: &App) -> FocusHandle {
23786        self.focus_handle.clone()
23787    }
23788}
23789
23790impl Render for Editor {
23791    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23792        let settings = ThemeSettings::get_global(cx);
23793
23794        let mut text_style = match self.mode {
23795            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
23796                color: cx.theme().colors().editor_foreground,
23797                font_family: settings.ui_font.family.clone(),
23798                font_features: settings.ui_font.features.clone(),
23799                font_fallbacks: settings.ui_font.fallbacks.clone(),
23800                font_size: rems(0.875).into(),
23801                font_weight: settings.ui_font.weight,
23802                line_height: relative(settings.buffer_line_height.value()),
23803                ..Default::default()
23804            },
23805            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
23806                color: cx.theme().colors().editor_foreground,
23807                font_family: settings.buffer_font.family.clone(),
23808                font_features: settings.buffer_font.features.clone(),
23809                font_fallbacks: settings.buffer_font.fallbacks.clone(),
23810                font_size: settings.buffer_font_size(cx).into(),
23811                font_weight: settings.buffer_font.weight,
23812                line_height: relative(settings.buffer_line_height.value()),
23813                ..Default::default()
23814            },
23815        };
23816        if let Some(text_style_refinement) = &self.text_style_refinement {
23817            text_style.refine(text_style_refinement)
23818        }
23819
23820        let background = match self.mode {
23821            EditorMode::SingleLine => cx.theme().system().transparent,
23822            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
23823            EditorMode::Full { .. } => cx.theme().colors().editor_background,
23824            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
23825        };
23826
23827        EditorElement::new(
23828            &cx.entity(),
23829            EditorStyle {
23830                background,
23831                border: cx.theme().colors().border,
23832                local_player: cx.theme().players().local(),
23833                text: text_style,
23834                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
23835                syntax: cx.theme().syntax().clone(),
23836                status: cx.theme().status().clone(),
23837                inlay_hints_style: make_inlay_hints_style(cx),
23838                edit_prediction_styles: make_suggestion_styles(cx),
23839                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
23840                show_underlines: self.diagnostics_enabled(),
23841            },
23842        )
23843    }
23844}
23845
23846impl EntityInputHandler for Editor {
23847    fn text_for_range(
23848        &mut self,
23849        range_utf16: Range<usize>,
23850        adjusted_range: &mut Option<Range<usize>>,
23851        _: &mut Window,
23852        cx: &mut Context<Self>,
23853    ) -> Option<String> {
23854        let snapshot = self.buffer.read(cx).read(cx);
23855        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
23856        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
23857        if (start.0..end.0) != range_utf16 {
23858            adjusted_range.replace(start.0..end.0);
23859        }
23860        Some(snapshot.text_for_range(start..end).collect())
23861    }
23862
23863    fn selected_text_range(
23864        &mut self,
23865        ignore_disabled_input: bool,
23866        _: &mut Window,
23867        cx: &mut Context<Self>,
23868    ) -> Option<UTF16Selection> {
23869        // Prevent the IME menu from appearing when holding down an alphabetic key
23870        // while input is disabled.
23871        if !ignore_disabled_input && !self.input_enabled {
23872            return None;
23873        }
23874
23875        let selection = self
23876            .selections
23877            .newest::<OffsetUtf16>(&self.display_snapshot(cx));
23878        let range = selection.range();
23879
23880        Some(UTF16Selection {
23881            range: range.start.0..range.end.0,
23882            reversed: selection.reversed,
23883        })
23884    }
23885
23886    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
23887        let snapshot = self.buffer.read(cx).read(cx);
23888        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
23889        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
23890    }
23891
23892    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
23893        self.clear_highlights::<InputComposition>(cx);
23894        self.ime_transaction.take();
23895    }
23896
23897    fn replace_text_in_range(
23898        &mut self,
23899        range_utf16: Option<Range<usize>>,
23900        text: &str,
23901        window: &mut Window,
23902        cx: &mut Context<Self>,
23903    ) {
23904        if !self.input_enabled {
23905            cx.emit(EditorEvent::InputIgnored { text: text.into() });
23906            return;
23907        }
23908
23909        self.transact(window, cx, |this, window, cx| {
23910            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
23911                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23912                Some(this.selection_replacement_ranges(range_utf16, cx))
23913            } else {
23914                this.marked_text_ranges(cx)
23915            };
23916
23917            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
23918                let newest_selection_id = this.selections.newest_anchor().id;
23919                this.selections
23920                    .all::<OffsetUtf16>(&this.display_snapshot(cx))
23921                    .iter()
23922                    .zip(ranges_to_replace.iter())
23923                    .find_map(|(selection, range)| {
23924                        if selection.id == newest_selection_id {
23925                            Some(
23926                                (range.start.0 as isize - selection.head().0 as isize)
23927                                    ..(range.end.0 as isize - selection.head().0 as isize),
23928                            )
23929                        } else {
23930                            None
23931                        }
23932                    })
23933            });
23934
23935            cx.emit(EditorEvent::InputHandled {
23936                utf16_range_to_replace: range_to_replace,
23937                text: text.into(),
23938            });
23939
23940            if let Some(new_selected_ranges) = new_selected_ranges {
23941                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23942                    selections.select_ranges(new_selected_ranges)
23943                });
23944                this.backspace(&Default::default(), window, cx);
23945            }
23946
23947            this.handle_input(text, window, cx);
23948        });
23949
23950        if let Some(transaction) = self.ime_transaction {
23951            self.buffer.update(cx, |buffer, cx| {
23952                buffer.group_until_transaction(transaction, cx);
23953            });
23954        }
23955
23956        self.unmark_text(window, cx);
23957    }
23958
23959    fn replace_and_mark_text_in_range(
23960        &mut self,
23961        range_utf16: Option<Range<usize>>,
23962        text: &str,
23963        new_selected_range_utf16: Option<Range<usize>>,
23964        window: &mut Window,
23965        cx: &mut Context<Self>,
23966    ) {
23967        if !self.input_enabled {
23968            return;
23969        }
23970
23971        let transaction = self.transact(window, cx, |this, window, cx| {
23972            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
23973                let snapshot = this.buffer.read(cx).read(cx);
23974                if let Some(relative_range_utf16) = range_utf16.as_ref() {
23975                    for marked_range in &mut marked_ranges {
23976                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
23977                        marked_range.start.0 += relative_range_utf16.start;
23978                        marked_range.start =
23979                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
23980                        marked_range.end =
23981                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
23982                    }
23983                }
23984                Some(marked_ranges)
23985            } else if let Some(range_utf16) = range_utf16 {
23986                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23987                Some(this.selection_replacement_ranges(range_utf16, cx))
23988            } else {
23989                None
23990            };
23991
23992            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
23993                let newest_selection_id = this.selections.newest_anchor().id;
23994                this.selections
23995                    .all::<OffsetUtf16>(&this.display_snapshot(cx))
23996                    .iter()
23997                    .zip(ranges_to_replace.iter())
23998                    .find_map(|(selection, range)| {
23999                        if selection.id == newest_selection_id {
24000                            Some(
24001                                (range.start.0 as isize - selection.head().0 as isize)
24002                                    ..(range.end.0 as isize - selection.head().0 as isize),
24003                            )
24004                        } else {
24005                            None
24006                        }
24007                    })
24008            });
24009
24010            cx.emit(EditorEvent::InputHandled {
24011                utf16_range_to_replace: range_to_replace,
24012                text: text.into(),
24013            });
24014
24015            if let Some(ranges) = ranges_to_replace {
24016                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
24017                    s.select_ranges(ranges)
24018                });
24019            }
24020
24021            let marked_ranges = {
24022                let snapshot = this.buffer.read(cx).read(cx);
24023                this.selections
24024                    .disjoint_anchors_arc()
24025                    .iter()
24026                    .map(|selection| {
24027                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
24028                    })
24029                    .collect::<Vec<_>>()
24030            };
24031
24032            if text.is_empty() {
24033                this.unmark_text(window, cx);
24034            } else {
24035                this.highlight_text::<InputComposition>(
24036                    marked_ranges.clone(),
24037                    HighlightStyle {
24038                        underline: Some(UnderlineStyle {
24039                            thickness: px(1.),
24040                            color: None,
24041                            wavy: false,
24042                        }),
24043                        ..Default::default()
24044                    },
24045                    cx,
24046                );
24047            }
24048
24049            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
24050            let use_autoclose = this.use_autoclose;
24051            let use_auto_surround = this.use_auto_surround;
24052            this.set_use_autoclose(false);
24053            this.set_use_auto_surround(false);
24054            this.handle_input(text, window, cx);
24055            this.set_use_autoclose(use_autoclose);
24056            this.set_use_auto_surround(use_auto_surround);
24057
24058            if let Some(new_selected_range) = new_selected_range_utf16 {
24059                let snapshot = this.buffer.read(cx).read(cx);
24060                let new_selected_ranges = marked_ranges
24061                    .into_iter()
24062                    .map(|marked_range| {
24063                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
24064                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
24065                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
24066                        snapshot.clip_offset_utf16(new_start, Bias::Left)
24067                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
24068                    })
24069                    .collect::<Vec<_>>();
24070
24071                drop(snapshot);
24072                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
24073                    selections.select_ranges(new_selected_ranges)
24074                });
24075            }
24076        });
24077
24078        self.ime_transaction = self.ime_transaction.or(transaction);
24079        if let Some(transaction) = self.ime_transaction {
24080            self.buffer.update(cx, |buffer, cx| {
24081                buffer.group_until_transaction(transaction, cx);
24082            });
24083        }
24084
24085        if self.text_highlights::<InputComposition>(cx).is_none() {
24086            self.ime_transaction.take();
24087        }
24088    }
24089
24090    fn bounds_for_range(
24091        &mut self,
24092        range_utf16: Range<usize>,
24093        element_bounds: gpui::Bounds<Pixels>,
24094        window: &mut Window,
24095        cx: &mut Context<Self>,
24096    ) -> Option<gpui::Bounds<Pixels>> {
24097        let text_layout_details = self.text_layout_details(window);
24098        let CharacterDimensions {
24099            em_width,
24100            em_advance,
24101            line_height,
24102        } = self.character_dimensions(window);
24103
24104        let snapshot = self.snapshot(window, cx);
24105        let scroll_position = snapshot.scroll_position();
24106        let scroll_left = scroll_position.x * ScrollOffset::from(em_advance);
24107
24108        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
24109        let x = Pixels::from(
24110            ScrollOffset::from(
24111                snapshot.x_for_display_point(start, &text_layout_details)
24112                    + self.gutter_dimensions.full_width(),
24113            ) - scroll_left,
24114        );
24115        let y = line_height * (start.row().as_f64() - scroll_position.y) as f32;
24116
24117        Some(Bounds {
24118            origin: element_bounds.origin + point(x, y),
24119            size: size(em_width, line_height),
24120        })
24121    }
24122
24123    fn character_index_for_point(
24124        &mut self,
24125        point: gpui::Point<Pixels>,
24126        _window: &mut Window,
24127        _cx: &mut Context<Self>,
24128    ) -> Option<usize> {
24129        let position_map = self.last_position_map.as_ref()?;
24130        if !position_map.text_hitbox.contains(&point) {
24131            return None;
24132        }
24133        let display_point = position_map.point_for_position(point).previous_valid;
24134        let anchor = position_map
24135            .snapshot
24136            .display_point_to_anchor(display_point, Bias::Left);
24137        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot());
24138        Some(utf16_offset.0)
24139    }
24140}
24141
24142trait SelectionExt {
24143    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
24144    fn spanned_rows(
24145        &self,
24146        include_end_if_at_line_start: bool,
24147        map: &DisplaySnapshot,
24148    ) -> Range<MultiBufferRow>;
24149}
24150
24151impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
24152    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
24153        let start = self
24154            .start
24155            .to_point(map.buffer_snapshot())
24156            .to_display_point(map);
24157        let end = self
24158            .end
24159            .to_point(map.buffer_snapshot())
24160            .to_display_point(map);
24161        if self.reversed {
24162            end..start
24163        } else {
24164            start..end
24165        }
24166    }
24167
24168    fn spanned_rows(
24169        &self,
24170        include_end_if_at_line_start: bool,
24171        map: &DisplaySnapshot,
24172    ) -> Range<MultiBufferRow> {
24173        let start = self.start.to_point(map.buffer_snapshot());
24174        let mut end = self.end.to_point(map.buffer_snapshot());
24175        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
24176            end.row -= 1;
24177        }
24178
24179        let buffer_start = map.prev_line_boundary(start).0;
24180        let buffer_end = map.next_line_boundary(end).0;
24181        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
24182    }
24183}
24184
24185impl<T: InvalidationRegion> InvalidationStack<T> {
24186    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
24187    where
24188        S: Clone + ToOffset,
24189    {
24190        while let Some(region) = self.last() {
24191            let all_selections_inside_invalidation_ranges =
24192                if selections.len() == region.ranges().len() {
24193                    selections
24194                        .iter()
24195                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
24196                        .all(|(selection, invalidation_range)| {
24197                            let head = selection.head().to_offset(buffer);
24198                            invalidation_range.start <= head && invalidation_range.end >= head
24199                        })
24200                } else {
24201                    false
24202                };
24203
24204            if all_selections_inside_invalidation_ranges {
24205                break;
24206            } else {
24207                self.pop();
24208            }
24209        }
24210    }
24211}
24212
24213impl<T> Default for InvalidationStack<T> {
24214    fn default() -> Self {
24215        Self(Default::default())
24216    }
24217}
24218
24219impl<T> Deref for InvalidationStack<T> {
24220    type Target = Vec<T>;
24221
24222    fn deref(&self) -> &Self::Target {
24223        &self.0
24224    }
24225}
24226
24227impl<T> DerefMut for InvalidationStack<T> {
24228    fn deref_mut(&mut self) -> &mut Self::Target {
24229        &mut self.0
24230    }
24231}
24232
24233impl InvalidationRegion for SnippetState {
24234    fn ranges(&self) -> &[Range<Anchor>] {
24235        &self.ranges[self.active_index]
24236    }
24237}
24238
24239fn edit_prediction_edit_text(
24240    current_snapshot: &BufferSnapshot,
24241    edits: &[(Range<Anchor>, String)],
24242    edit_preview: &EditPreview,
24243    include_deletions: bool,
24244    cx: &App,
24245) -> HighlightedText {
24246    let edits = edits
24247        .iter()
24248        .map(|(anchor, text)| {
24249            (
24250                anchor.start.text_anchor..anchor.end.text_anchor,
24251                text.clone(),
24252            )
24253        })
24254        .collect::<Vec<_>>();
24255
24256    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
24257}
24258
24259fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, String)], cx: &App) -> HighlightedText {
24260    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
24261    // Just show the raw edit text with basic styling
24262    let mut text = String::new();
24263    let mut highlights = Vec::new();
24264
24265    let insertion_highlight_style = HighlightStyle {
24266        color: Some(cx.theme().colors().text),
24267        ..Default::default()
24268    };
24269
24270    for (_, edit_text) in edits {
24271        let start_offset = text.len();
24272        text.push_str(edit_text);
24273        let end_offset = text.len();
24274
24275        if start_offset < end_offset {
24276            highlights.push((start_offset..end_offset, insertion_highlight_style));
24277        }
24278    }
24279
24280    HighlightedText {
24281        text: text.into(),
24282        highlights,
24283    }
24284}
24285
24286pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
24287    match severity {
24288        lsp::DiagnosticSeverity::ERROR => colors.error,
24289        lsp::DiagnosticSeverity::WARNING => colors.warning,
24290        lsp::DiagnosticSeverity::INFORMATION => colors.info,
24291        lsp::DiagnosticSeverity::HINT => colors.info,
24292        _ => colors.ignored,
24293    }
24294}
24295
24296pub fn styled_runs_for_code_label<'a>(
24297    label: &'a CodeLabel,
24298    syntax_theme: &'a theme::SyntaxTheme,
24299) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
24300    let fade_out = HighlightStyle {
24301        fade_out: Some(0.35),
24302        ..Default::default()
24303    };
24304
24305    let mut prev_end = label.filter_range.end;
24306    label
24307        .runs
24308        .iter()
24309        .enumerate()
24310        .flat_map(move |(ix, (range, highlight_id))| {
24311            let style = if let Some(style) = highlight_id.style(syntax_theme) {
24312                style
24313            } else {
24314                return Default::default();
24315            };
24316            let muted_style = style.highlight(fade_out);
24317
24318            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
24319            if range.start >= label.filter_range.end {
24320                if range.start > prev_end {
24321                    runs.push((prev_end..range.start, fade_out));
24322                }
24323                runs.push((range.clone(), muted_style));
24324            } else if range.end <= label.filter_range.end {
24325                runs.push((range.clone(), style));
24326            } else {
24327                runs.push((range.start..label.filter_range.end, style));
24328                runs.push((label.filter_range.end..range.end, muted_style));
24329            }
24330            prev_end = cmp::max(prev_end, range.end);
24331
24332            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
24333                runs.push((prev_end..label.text.len(), fade_out));
24334            }
24335
24336            runs
24337        })
24338}
24339
24340pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
24341    let mut prev_index = 0;
24342    let mut prev_codepoint: Option<char> = None;
24343    text.char_indices()
24344        .chain([(text.len(), '\0')])
24345        .filter_map(move |(index, codepoint)| {
24346            let prev_codepoint = prev_codepoint.replace(codepoint)?;
24347            let is_boundary = index == text.len()
24348                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
24349                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
24350            if is_boundary {
24351                let chunk = &text[prev_index..index];
24352                prev_index = index;
24353                Some(chunk)
24354            } else {
24355                None
24356            }
24357        })
24358}
24359
24360pub trait RangeToAnchorExt: Sized {
24361    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
24362
24363    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
24364        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot());
24365        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
24366    }
24367}
24368
24369impl<T: ToOffset> RangeToAnchorExt for Range<T> {
24370    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
24371        let start_offset = self.start.to_offset(snapshot);
24372        let end_offset = self.end.to_offset(snapshot);
24373        if start_offset == end_offset {
24374            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
24375        } else {
24376            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
24377        }
24378    }
24379}
24380
24381pub trait RowExt {
24382    fn as_f64(&self) -> f64;
24383
24384    fn next_row(&self) -> Self;
24385
24386    fn previous_row(&self) -> Self;
24387
24388    fn minus(&self, other: Self) -> u32;
24389}
24390
24391impl RowExt for DisplayRow {
24392    fn as_f64(&self) -> f64 {
24393        self.0 as _
24394    }
24395
24396    fn next_row(&self) -> Self {
24397        Self(self.0 + 1)
24398    }
24399
24400    fn previous_row(&self) -> Self {
24401        Self(self.0.saturating_sub(1))
24402    }
24403
24404    fn minus(&self, other: Self) -> u32 {
24405        self.0 - other.0
24406    }
24407}
24408
24409impl RowExt for MultiBufferRow {
24410    fn as_f64(&self) -> f64 {
24411        self.0 as _
24412    }
24413
24414    fn next_row(&self) -> Self {
24415        Self(self.0 + 1)
24416    }
24417
24418    fn previous_row(&self) -> Self {
24419        Self(self.0.saturating_sub(1))
24420    }
24421
24422    fn minus(&self, other: Self) -> u32 {
24423        self.0 - other.0
24424    }
24425}
24426
24427trait RowRangeExt {
24428    type Row;
24429
24430    fn len(&self) -> usize;
24431
24432    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
24433}
24434
24435impl RowRangeExt for Range<MultiBufferRow> {
24436    type Row = MultiBufferRow;
24437
24438    fn len(&self) -> usize {
24439        (self.end.0 - self.start.0) as usize
24440    }
24441
24442    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
24443        (self.start.0..self.end.0).map(MultiBufferRow)
24444    }
24445}
24446
24447impl RowRangeExt for Range<DisplayRow> {
24448    type Row = DisplayRow;
24449
24450    fn len(&self) -> usize {
24451        (self.end.0 - self.start.0) as usize
24452    }
24453
24454    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
24455        (self.start.0..self.end.0).map(DisplayRow)
24456    }
24457}
24458
24459/// If select range has more than one line, we
24460/// just point the cursor to range.start.
24461fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
24462    if range.start.row == range.end.row {
24463        range
24464    } else {
24465        range.start..range.start
24466    }
24467}
24468pub struct KillRing(ClipboardItem);
24469impl Global for KillRing {}
24470
24471const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
24472
24473enum BreakpointPromptEditAction {
24474    Log,
24475    Condition,
24476    HitCondition,
24477}
24478
24479struct BreakpointPromptEditor {
24480    pub(crate) prompt: Entity<Editor>,
24481    editor: WeakEntity<Editor>,
24482    breakpoint_anchor: Anchor,
24483    breakpoint: Breakpoint,
24484    edit_action: BreakpointPromptEditAction,
24485    block_ids: HashSet<CustomBlockId>,
24486    editor_margins: Arc<Mutex<EditorMargins>>,
24487    _subscriptions: Vec<Subscription>,
24488}
24489
24490impl BreakpointPromptEditor {
24491    const MAX_LINES: u8 = 4;
24492
24493    fn new(
24494        editor: WeakEntity<Editor>,
24495        breakpoint_anchor: Anchor,
24496        breakpoint: Breakpoint,
24497        edit_action: BreakpointPromptEditAction,
24498        window: &mut Window,
24499        cx: &mut Context<Self>,
24500    ) -> Self {
24501        let base_text = match edit_action {
24502            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
24503            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
24504            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
24505        }
24506        .map(|msg| msg.to_string())
24507        .unwrap_or_default();
24508
24509        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
24510        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
24511
24512        let prompt = cx.new(|cx| {
24513            let mut prompt = Editor::new(
24514                EditorMode::AutoHeight {
24515                    min_lines: 1,
24516                    max_lines: Some(Self::MAX_LINES as usize),
24517                },
24518                buffer,
24519                None,
24520                window,
24521                cx,
24522            );
24523            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
24524            prompt.set_show_cursor_when_unfocused(false, cx);
24525            prompt.set_placeholder_text(
24526                match edit_action {
24527                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
24528                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
24529                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
24530                },
24531                window,
24532                cx,
24533            );
24534
24535            prompt
24536        });
24537
24538        Self {
24539            prompt,
24540            editor,
24541            breakpoint_anchor,
24542            breakpoint,
24543            edit_action,
24544            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
24545            block_ids: Default::default(),
24546            _subscriptions: vec![],
24547        }
24548    }
24549
24550    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
24551        self.block_ids.extend(block_ids)
24552    }
24553
24554    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
24555        if let Some(editor) = self.editor.upgrade() {
24556            let message = self
24557                .prompt
24558                .read(cx)
24559                .buffer
24560                .read(cx)
24561                .as_singleton()
24562                .expect("A multi buffer in breakpoint prompt isn't possible")
24563                .read(cx)
24564                .as_rope()
24565                .to_string();
24566
24567            editor.update(cx, |editor, cx| {
24568                editor.edit_breakpoint_at_anchor(
24569                    self.breakpoint_anchor,
24570                    self.breakpoint.clone(),
24571                    match self.edit_action {
24572                        BreakpointPromptEditAction::Log => {
24573                            BreakpointEditAction::EditLogMessage(message.into())
24574                        }
24575                        BreakpointPromptEditAction::Condition => {
24576                            BreakpointEditAction::EditCondition(message.into())
24577                        }
24578                        BreakpointPromptEditAction::HitCondition => {
24579                            BreakpointEditAction::EditHitCondition(message.into())
24580                        }
24581                    },
24582                    cx,
24583                );
24584
24585                editor.remove_blocks(self.block_ids.clone(), None, cx);
24586                cx.focus_self(window);
24587            });
24588        }
24589    }
24590
24591    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
24592        self.editor
24593            .update(cx, |editor, cx| {
24594                editor.remove_blocks(self.block_ids.clone(), None, cx);
24595                window.focus(&editor.focus_handle);
24596            })
24597            .log_err();
24598    }
24599
24600    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
24601        let settings = ThemeSettings::get_global(cx);
24602        let text_style = TextStyle {
24603            color: if self.prompt.read(cx).read_only(cx) {
24604                cx.theme().colors().text_disabled
24605            } else {
24606                cx.theme().colors().text
24607            },
24608            font_family: settings.buffer_font.family.clone(),
24609            font_fallbacks: settings.buffer_font.fallbacks.clone(),
24610            font_size: settings.buffer_font_size(cx).into(),
24611            font_weight: settings.buffer_font.weight,
24612            line_height: relative(settings.buffer_line_height.value()),
24613            ..Default::default()
24614        };
24615        EditorElement::new(
24616            &self.prompt,
24617            EditorStyle {
24618                background: cx.theme().colors().editor_background,
24619                local_player: cx.theme().players().local(),
24620                text: text_style,
24621                ..Default::default()
24622            },
24623        )
24624    }
24625}
24626
24627impl Render for BreakpointPromptEditor {
24628    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24629        let editor_margins = *self.editor_margins.lock();
24630        let gutter_dimensions = editor_margins.gutter;
24631        h_flex()
24632            .key_context("Editor")
24633            .bg(cx.theme().colors().editor_background)
24634            .border_y_1()
24635            .border_color(cx.theme().status().info_border)
24636            .size_full()
24637            .py(window.line_height() / 2.5)
24638            .on_action(cx.listener(Self::confirm))
24639            .on_action(cx.listener(Self::cancel))
24640            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
24641            .child(div().flex_1().child(self.render_prompt_editor(cx)))
24642    }
24643}
24644
24645impl Focusable for BreakpointPromptEditor {
24646    fn focus_handle(&self, cx: &App) -> FocusHandle {
24647        self.prompt.focus_handle(cx)
24648    }
24649}
24650
24651fn all_edits_insertions_or_deletions(
24652    edits: &Vec<(Range<Anchor>, String)>,
24653    snapshot: &MultiBufferSnapshot,
24654) -> bool {
24655    let mut all_insertions = true;
24656    let mut all_deletions = true;
24657
24658    for (range, new_text) in edits.iter() {
24659        let range_is_empty = range.to_offset(snapshot).is_empty();
24660        let text_is_empty = new_text.is_empty();
24661
24662        if range_is_empty != text_is_empty {
24663            if range_is_empty {
24664                all_deletions = false;
24665            } else {
24666                all_insertions = false;
24667            }
24668        } else {
24669            return false;
24670        }
24671
24672        if !all_insertions && !all_deletions {
24673            return false;
24674        }
24675    }
24676    all_insertions || all_deletions
24677}
24678
24679struct MissingEditPredictionKeybindingTooltip;
24680
24681impl Render for MissingEditPredictionKeybindingTooltip {
24682    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24683        ui::tooltip_container(cx, |container, cx| {
24684            container
24685                .flex_shrink_0()
24686                .max_w_80()
24687                .min_h(rems_from_px(124.))
24688                .justify_between()
24689                .child(
24690                    v_flex()
24691                        .flex_1()
24692                        .text_ui_sm(cx)
24693                        .child(Label::new("Conflict with Accept Keybinding"))
24694                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
24695                )
24696                .child(
24697                    h_flex()
24698                        .pb_1()
24699                        .gap_1()
24700                        .items_end()
24701                        .w_full()
24702                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
24703                            window.dispatch_action(zed_actions::OpenKeymapFile.boxed_clone(), cx)
24704                        }))
24705                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
24706                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
24707                        })),
24708                )
24709        })
24710    }
24711}
24712
24713#[derive(Debug, Clone, Copy, PartialEq)]
24714pub struct LineHighlight {
24715    pub background: Background,
24716    pub border: Option<gpui::Hsla>,
24717    pub include_gutter: bool,
24718    pub type_id: Option<TypeId>,
24719}
24720
24721struct LineManipulationResult {
24722    pub new_text: String,
24723    pub line_count_before: usize,
24724    pub line_count_after: usize,
24725}
24726
24727fn render_diff_hunk_controls(
24728    row: u32,
24729    status: &DiffHunkStatus,
24730    hunk_range: Range<Anchor>,
24731    is_created_file: bool,
24732    line_height: Pixels,
24733    editor: &Entity<Editor>,
24734    _window: &mut Window,
24735    cx: &mut App,
24736) -> AnyElement {
24737    h_flex()
24738        .h(line_height)
24739        .mr_1()
24740        .gap_1()
24741        .px_0p5()
24742        .pb_1()
24743        .border_x_1()
24744        .border_b_1()
24745        .border_color(cx.theme().colors().border_variant)
24746        .rounded_b_lg()
24747        .bg(cx.theme().colors().editor_background)
24748        .gap_1()
24749        .block_mouse_except_scroll()
24750        .shadow_md()
24751        .child(if status.has_secondary_hunk() {
24752            Button::new(("stage", row as u64), "Stage")
24753                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24754                .tooltip({
24755                    let focus_handle = editor.focus_handle(cx);
24756                    move |_window, cx| {
24757                        Tooltip::for_action_in(
24758                            "Stage Hunk",
24759                            &::git::ToggleStaged,
24760                            &focus_handle,
24761                            cx,
24762                        )
24763                    }
24764                })
24765                .on_click({
24766                    let editor = editor.clone();
24767                    move |_event, _window, cx| {
24768                        editor.update(cx, |editor, cx| {
24769                            editor.stage_or_unstage_diff_hunks(
24770                                true,
24771                                vec![hunk_range.start..hunk_range.start],
24772                                cx,
24773                            );
24774                        });
24775                    }
24776                })
24777        } else {
24778            Button::new(("unstage", row as u64), "Unstage")
24779                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24780                .tooltip({
24781                    let focus_handle = editor.focus_handle(cx);
24782                    move |_window, cx| {
24783                        Tooltip::for_action_in(
24784                            "Unstage Hunk",
24785                            &::git::ToggleStaged,
24786                            &focus_handle,
24787                            cx,
24788                        )
24789                    }
24790                })
24791                .on_click({
24792                    let editor = editor.clone();
24793                    move |_event, _window, cx| {
24794                        editor.update(cx, |editor, cx| {
24795                            editor.stage_or_unstage_diff_hunks(
24796                                false,
24797                                vec![hunk_range.start..hunk_range.start],
24798                                cx,
24799                            );
24800                        });
24801                    }
24802                })
24803        })
24804        .child(
24805            Button::new(("restore", row as u64), "Restore")
24806                .tooltip({
24807                    let focus_handle = editor.focus_handle(cx);
24808                    move |_window, cx| {
24809                        Tooltip::for_action_in("Restore Hunk", &::git::Restore, &focus_handle, cx)
24810                    }
24811                })
24812                .on_click({
24813                    let editor = editor.clone();
24814                    move |_event, window, cx| {
24815                        editor.update(cx, |editor, cx| {
24816                            let snapshot = editor.snapshot(window, cx);
24817                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot());
24818                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
24819                        });
24820                    }
24821                })
24822                .disabled(is_created_file),
24823        )
24824        .when(
24825            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
24826            |el| {
24827                el.child(
24828                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
24829                        .shape(IconButtonShape::Square)
24830                        .icon_size(IconSize::Small)
24831                        // .disabled(!has_multiple_hunks)
24832                        .tooltip({
24833                            let focus_handle = editor.focus_handle(cx);
24834                            move |_window, cx| {
24835                                Tooltip::for_action_in("Next Hunk", &GoToHunk, &focus_handle, cx)
24836                            }
24837                        })
24838                        .on_click({
24839                            let editor = editor.clone();
24840                            move |_event, window, cx| {
24841                                editor.update(cx, |editor, cx| {
24842                                    let snapshot = editor.snapshot(window, cx);
24843                                    let position =
24844                                        hunk_range.end.to_point(&snapshot.buffer_snapshot());
24845                                    editor.go_to_hunk_before_or_after_position(
24846                                        &snapshot,
24847                                        position,
24848                                        Direction::Next,
24849                                        window,
24850                                        cx,
24851                                    );
24852                                    editor.expand_selected_diff_hunks(cx);
24853                                });
24854                            }
24855                        }),
24856                )
24857                .child(
24858                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
24859                        .shape(IconButtonShape::Square)
24860                        .icon_size(IconSize::Small)
24861                        // .disabled(!has_multiple_hunks)
24862                        .tooltip({
24863                            let focus_handle = editor.focus_handle(cx);
24864                            move |_window, cx| {
24865                                Tooltip::for_action_in(
24866                                    "Previous Hunk",
24867                                    &GoToPreviousHunk,
24868                                    &focus_handle,
24869                                    cx,
24870                                )
24871                            }
24872                        })
24873                        .on_click({
24874                            let editor = editor.clone();
24875                            move |_event, window, cx| {
24876                                editor.update(cx, |editor, cx| {
24877                                    let snapshot = editor.snapshot(window, cx);
24878                                    let point =
24879                                        hunk_range.start.to_point(&snapshot.buffer_snapshot());
24880                                    editor.go_to_hunk_before_or_after_position(
24881                                        &snapshot,
24882                                        point,
24883                                        Direction::Prev,
24884                                        window,
24885                                        cx,
24886                                    );
24887                                    editor.expand_selected_diff_hunks(cx);
24888                                });
24889                            }
24890                        }),
24891                )
24892            },
24893        )
24894        .into_any_element()
24895}
24896
24897pub fn multibuffer_context_lines(cx: &App) -> u32 {
24898    EditorSettings::try_get(cx)
24899        .map(|settings| settings.excerpt_context_lines)
24900        .unwrap_or(2)
24901        .min(32)
24902}