editor.rs

    1#![allow(rustdoc::private_intra_doc_links)]
    2//! This is the place where everything editor-related is stored (data-wise) and displayed (ui-wise).
    3//! The main point of interest in this crate is [`Editor`] type, which is used in every other Zed part as a user input element.
    4//! It comes in different flavors: single line, multiline and a fixed height one.
    5//!
    6//! Editor contains of multiple large submodules:
    7//! * [`element`] — the place where all rendering happens
    8//! * [`display_map`] - chunks up text in the editor into the logical blocks, establishes coordinates and mapping between each of them.
    9//!   Contains all metadata related to text transformations (folds, fake inlay text insertions, soft wraps, tab markup, etc.).
   10//!
   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    autoindent_mode: Option<AutoindentMode>,
 1073    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1074    input_enabled: bool,
 1075    use_modal_editing: bool,
 1076    read_only: bool,
 1077    leader_id: Option<CollaboratorId>,
 1078    remote_id: Option<ViewId>,
 1079    pub hover_state: HoverState,
 1080    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1081    gutter_hovered: bool,
 1082    hovered_link_state: Option<HoveredLinkState>,
 1083    edit_prediction_provider: Option<RegisteredEditPredictionProvider>,
 1084    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1085    active_edit_prediction: Option<EditPredictionState>,
 1086    /// Used to prevent flickering as the user types while the menu is open
 1087    stale_edit_prediction_in_menu: Option<EditPredictionState>,
 1088    edit_prediction_settings: EditPredictionSettings,
 1089    edit_predictions_hidden_for_vim_mode: bool,
 1090    show_edit_predictions_override: Option<bool>,
 1091    menu_edit_predictions_policy: MenuEditPredictionsPolicy,
 1092    edit_prediction_preview: EditPredictionPreview,
 1093    edit_prediction_indent_conflict: bool,
 1094    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1095    next_inlay_id: usize,
 1096    next_color_inlay_id: usize,
 1097    _subscriptions: Vec<Subscription>,
 1098    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1099    gutter_dimensions: GutterDimensions,
 1100    style: Option<EditorStyle>,
 1101    text_style_refinement: Option<TextStyleRefinement>,
 1102    next_editor_action_id: EditorActionId,
 1103    editor_actions: Rc<
 1104        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1105    >,
 1106    use_autoclose: bool,
 1107    use_auto_surround: bool,
 1108    auto_replace_emoji_shortcode: bool,
 1109    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1110    show_git_blame_gutter: bool,
 1111    show_git_blame_inline: bool,
 1112    show_git_blame_inline_delay_task: Option<Task<()>>,
 1113    git_blame_inline_enabled: bool,
 1114    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1115    serialize_dirty_buffers: bool,
 1116    show_selection_menu: Option<bool>,
 1117    blame: Option<Entity<GitBlame>>,
 1118    blame_subscription: Option<Subscription>,
 1119    custom_context_menu: Option<
 1120        Box<
 1121            dyn 'static
 1122                + Fn(
 1123                    &mut Self,
 1124                    DisplayPoint,
 1125                    &mut Window,
 1126                    &mut Context<Self>,
 1127                ) -> Option<Entity<ui::ContextMenu>>,
 1128        >,
 1129    >,
 1130    last_bounds: Option<Bounds<Pixels>>,
 1131    last_position_map: Option<Rc<PositionMap>>,
 1132    expect_bounds_change: Option<Bounds<Pixels>>,
 1133    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1134    tasks_update_task: Option<Task<()>>,
 1135    breakpoint_store: Option<Entity<BreakpointStore>>,
 1136    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1137    hovered_diff_hunk_row: Option<DisplayRow>,
 1138    pull_diagnostics_task: Task<()>,
 1139    in_project_search: bool,
 1140    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1141    breadcrumb_header: Option<String>,
 1142    focused_block: Option<FocusedBlock>,
 1143    next_scroll_position: NextScrollCursorCenterTopBottom,
 1144    addons: HashMap<TypeId, Box<dyn Addon>>,
 1145    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1146    load_diff_task: Option<Shared<Task<()>>>,
 1147    /// Whether we are temporarily displaying a diff other than git's
 1148    temporary_diff_override: bool,
 1149    selection_mark_mode: bool,
 1150    toggle_fold_multiple_buffers: Task<()>,
 1151    _scroll_cursor_center_top_bottom_task: Task<()>,
 1152    serialize_selections: Task<()>,
 1153    serialize_folds: Task<()>,
 1154    mouse_cursor_hidden: bool,
 1155    minimap: Option<Entity<Self>>,
 1156    hide_mouse_mode: HideMouseMode,
 1157    pub change_list: ChangeList,
 1158    inline_value_cache: InlineValueCache,
 1159    selection_drag_state: SelectionDragState,
 1160    colors: Option<LspColorData>,
 1161    post_scroll_update: Task<()>,
 1162    refresh_colors_task: Task<()>,
 1163    inlay_hints: Option<LspInlayHintData>,
 1164    folding_newlines: Task<()>,
 1165    pub lookup_key: Option<Box<dyn Any + Send + Sync>>,
 1166}
 1167
 1168fn debounce_value(debounce_ms: u64) -> Option<Duration> {
 1169    if debounce_ms > 0 {
 1170        Some(Duration::from_millis(debounce_ms))
 1171    } else {
 1172        None
 1173    }
 1174}
 1175
 1176#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1177enum NextScrollCursorCenterTopBottom {
 1178    #[default]
 1179    Center,
 1180    Top,
 1181    Bottom,
 1182}
 1183
 1184impl NextScrollCursorCenterTopBottom {
 1185    fn next(&self) -> Self {
 1186        match self {
 1187            Self::Center => Self::Top,
 1188            Self::Top => Self::Bottom,
 1189            Self::Bottom => Self::Center,
 1190        }
 1191    }
 1192}
 1193
 1194#[derive(Clone)]
 1195pub struct EditorSnapshot {
 1196    pub mode: EditorMode,
 1197    show_gutter: bool,
 1198    show_line_numbers: Option<bool>,
 1199    show_git_diff_gutter: Option<bool>,
 1200    show_code_actions: Option<bool>,
 1201    show_runnables: Option<bool>,
 1202    show_breakpoints: Option<bool>,
 1203    git_blame_gutter_max_author_length: Option<usize>,
 1204    pub display_snapshot: DisplaySnapshot,
 1205    pub placeholder_display_snapshot: Option<DisplaySnapshot>,
 1206    is_focused: bool,
 1207    scroll_anchor: ScrollAnchor,
 1208    ongoing_scroll: OngoingScroll,
 1209    current_line_highlight: CurrentLineHighlight,
 1210    gutter_hovered: bool,
 1211}
 1212
 1213#[derive(Default, Debug, Clone, Copy)]
 1214pub struct GutterDimensions {
 1215    pub left_padding: Pixels,
 1216    pub right_padding: Pixels,
 1217    pub width: Pixels,
 1218    pub margin: Pixels,
 1219    pub git_blame_entries_width: Option<Pixels>,
 1220}
 1221
 1222impl GutterDimensions {
 1223    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1224        Self {
 1225            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1226            ..Default::default()
 1227        }
 1228    }
 1229
 1230    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1231        -cx.text_system().descent(font_id, font_size)
 1232    }
 1233    /// The full width of the space taken up by the gutter.
 1234    pub fn full_width(&self) -> Pixels {
 1235        self.margin + self.width
 1236    }
 1237
 1238    /// The width of the space reserved for the fold indicators,
 1239    /// use alongside 'justify_end' and `gutter_width` to
 1240    /// right align content with the line numbers
 1241    pub fn fold_area_width(&self) -> Pixels {
 1242        self.margin + self.right_padding
 1243    }
 1244}
 1245
 1246struct CharacterDimensions {
 1247    em_width: Pixels,
 1248    em_advance: Pixels,
 1249    line_height: Pixels,
 1250}
 1251
 1252#[derive(Debug)]
 1253pub struct RemoteSelection {
 1254    pub replica_id: ReplicaId,
 1255    pub selection: Selection<Anchor>,
 1256    pub cursor_shape: CursorShape,
 1257    pub collaborator_id: CollaboratorId,
 1258    pub line_mode: bool,
 1259    pub user_name: Option<SharedString>,
 1260    pub color: PlayerColor,
 1261}
 1262
 1263#[derive(Clone, Debug)]
 1264struct SelectionHistoryEntry {
 1265    selections: Arc<[Selection<Anchor>]>,
 1266    select_next_state: Option<SelectNextState>,
 1267    select_prev_state: Option<SelectNextState>,
 1268    add_selections_state: Option<AddSelectionsState>,
 1269}
 1270
 1271#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 1272enum SelectionHistoryMode {
 1273    Normal,
 1274    Undoing,
 1275    Redoing,
 1276    Skipping,
 1277}
 1278
 1279#[derive(Clone, PartialEq, Eq, Hash)]
 1280struct HoveredCursor {
 1281    replica_id: ReplicaId,
 1282    selection_id: usize,
 1283}
 1284
 1285impl Default for SelectionHistoryMode {
 1286    fn default() -> Self {
 1287        Self::Normal
 1288    }
 1289}
 1290
 1291#[derive(Debug)]
 1292/// SelectionEffects controls the side-effects of updating the selection.
 1293///
 1294/// The default behaviour does "what you mostly want":
 1295/// - it pushes to the nav history if the cursor moved by >10 lines
 1296/// - it re-triggers completion requests
 1297/// - it scrolls to fit
 1298///
 1299/// You might want to modify these behaviours. For example when doing a "jump"
 1300/// like go to definition, we always want to add to nav history; but when scrolling
 1301/// in vim mode we never do.
 1302///
 1303/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1304/// move.
 1305#[derive(Clone)]
 1306pub struct SelectionEffects {
 1307    nav_history: Option<bool>,
 1308    completions: bool,
 1309    scroll: Option<Autoscroll>,
 1310}
 1311
 1312impl Default for SelectionEffects {
 1313    fn default() -> Self {
 1314        Self {
 1315            nav_history: None,
 1316            completions: true,
 1317            scroll: Some(Autoscroll::fit()),
 1318        }
 1319    }
 1320}
 1321impl SelectionEffects {
 1322    pub fn scroll(scroll: Autoscroll) -> Self {
 1323        Self {
 1324            scroll: Some(scroll),
 1325            ..Default::default()
 1326        }
 1327    }
 1328
 1329    pub fn no_scroll() -> Self {
 1330        Self {
 1331            scroll: None,
 1332            ..Default::default()
 1333        }
 1334    }
 1335
 1336    pub fn completions(self, completions: bool) -> Self {
 1337        Self {
 1338            completions,
 1339            ..self
 1340        }
 1341    }
 1342
 1343    pub fn nav_history(self, nav_history: bool) -> Self {
 1344        Self {
 1345            nav_history: Some(nav_history),
 1346            ..self
 1347        }
 1348    }
 1349}
 1350
 1351struct DeferredSelectionEffectsState {
 1352    changed: bool,
 1353    effects: SelectionEffects,
 1354    old_cursor_position: Anchor,
 1355    history_entry: SelectionHistoryEntry,
 1356}
 1357
 1358#[derive(Default)]
 1359struct SelectionHistory {
 1360    #[allow(clippy::type_complexity)]
 1361    selections_by_transaction:
 1362        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1363    mode: SelectionHistoryMode,
 1364    undo_stack: VecDeque<SelectionHistoryEntry>,
 1365    redo_stack: VecDeque<SelectionHistoryEntry>,
 1366}
 1367
 1368impl SelectionHistory {
 1369    #[track_caller]
 1370    fn insert_transaction(
 1371        &mut self,
 1372        transaction_id: TransactionId,
 1373        selections: Arc<[Selection<Anchor>]>,
 1374    ) {
 1375        if selections.is_empty() {
 1376            log::error!(
 1377                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1378                std::panic::Location::caller()
 1379            );
 1380            return;
 1381        }
 1382        self.selections_by_transaction
 1383            .insert(transaction_id, (selections, None));
 1384    }
 1385
 1386    #[allow(clippy::type_complexity)]
 1387    fn transaction(
 1388        &self,
 1389        transaction_id: TransactionId,
 1390    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1391        self.selections_by_transaction.get(&transaction_id)
 1392    }
 1393
 1394    #[allow(clippy::type_complexity)]
 1395    fn transaction_mut(
 1396        &mut self,
 1397        transaction_id: TransactionId,
 1398    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1399        self.selections_by_transaction.get_mut(&transaction_id)
 1400    }
 1401
 1402    fn push(&mut self, entry: SelectionHistoryEntry) {
 1403        if !entry.selections.is_empty() {
 1404            match self.mode {
 1405                SelectionHistoryMode::Normal => {
 1406                    self.push_undo(entry);
 1407                    self.redo_stack.clear();
 1408                }
 1409                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1410                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1411                SelectionHistoryMode::Skipping => {}
 1412            }
 1413        }
 1414    }
 1415
 1416    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1417        if self
 1418            .undo_stack
 1419            .back()
 1420            .is_none_or(|e| e.selections != entry.selections)
 1421        {
 1422            self.undo_stack.push_back(entry);
 1423            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1424                self.undo_stack.pop_front();
 1425            }
 1426        }
 1427    }
 1428
 1429    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1430        if self
 1431            .redo_stack
 1432            .back()
 1433            .is_none_or(|e| e.selections != entry.selections)
 1434        {
 1435            self.redo_stack.push_back(entry);
 1436            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1437                self.redo_stack.pop_front();
 1438            }
 1439        }
 1440    }
 1441}
 1442
 1443#[derive(Clone, Copy)]
 1444pub struct RowHighlightOptions {
 1445    pub autoscroll: bool,
 1446    pub include_gutter: bool,
 1447}
 1448
 1449impl Default for RowHighlightOptions {
 1450    fn default() -> Self {
 1451        Self {
 1452            autoscroll: Default::default(),
 1453            include_gutter: true,
 1454        }
 1455    }
 1456}
 1457
 1458struct RowHighlight {
 1459    index: usize,
 1460    range: Range<Anchor>,
 1461    color: Hsla,
 1462    options: RowHighlightOptions,
 1463    type_id: TypeId,
 1464}
 1465
 1466#[derive(Clone, Debug)]
 1467struct AddSelectionsState {
 1468    groups: Vec<AddSelectionsGroup>,
 1469}
 1470
 1471#[derive(Clone, Debug)]
 1472struct AddSelectionsGroup {
 1473    above: bool,
 1474    stack: Vec<usize>,
 1475}
 1476
 1477#[derive(Clone)]
 1478struct SelectNextState {
 1479    query: AhoCorasick,
 1480    wordwise: bool,
 1481    done: bool,
 1482}
 1483
 1484impl std::fmt::Debug for SelectNextState {
 1485    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1486        f.debug_struct(std::any::type_name::<Self>())
 1487            .field("wordwise", &self.wordwise)
 1488            .field("done", &self.done)
 1489            .finish()
 1490    }
 1491}
 1492
 1493#[derive(Debug)]
 1494struct AutocloseRegion {
 1495    selection_id: usize,
 1496    range: Range<Anchor>,
 1497    pair: BracketPair,
 1498}
 1499
 1500#[derive(Debug)]
 1501struct SnippetState {
 1502    ranges: Vec<Vec<Range<Anchor>>>,
 1503    active_index: usize,
 1504    choices: Vec<Option<Vec<String>>>,
 1505}
 1506
 1507#[doc(hidden)]
 1508pub struct RenameState {
 1509    pub range: Range<Anchor>,
 1510    pub old_name: Arc<str>,
 1511    pub editor: Entity<Editor>,
 1512    block_id: CustomBlockId,
 1513}
 1514
 1515struct InvalidationStack<T>(Vec<T>);
 1516
 1517struct RegisteredEditPredictionProvider {
 1518    provider: Arc<dyn EditPredictionProviderHandle>,
 1519    _subscription: Subscription,
 1520}
 1521
 1522#[derive(Debug, PartialEq, Eq)]
 1523pub struct ActiveDiagnosticGroup {
 1524    pub active_range: Range<Anchor>,
 1525    pub active_message: String,
 1526    pub group_id: usize,
 1527    pub blocks: HashSet<CustomBlockId>,
 1528}
 1529
 1530#[derive(Debug, PartialEq, Eq)]
 1531
 1532pub(crate) enum ActiveDiagnostic {
 1533    None,
 1534    All,
 1535    Group(ActiveDiagnosticGroup),
 1536}
 1537
 1538#[derive(Serialize, Deserialize, Clone, Debug)]
 1539pub struct ClipboardSelection {
 1540    /// The number of bytes in this selection.
 1541    pub len: usize,
 1542    /// Whether this was a full-line selection.
 1543    pub is_entire_line: bool,
 1544    /// The indentation of the first line when this content was originally copied.
 1545    pub first_line_indent: u32,
 1546}
 1547
 1548// selections, scroll behavior, was newest selection reversed
 1549type SelectSyntaxNodeHistoryState = (
 1550    Box<[Selection<usize>]>,
 1551    SelectSyntaxNodeScrollBehavior,
 1552    bool,
 1553);
 1554
 1555#[derive(Default)]
 1556struct SelectSyntaxNodeHistory {
 1557    stack: Vec<SelectSyntaxNodeHistoryState>,
 1558    // disable temporarily to allow changing selections without losing the stack
 1559    pub disable_clearing: bool,
 1560}
 1561
 1562impl SelectSyntaxNodeHistory {
 1563    pub fn try_clear(&mut self) {
 1564        if !self.disable_clearing {
 1565            self.stack.clear();
 1566        }
 1567    }
 1568
 1569    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1570        self.stack.push(selection);
 1571    }
 1572
 1573    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1574        self.stack.pop()
 1575    }
 1576}
 1577
 1578enum SelectSyntaxNodeScrollBehavior {
 1579    CursorTop,
 1580    FitSelection,
 1581    CursorBottom,
 1582}
 1583
 1584#[derive(Debug)]
 1585pub(crate) struct NavigationData {
 1586    cursor_anchor: Anchor,
 1587    cursor_position: Point,
 1588    scroll_anchor: ScrollAnchor,
 1589    scroll_top_row: u32,
 1590}
 1591
 1592#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1593pub enum GotoDefinitionKind {
 1594    Symbol,
 1595    Declaration,
 1596    Type,
 1597    Implementation,
 1598}
 1599
 1600pub enum FormatTarget {
 1601    Buffers(HashSet<Entity<Buffer>>),
 1602    Ranges(Vec<Range<MultiBufferPoint>>),
 1603}
 1604
 1605pub(crate) struct FocusedBlock {
 1606    id: BlockId,
 1607    focus_handle: WeakFocusHandle,
 1608}
 1609
 1610#[derive(Clone)]
 1611enum JumpData {
 1612    MultiBufferRow {
 1613        row: MultiBufferRow,
 1614        line_offset_from_top: u32,
 1615    },
 1616    MultiBufferPoint {
 1617        excerpt_id: ExcerptId,
 1618        position: Point,
 1619        anchor: text::Anchor,
 1620        line_offset_from_top: u32,
 1621    },
 1622}
 1623
 1624pub enum MultibufferSelectionMode {
 1625    First,
 1626    All,
 1627}
 1628
 1629#[derive(Clone, Copy, Debug, Default)]
 1630pub struct RewrapOptions {
 1631    pub override_language_settings: bool,
 1632    pub preserve_existing_whitespace: bool,
 1633}
 1634
 1635impl Editor {
 1636    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1637        let buffer = cx.new(|cx| Buffer::local("", cx));
 1638        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1639        Self::new(EditorMode::SingleLine, buffer, None, window, cx)
 1640    }
 1641
 1642    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1643        let buffer = cx.new(|cx| Buffer::local("", cx));
 1644        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1645        Self::new(EditorMode::full(), buffer, None, window, cx)
 1646    }
 1647
 1648    pub fn auto_height(
 1649        min_lines: usize,
 1650        max_lines: usize,
 1651        window: &mut Window,
 1652        cx: &mut Context<Self>,
 1653    ) -> Self {
 1654        let buffer = cx.new(|cx| Buffer::local("", cx));
 1655        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1656        Self::new(
 1657            EditorMode::AutoHeight {
 1658                min_lines,
 1659                max_lines: Some(max_lines),
 1660            },
 1661            buffer,
 1662            None,
 1663            window,
 1664            cx,
 1665        )
 1666    }
 1667
 1668    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1669    /// The editor grows as tall as needed to fit its content.
 1670    pub fn auto_height_unbounded(
 1671        min_lines: usize,
 1672        window: &mut Window,
 1673        cx: &mut Context<Self>,
 1674    ) -> Self {
 1675        let buffer = cx.new(|cx| Buffer::local("", cx));
 1676        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1677        Self::new(
 1678            EditorMode::AutoHeight {
 1679                min_lines,
 1680                max_lines: None,
 1681            },
 1682            buffer,
 1683            None,
 1684            window,
 1685            cx,
 1686        )
 1687    }
 1688
 1689    pub fn for_buffer(
 1690        buffer: Entity<Buffer>,
 1691        project: Option<Entity<Project>>,
 1692        window: &mut Window,
 1693        cx: &mut Context<Self>,
 1694    ) -> Self {
 1695        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1696        Self::new(EditorMode::full(), buffer, project, window, cx)
 1697    }
 1698
 1699    pub fn for_multibuffer(
 1700        buffer: Entity<MultiBuffer>,
 1701        project: Option<Entity<Project>>,
 1702        window: &mut Window,
 1703        cx: &mut Context<Self>,
 1704    ) -> Self {
 1705        Self::new(EditorMode::full(), buffer, project, window, cx)
 1706    }
 1707
 1708    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1709        let mut clone = Self::new(
 1710            self.mode.clone(),
 1711            self.buffer.clone(),
 1712            self.project.clone(),
 1713            window,
 1714            cx,
 1715        );
 1716        self.display_map.update(cx, |display_map, cx| {
 1717            let snapshot = display_map.snapshot(cx);
 1718            clone.display_map.update(cx, |display_map, cx| {
 1719                display_map.set_state(&snapshot, cx);
 1720            });
 1721        });
 1722        clone.folds_did_change(cx);
 1723        clone.selections.clone_state(&self.selections);
 1724        clone.scroll_manager.clone_state(&self.scroll_manager);
 1725        clone.searchable = self.searchable;
 1726        clone.read_only = self.read_only;
 1727        clone
 1728    }
 1729
 1730    pub fn new(
 1731        mode: EditorMode,
 1732        buffer: Entity<MultiBuffer>,
 1733        project: Option<Entity<Project>>,
 1734        window: &mut Window,
 1735        cx: &mut Context<Self>,
 1736    ) -> Self {
 1737        Editor::new_internal(mode, buffer, project, None, window, cx)
 1738    }
 1739
 1740    fn new_internal(
 1741        mode: EditorMode,
 1742        multi_buffer: Entity<MultiBuffer>,
 1743        project: Option<Entity<Project>>,
 1744        display_map: Option<Entity<DisplayMap>>,
 1745        window: &mut Window,
 1746        cx: &mut Context<Self>,
 1747    ) -> Self {
 1748        debug_assert!(
 1749            display_map.is_none() || mode.is_minimap(),
 1750            "Providing a display map for a new editor is only intended for the minimap and might have unintended side effects otherwise!"
 1751        );
 1752
 1753        let full_mode = mode.is_full();
 1754        let is_minimap = mode.is_minimap();
 1755        let diagnostics_max_severity = if full_mode {
 1756            EditorSettings::get_global(cx)
 1757                .diagnostics_max_severity
 1758                .unwrap_or(DiagnosticSeverity::Hint)
 1759        } else {
 1760            DiagnosticSeverity::Off
 1761        };
 1762        let style = window.text_style();
 1763        let font_size = style.font_size.to_pixels(window.rem_size());
 1764        let editor = cx.entity().downgrade();
 1765        let fold_placeholder = FoldPlaceholder {
 1766            constrain_width: false,
 1767            render: Arc::new(move |fold_id, fold_range, cx| {
 1768                let editor = editor.clone();
 1769                div()
 1770                    .id(fold_id)
 1771                    .bg(cx.theme().colors().ghost_element_background)
 1772                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1773                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1774                    .rounded_xs()
 1775                    .size_full()
 1776                    .cursor_pointer()
 1777                    .child("")
 1778                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1779                    .on_click(move |_, _window, cx| {
 1780                        editor
 1781                            .update(cx, |editor, cx| {
 1782                                editor.unfold_ranges(
 1783                                    &[fold_range.start..fold_range.end],
 1784                                    true,
 1785                                    false,
 1786                                    cx,
 1787                                );
 1788                                cx.stop_propagation();
 1789                            })
 1790                            .ok();
 1791                    })
 1792                    .into_any()
 1793            }),
 1794            merge_adjacent: true,
 1795            ..FoldPlaceholder::default()
 1796        };
 1797        let display_map = display_map.unwrap_or_else(|| {
 1798            cx.new(|cx| {
 1799                DisplayMap::new(
 1800                    multi_buffer.clone(),
 1801                    style.font(),
 1802                    font_size,
 1803                    None,
 1804                    FILE_HEADER_HEIGHT,
 1805                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1806                    fold_placeholder,
 1807                    diagnostics_max_severity,
 1808                    cx,
 1809                )
 1810            })
 1811        });
 1812
 1813        let selections = SelectionsCollection::new(display_map.clone(), multi_buffer.clone());
 1814
 1815        let blink_manager = cx.new(|cx| {
 1816            let mut blink_manager = BlinkManager::new(CURSOR_BLINK_INTERVAL, cx);
 1817            if is_minimap {
 1818                blink_manager.disable(cx);
 1819            }
 1820            blink_manager
 1821        });
 1822
 1823        let soft_wrap_mode_override =
 1824            matches!(mode, EditorMode::SingleLine).then(|| language_settings::SoftWrap::None);
 1825
 1826        let mut project_subscriptions = Vec::new();
 1827        if full_mode && let Some(project) = project.as_ref() {
 1828            project_subscriptions.push(cx.subscribe_in(
 1829                project,
 1830                window,
 1831                |editor, _, event, window, cx| match event {
 1832                    project::Event::RefreshCodeLens => {
 1833                        // we always query lens with actions, without storing them, always refreshing them
 1834                    }
 1835                    project::Event::RefreshInlayHints(server_id) => {
 1836                        editor.refresh_inlay_hints(
 1837                            InlayHintRefreshReason::RefreshRequested(*server_id),
 1838                            cx,
 1839                        );
 1840                    }
 1841                    project::Event::LanguageServerRemoved(..) => {
 1842                        if editor.tasks_update_task.is_none() {
 1843                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1844                        }
 1845                        editor.registered_buffers.clear();
 1846                        editor.register_visible_buffers(cx);
 1847                    }
 1848                    project::Event::LanguageServerAdded(..) => {
 1849                        if editor.tasks_update_task.is_none() {
 1850                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1851                        }
 1852                    }
 1853                    project::Event::SnippetEdit(id, snippet_edits) => {
 1854                        if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1855                            let focus_handle = editor.focus_handle(cx);
 1856                            if focus_handle.is_focused(window) {
 1857                                let snapshot = buffer.read(cx).snapshot();
 1858                                for (range, snippet) in snippet_edits {
 1859                                    let editor_range =
 1860                                        language::range_from_lsp(*range).to_offset(&snapshot);
 1861                                    editor
 1862                                        .insert_snippet(
 1863                                            &[editor_range],
 1864                                            snippet.clone(),
 1865                                            window,
 1866                                            cx,
 1867                                        )
 1868                                        .ok();
 1869                                }
 1870                            }
 1871                        }
 1872                    }
 1873                    project::Event::LanguageServerBufferRegistered { buffer_id, .. } => {
 1874                        let buffer_id = *buffer_id;
 1875                        if editor.buffer().read(cx).buffer(buffer_id).is_some() {
 1876                            editor.register_buffer(buffer_id, cx);
 1877                            editor.update_lsp_data(Some(buffer_id), window, cx);
 1878                            editor.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
 1879                            refresh_linked_ranges(editor, window, cx);
 1880                            editor.refresh_code_actions(window, cx);
 1881                            editor.refresh_document_highlights(cx);
 1882                        }
 1883                    }
 1884
 1885                    project::Event::EntryRenamed(transaction) => {
 1886                        let Some(workspace) = editor.workspace() else {
 1887                            return;
 1888                        };
 1889                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 1890                        else {
 1891                            return;
 1892                        };
 1893                        if active_editor.entity_id() == cx.entity_id() {
 1894                            let edited_buffers_already_open = {
 1895                                let other_editors: Vec<Entity<Editor>> = workspace
 1896                                    .read(cx)
 1897                                    .panes()
 1898                                    .iter()
 1899                                    .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
 1900                                    .filter(|editor| editor.entity_id() != cx.entity_id())
 1901                                    .collect();
 1902
 1903                                transaction.0.keys().all(|buffer| {
 1904                                    other_editors.iter().any(|editor| {
 1905                                        let multi_buffer = editor.read(cx).buffer();
 1906                                        multi_buffer.read(cx).is_singleton()
 1907                                            && multi_buffer.read(cx).as_singleton().map_or(
 1908                                                false,
 1909                                                |singleton| {
 1910                                                    singleton.entity_id() == buffer.entity_id()
 1911                                                },
 1912                                            )
 1913                                    })
 1914                                })
 1915                            };
 1916
 1917                            if !edited_buffers_already_open {
 1918                                let workspace = workspace.downgrade();
 1919                                let transaction = transaction.clone();
 1920                                cx.defer_in(window, move |_, window, cx| {
 1921                                    cx.spawn_in(window, async move |editor, cx| {
 1922                                        Self::open_project_transaction(
 1923                                            &editor,
 1924                                            workspace,
 1925                                            transaction,
 1926                                            "Rename".to_string(),
 1927                                            cx,
 1928                                        )
 1929                                        .await
 1930                                        .ok()
 1931                                    })
 1932                                    .detach();
 1933                                });
 1934                            }
 1935                        }
 1936                    }
 1937
 1938                    _ => {}
 1939                },
 1940            ));
 1941            if let Some(task_inventory) = project
 1942                .read(cx)
 1943                .task_store()
 1944                .read(cx)
 1945                .task_inventory()
 1946                .cloned()
 1947            {
 1948                project_subscriptions.push(cx.observe_in(
 1949                    &task_inventory,
 1950                    window,
 1951                    |editor, _, window, cx| {
 1952                        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1953                    },
 1954                ));
 1955            };
 1956
 1957            project_subscriptions.push(cx.subscribe_in(
 1958                &project.read(cx).breakpoint_store(),
 1959                window,
 1960                |editor, _, event, window, cx| match event {
 1961                    BreakpointStoreEvent::ClearDebugLines => {
 1962                        editor.clear_row_highlights::<ActiveDebugLine>();
 1963                        editor.refresh_inline_values(cx);
 1964                    }
 1965                    BreakpointStoreEvent::SetDebugLine => {
 1966                        if editor.go_to_active_debug_line(window, cx) {
 1967                            cx.stop_propagation();
 1968                        }
 1969
 1970                        editor.refresh_inline_values(cx);
 1971                    }
 1972                    _ => {}
 1973                },
 1974            ));
 1975            let git_store = project.read(cx).git_store().clone();
 1976            let project = project.clone();
 1977            project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 1978                if let GitStoreEvent::RepositoryAdded = event {
 1979                    this.load_diff_task = Some(
 1980                        update_uncommitted_diff_for_buffer(
 1981                            cx.entity(),
 1982                            &project,
 1983                            this.buffer.read(cx).all_buffers(),
 1984                            this.buffer.clone(),
 1985                            cx,
 1986                        )
 1987                        .shared(),
 1988                    );
 1989                }
 1990            }));
 1991        }
 1992
 1993        let buffer_snapshot = multi_buffer.read(cx).snapshot(cx);
 1994
 1995        let inlay_hint_settings =
 1996            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 1997        let focus_handle = cx.focus_handle();
 1998        if !is_minimap {
 1999            cx.on_focus(&focus_handle, window, Self::handle_focus)
 2000                .detach();
 2001            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 2002                .detach();
 2003            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 2004                .detach();
 2005            cx.on_blur(&focus_handle, window, Self::handle_blur)
 2006                .detach();
 2007            cx.observe_pending_input(window, Self::observe_pending_input)
 2008                .detach();
 2009        }
 2010
 2011        let show_indent_guides =
 2012            if matches!(mode, EditorMode::SingleLine | EditorMode::Minimap { .. }) {
 2013                Some(false)
 2014            } else {
 2015                None
 2016            };
 2017
 2018        let breakpoint_store = match (&mode, project.as_ref()) {
 2019            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 2020            _ => None,
 2021        };
 2022
 2023        let mut code_action_providers = Vec::new();
 2024        let mut load_uncommitted_diff = None;
 2025        if let Some(project) = project.clone() {
 2026            load_uncommitted_diff = Some(
 2027                update_uncommitted_diff_for_buffer(
 2028                    cx.entity(),
 2029                    &project,
 2030                    multi_buffer.read(cx).all_buffers(),
 2031                    multi_buffer.clone(),
 2032                    cx,
 2033                )
 2034                .shared(),
 2035            );
 2036            code_action_providers.push(Rc::new(project) as Rc<_>);
 2037        }
 2038
 2039        let mut editor = Self {
 2040            focus_handle,
 2041            show_cursor_when_unfocused: false,
 2042            last_focused_descendant: None,
 2043            buffer: multi_buffer.clone(),
 2044            display_map: display_map.clone(),
 2045            placeholder_display_map: None,
 2046            selections,
 2047            scroll_manager: ScrollManager::new(cx),
 2048            columnar_selection_state: None,
 2049            add_selections_state: None,
 2050            select_next_state: None,
 2051            select_prev_state: None,
 2052            selection_history: SelectionHistory::default(),
 2053            defer_selection_effects: false,
 2054            deferred_selection_effects_state: None,
 2055            autoclose_regions: Vec::new(),
 2056            snippet_stack: InvalidationStack::default(),
 2057            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2058            ime_transaction: None,
 2059            active_diagnostics: ActiveDiagnostic::None,
 2060            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2061            inline_diagnostics_update: Task::ready(()),
 2062            inline_diagnostics: Vec::new(),
 2063            soft_wrap_mode_override,
 2064            diagnostics_max_severity,
 2065            hard_wrap: None,
 2066            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2067            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2068            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2069            project,
 2070            blink_manager: blink_manager.clone(),
 2071            show_local_selections: true,
 2072            show_scrollbars: ScrollbarAxes {
 2073                horizontal: full_mode,
 2074                vertical: full_mode,
 2075            },
 2076            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2077            offset_content: !matches!(mode, EditorMode::SingleLine),
 2078            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2079            show_gutter: full_mode,
 2080            show_line_numbers: (!full_mode).then_some(false),
 2081            use_relative_line_numbers: None,
 2082            disable_expand_excerpt_buttons: !full_mode,
 2083            show_git_diff_gutter: None,
 2084            show_code_actions: None,
 2085            show_runnables: None,
 2086            show_breakpoints: None,
 2087            show_wrap_guides: None,
 2088            show_indent_guides,
 2089            highlight_order: 0,
 2090            highlighted_rows: HashMap::default(),
 2091            background_highlights: HashMap::default(),
 2092            gutter_highlights: HashMap::default(),
 2093            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2094            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2095            nav_history: None,
 2096            context_menu: RefCell::new(None),
 2097            context_menu_options: None,
 2098            mouse_context_menu: None,
 2099            completion_tasks: Vec::new(),
 2100            inline_blame_popover: None,
 2101            inline_blame_popover_show_task: None,
 2102            signature_help_state: SignatureHelpState::default(),
 2103            auto_signature_help: None,
 2104            find_all_references_task_sources: Vec::new(),
 2105            next_completion_id: 0,
 2106            next_inlay_id: 0,
 2107            code_action_providers,
 2108            available_code_actions: None,
 2109            code_actions_task: None,
 2110            quick_selection_highlight_task: None,
 2111            debounced_selection_highlight_task: None,
 2112            document_highlights_task: None,
 2113            linked_editing_range_task: None,
 2114            pending_rename: None,
 2115            searchable: !is_minimap,
 2116            cursor_shape: EditorSettings::get_global(cx)
 2117                .cursor_shape
 2118                .unwrap_or_default(),
 2119            current_line_highlight: None,
 2120            autoindent_mode: Some(AutoindentMode::EachLine),
 2121
 2122            workspace: None,
 2123            input_enabled: !is_minimap,
 2124            use_modal_editing: full_mode,
 2125            read_only: is_minimap,
 2126            use_autoclose: true,
 2127            use_auto_surround: true,
 2128            auto_replace_emoji_shortcode: false,
 2129            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2130            leader_id: None,
 2131            remote_id: None,
 2132            hover_state: HoverState::default(),
 2133            pending_mouse_down: None,
 2134            hovered_link_state: None,
 2135            edit_prediction_provider: None,
 2136            active_edit_prediction: None,
 2137            stale_edit_prediction_in_menu: None,
 2138            edit_prediction_preview: EditPredictionPreview::Inactive {
 2139                released_too_fast: false,
 2140            },
 2141            inline_diagnostics_enabled: full_mode,
 2142            diagnostics_enabled: full_mode,
 2143            word_completions_enabled: full_mode,
 2144            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2145            gutter_hovered: false,
 2146            pixel_position_of_newest_cursor: None,
 2147            last_bounds: None,
 2148            last_position_map: None,
 2149            expect_bounds_change: None,
 2150            gutter_dimensions: GutterDimensions::default(),
 2151            style: None,
 2152            show_cursor_names: false,
 2153            hovered_cursors: HashMap::default(),
 2154            next_editor_action_id: EditorActionId::default(),
 2155            editor_actions: Rc::default(),
 2156            edit_predictions_hidden_for_vim_mode: false,
 2157            show_edit_predictions_override: None,
 2158            menu_edit_predictions_policy: MenuEditPredictionsPolicy::ByProvider,
 2159            edit_prediction_settings: EditPredictionSettings::Disabled,
 2160            edit_prediction_indent_conflict: false,
 2161            edit_prediction_requires_modifier_in_indent_conflict: true,
 2162            custom_context_menu: None,
 2163            show_git_blame_gutter: false,
 2164            show_git_blame_inline: false,
 2165            show_selection_menu: None,
 2166            show_git_blame_inline_delay_task: None,
 2167            git_blame_inline_enabled: full_mode
 2168                && ProjectSettings::get_global(cx).git.inline_blame.enabled,
 2169            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2170            serialize_dirty_buffers: !is_minimap
 2171                && ProjectSettings::get_global(cx)
 2172                    .session
 2173                    .restore_unsaved_buffers,
 2174            blame: None,
 2175            blame_subscription: None,
 2176            tasks: BTreeMap::default(),
 2177
 2178            breakpoint_store,
 2179            gutter_breakpoint_indicator: (None, None),
 2180            hovered_diff_hunk_row: None,
 2181            _subscriptions: (!is_minimap)
 2182                .then(|| {
 2183                    vec![
 2184                        cx.observe(&multi_buffer, Self::on_buffer_changed),
 2185                        cx.subscribe_in(&multi_buffer, window, Self::on_buffer_event),
 2186                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2187                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2188                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2189                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2190                        cx.observe_window_activation(window, |editor, window, cx| {
 2191                            let active = window.is_window_active();
 2192                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2193                                if active {
 2194                                    blink_manager.enable(cx);
 2195                                } else {
 2196                                    blink_manager.disable(cx);
 2197                                }
 2198                            });
 2199                            if active {
 2200                                editor.show_mouse_cursor(cx);
 2201                            }
 2202                        }),
 2203                    ]
 2204                })
 2205                .unwrap_or_default(),
 2206            tasks_update_task: None,
 2207            pull_diagnostics_task: Task::ready(()),
 2208            colors: None,
 2209            refresh_colors_task: Task::ready(()),
 2210            inlay_hints: None,
 2211            next_color_inlay_id: 0,
 2212            post_scroll_update: Task::ready(()),
 2213            linked_edit_ranges: Default::default(),
 2214            in_project_search: false,
 2215            previous_search_ranges: None,
 2216            breadcrumb_header: None,
 2217            focused_block: None,
 2218            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2219            addons: HashMap::default(),
 2220            registered_buffers: HashMap::default(),
 2221            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2222            selection_mark_mode: false,
 2223            toggle_fold_multiple_buffers: Task::ready(()),
 2224            serialize_selections: Task::ready(()),
 2225            serialize_folds: Task::ready(()),
 2226            text_style_refinement: None,
 2227            load_diff_task: load_uncommitted_diff,
 2228            temporary_diff_override: false,
 2229            mouse_cursor_hidden: false,
 2230            minimap: None,
 2231            hide_mouse_mode: EditorSettings::get_global(cx)
 2232                .hide_mouse
 2233                .unwrap_or_default(),
 2234            change_list: ChangeList::new(),
 2235            mode,
 2236            selection_drag_state: SelectionDragState::None,
 2237            folding_newlines: Task::ready(()),
 2238            lookup_key: None,
 2239        };
 2240
 2241        if is_minimap {
 2242            return editor;
 2243        }
 2244
 2245        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2246            editor
 2247                ._subscriptions
 2248                .push(cx.observe(breakpoints, |_, _, cx| {
 2249                    cx.notify();
 2250                }));
 2251        }
 2252        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2253        editor._subscriptions.extend(project_subscriptions);
 2254
 2255        editor._subscriptions.push(cx.subscribe_in(
 2256            &cx.entity(),
 2257            window,
 2258            |editor, _, e: &EditorEvent, window, cx| match e {
 2259                EditorEvent::ScrollPositionChanged { local, .. } => {
 2260                    if *local {
 2261                        let new_anchor = editor.scroll_manager.anchor();
 2262                        let snapshot = editor.snapshot(window, cx);
 2263                        editor.update_restoration_data(cx, move |data| {
 2264                            data.scroll_position = (
 2265                                new_anchor.top_row(snapshot.buffer_snapshot()),
 2266                                new_anchor.offset,
 2267                            );
 2268                        });
 2269                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2270                        editor.inline_blame_popover.take();
 2271                    }
 2272                }
 2273                EditorEvent::Edited { .. } => {
 2274                    if vim_flavor(cx).is_none() {
 2275                        let display_map = editor.display_snapshot(cx);
 2276                        let selections = editor.selections.all_adjusted_display(&display_map);
 2277                        let pop_state = editor
 2278                            .change_list
 2279                            .last()
 2280                            .map(|previous| {
 2281                                previous.len() == selections.len()
 2282                                    && previous.iter().enumerate().all(|(ix, p)| {
 2283                                        p.to_display_point(&display_map).row()
 2284                                            == selections[ix].head().row()
 2285                                    })
 2286                            })
 2287                            .unwrap_or(false);
 2288                        let new_positions = selections
 2289                            .into_iter()
 2290                            .map(|s| display_map.display_point_to_anchor(s.head(), Bias::Left))
 2291                            .collect();
 2292                        editor
 2293                            .change_list
 2294                            .push_to_change_list(pop_state, new_positions);
 2295                    }
 2296                }
 2297                _ => (),
 2298            },
 2299        ));
 2300
 2301        if let Some(dap_store) = editor
 2302            .project
 2303            .as_ref()
 2304            .map(|project| project.read(cx).dap_store())
 2305        {
 2306            let weak_editor = cx.weak_entity();
 2307
 2308            editor
 2309                ._subscriptions
 2310                .push(
 2311                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2312                        let session_entity = cx.entity();
 2313                        weak_editor
 2314                            .update(cx, |editor, cx| {
 2315                                editor._subscriptions.push(
 2316                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2317                                );
 2318                            })
 2319                            .ok();
 2320                    }),
 2321                );
 2322
 2323            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2324                editor
 2325                    ._subscriptions
 2326                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2327            }
 2328        }
 2329
 2330        // skip adding the initial selection to selection history
 2331        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2332        editor.end_selection(window, cx);
 2333        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2334
 2335        editor.scroll_manager.show_scrollbars(window, cx);
 2336        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &multi_buffer, cx);
 2337
 2338        if full_mode {
 2339            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2340            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2341
 2342            if editor.git_blame_inline_enabled {
 2343                editor.start_git_blame_inline(false, window, cx);
 2344            }
 2345
 2346            editor.go_to_active_debug_line(window, cx);
 2347
 2348            editor.minimap =
 2349                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2350            editor.colors = Some(LspColorData::new(cx));
 2351            editor.inlay_hints = Some(LspInlayHintData::new(inlay_hint_settings));
 2352
 2353            if let Some(buffer) = multi_buffer.read(cx).as_singleton() {
 2354                editor.register_buffer(buffer.read(cx).remote_id(), cx);
 2355            }
 2356            editor.update_lsp_data(None, window, cx);
 2357            editor.report_editor_event(ReportEditorEvent::EditorOpened, None, cx);
 2358        }
 2359
 2360        editor
 2361    }
 2362
 2363    pub fn display_snapshot(&self, cx: &mut App) -> DisplaySnapshot {
 2364        self.selections.display_map(cx)
 2365    }
 2366
 2367    pub fn deploy_mouse_context_menu(
 2368        &mut self,
 2369        position: gpui::Point<Pixels>,
 2370        context_menu: Entity<ContextMenu>,
 2371        window: &mut Window,
 2372        cx: &mut Context<Self>,
 2373    ) {
 2374        self.mouse_context_menu = Some(MouseContextMenu::new(
 2375            self,
 2376            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2377            context_menu,
 2378            window,
 2379            cx,
 2380        ));
 2381    }
 2382
 2383    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2384        self.mouse_context_menu
 2385            .as_ref()
 2386            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2387    }
 2388
 2389    pub fn is_range_selected(&mut self, range: &Range<Anchor>, cx: &mut Context<Self>) -> bool {
 2390        if self
 2391            .selections
 2392            .pending_anchor()
 2393            .is_some_and(|pending_selection| {
 2394                let snapshot = self.buffer().read(cx).snapshot(cx);
 2395                pending_selection.range().includes(range, &snapshot)
 2396            })
 2397        {
 2398            return true;
 2399        }
 2400
 2401        self.selections
 2402            .disjoint_in_range::<usize>(range.clone(), &self.display_snapshot(cx))
 2403            .into_iter()
 2404            .any(|selection| {
 2405                // This is needed to cover a corner case, if we just check for an existing
 2406                // selection in the fold range, having a cursor at the start of the fold
 2407                // marks it as selected. Non-empty selections don't cause this.
 2408                let length = selection.end - selection.start;
 2409                length > 0
 2410            })
 2411    }
 2412
 2413    pub fn key_context(&self, window: &mut Window, cx: &mut App) -> KeyContext {
 2414        self.key_context_internal(self.has_active_edit_prediction(), window, cx)
 2415    }
 2416
 2417    fn key_context_internal(
 2418        &self,
 2419        has_active_edit_prediction: bool,
 2420        window: &mut Window,
 2421        cx: &mut App,
 2422    ) -> KeyContext {
 2423        let mut key_context = KeyContext::new_with_defaults();
 2424        key_context.add("Editor");
 2425        let mode = match self.mode {
 2426            EditorMode::SingleLine => "single_line",
 2427            EditorMode::AutoHeight { .. } => "auto_height",
 2428            EditorMode::Minimap { .. } => "minimap",
 2429            EditorMode::Full { .. } => "full",
 2430        };
 2431
 2432        if EditorSettings::jupyter_enabled(cx) {
 2433            key_context.add("jupyter");
 2434        }
 2435
 2436        key_context.set("mode", mode);
 2437        if self.pending_rename.is_some() {
 2438            key_context.add("renaming");
 2439        }
 2440
 2441        if !self.snippet_stack.is_empty() {
 2442            key_context.add("in_snippet");
 2443        }
 2444
 2445        match self.context_menu.borrow().as_ref() {
 2446            Some(CodeContextMenu::Completions(menu)) => {
 2447                if menu.visible() {
 2448                    key_context.add("menu");
 2449                    key_context.add("showing_completions");
 2450                }
 2451            }
 2452            Some(CodeContextMenu::CodeActions(menu)) => {
 2453                if menu.visible() {
 2454                    key_context.add("menu");
 2455                    key_context.add("showing_code_actions")
 2456                }
 2457            }
 2458            None => {}
 2459        }
 2460
 2461        if self.signature_help_state.has_multiple_signatures() {
 2462            key_context.add("showing_signature_help");
 2463        }
 2464
 2465        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2466        if !self.focus_handle(cx).contains_focused(window, cx)
 2467            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2468        {
 2469            for addon in self.addons.values() {
 2470                addon.extend_key_context(&mut key_context, cx)
 2471            }
 2472        }
 2473
 2474        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2475            if let Some(extension) = singleton_buffer.read(cx).file().and_then(|file| {
 2476                Some(
 2477                    file.full_path(cx)
 2478                        .extension()?
 2479                        .to_string_lossy()
 2480                        .into_owned(),
 2481                )
 2482            }) {
 2483                key_context.set("extension", extension);
 2484            }
 2485        } else {
 2486            key_context.add("multibuffer");
 2487        }
 2488
 2489        if has_active_edit_prediction {
 2490            if self.edit_prediction_in_conflict() {
 2491                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2492            } else {
 2493                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2494                key_context.add("copilot_suggestion");
 2495            }
 2496        }
 2497
 2498        if self.selection_mark_mode {
 2499            key_context.add("selection_mode");
 2500        }
 2501
 2502        let disjoint = self.selections.disjoint_anchors();
 2503        let snapshot = self.snapshot(window, cx);
 2504        let snapshot = snapshot.buffer_snapshot();
 2505        if self.mode == EditorMode::SingleLine
 2506            && let [selection] = disjoint
 2507            && selection.start == selection.end
 2508            && selection.end.to_offset(snapshot) == snapshot.len()
 2509        {
 2510            key_context.add("end_of_input");
 2511        }
 2512
 2513        key_context
 2514    }
 2515
 2516    pub fn last_bounds(&self) -> Option<&Bounds<Pixels>> {
 2517        self.last_bounds.as_ref()
 2518    }
 2519
 2520    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2521        if self.mouse_cursor_hidden {
 2522            self.mouse_cursor_hidden = false;
 2523            cx.notify();
 2524        }
 2525    }
 2526
 2527    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2528        let hide_mouse_cursor = match origin {
 2529            HideMouseCursorOrigin::TypingAction => {
 2530                matches!(
 2531                    self.hide_mouse_mode,
 2532                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2533                )
 2534            }
 2535            HideMouseCursorOrigin::MovementAction => {
 2536                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2537            }
 2538        };
 2539        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2540            self.mouse_cursor_hidden = hide_mouse_cursor;
 2541            cx.notify();
 2542        }
 2543    }
 2544
 2545    pub fn edit_prediction_in_conflict(&self) -> bool {
 2546        if !self.show_edit_predictions_in_menu() {
 2547            return false;
 2548        }
 2549
 2550        let showing_completions = self
 2551            .context_menu
 2552            .borrow()
 2553            .as_ref()
 2554            .is_some_and(|context| matches!(context, CodeContextMenu::Completions(_)));
 2555
 2556        showing_completions
 2557            || self.edit_prediction_requires_modifier()
 2558            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2559            // bindings to insert tab characters.
 2560            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2561    }
 2562
 2563    pub fn accept_edit_prediction_keybind(
 2564        &self,
 2565        accept_partial: bool,
 2566        window: &mut Window,
 2567        cx: &mut App,
 2568    ) -> AcceptEditPredictionBinding {
 2569        let key_context = self.key_context_internal(true, window, cx);
 2570        let in_conflict = self.edit_prediction_in_conflict();
 2571
 2572        let bindings = if accept_partial {
 2573            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2574        } else {
 2575            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2576        };
 2577
 2578        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2579        // just the first one.
 2580        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2581            !in_conflict
 2582                || binding
 2583                    .keystrokes()
 2584                    .first()
 2585                    .is_some_and(|keystroke| keystroke.modifiers().modified())
 2586        }))
 2587    }
 2588
 2589    pub fn new_file(
 2590        workspace: &mut Workspace,
 2591        _: &workspace::NewFile,
 2592        window: &mut Window,
 2593        cx: &mut Context<Workspace>,
 2594    ) {
 2595        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2596            "Failed to create buffer",
 2597            window,
 2598            cx,
 2599            |e, _, _| match e.error_code() {
 2600                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2601                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2602                e.error_tag("required").unwrap_or("the latest version")
 2603            )),
 2604                _ => None,
 2605            },
 2606        );
 2607    }
 2608
 2609    pub fn new_in_workspace(
 2610        workspace: &mut Workspace,
 2611        window: &mut Window,
 2612        cx: &mut Context<Workspace>,
 2613    ) -> Task<Result<Entity<Editor>>> {
 2614        let project = workspace.project().clone();
 2615        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2616
 2617        cx.spawn_in(window, async move |workspace, cx| {
 2618            let buffer = create.await?;
 2619            workspace.update_in(cx, |workspace, window, cx| {
 2620                let editor =
 2621                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2622                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2623                editor
 2624            })
 2625        })
 2626    }
 2627
 2628    fn new_file_vertical(
 2629        workspace: &mut Workspace,
 2630        _: &workspace::NewFileSplitVertical,
 2631        window: &mut Window,
 2632        cx: &mut Context<Workspace>,
 2633    ) {
 2634        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2635    }
 2636
 2637    fn new_file_horizontal(
 2638        workspace: &mut Workspace,
 2639        _: &workspace::NewFileSplitHorizontal,
 2640        window: &mut Window,
 2641        cx: &mut Context<Workspace>,
 2642    ) {
 2643        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2644    }
 2645
 2646    fn new_file_split(
 2647        workspace: &mut Workspace,
 2648        action: &workspace::NewFileSplit,
 2649        window: &mut Window,
 2650        cx: &mut Context<Workspace>,
 2651    ) {
 2652        Self::new_file_in_direction(workspace, action.0, window, cx)
 2653    }
 2654
 2655    fn new_file_in_direction(
 2656        workspace: &mut Workspace,
 2657        direction: SplitDirection,
 2658        window: &mut Window,
 2659        cx: &mut Context<Workspace>,
 2660    ) {
 2661        let project = workspace.project().clone();
 2662        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2663
 2664        cx.spawn_in(window, async move |workspace, cx| {
 2665            let buffer = create.await?;
 2666            workspace.update_in(cx, move |workspace, window, cx| {
 2667                workspace.split_item(
 2668                    direction,
 2669                    Box::new(
 2670                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2671                    ),
 2672                    window,
 2673                    cx,
 2674                )
 2675            })?;
 2676            anyhow::Ok(())
 2677        })
 2678        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2679            match e.error_code() {
 2680                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2681                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2682                e.error_tag("required").unwrap_or("the latest version")
 2683            )),
 2684                _ => None,
 2685            }
 2686        });
 2687    }
 2688
 2689    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2690        self.leader_id
 2691    }
 2692
 2693    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2694        &self.buffer
 2695    }
 2696
 2697    pub fn project(&self) -> Option<&Entity<Project>> {
 2698        self.project.as_ref()
 2699    }
 2700
 2701    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2702        self.workspace.as_ref()?.0.upgrade()
 2703    }
 2704
 2705    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2706        self.buffer().read(cx).title(cx)
 2707    }
 2708
 2709    pub fn snapshot(&self, window: &Window, cx: &mut App) -> EditorSnapshot {
 2710        let git_blame_gutter_max_author_length = self
 2711            .render_git_blame_gutter(cx)
 2712            .then(|| {
 2713                if let Some(blame) = self.blame.as_ref() {
 2714                    let max_author_length =
 2715                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2716                    Some(max_author_length)
 2717                } else {
 2718                    None
 2719                }
 2720            })
 2721            .flatten();
 2722
 2723        EditorSnapshot {
 2724            mode: self.mode.clone(),
 2725            show_gutter: self.show_gutter,
 2726            show_line_numbers: self.show_line_numbers,
 2727            show_git_diff_gutter: self.show_git_diff_gutter,
 2728            show_code_actions: self.show_code_actions,
 2729            show_runnables: self.show_runnables,
 2730            show_breakpoints: self.show_breakpoints,
 2731            git_blame_gutter_max_author_length,
 2732            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2733            placeholder_display_snapshot: self
 2734                .placeholder_display_map
 2735                .as_ref()
 2736                .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx))),
 2737            scroll_anchor: self.scroll_manager.anchor(),
 2738            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2739            is_focused: self.focus_handle.is_focused(window),
 2740            current_line_highlight: self
 2741                .current_line_highlight
 2742                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2743            gutter_hovered: self.gutter_hovered,
 2744        }
 2745    }
 2746
 2747    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2748        self.buffer.read(cx).language_at(point, cx)
 2749    }
 2750
 2751    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2752        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2753    }
 2754
 2755    pub fn active_excerpt(
 2756        &self,
 2757        cx: &App,
 2758    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2759        self.buffer
 2760            .read(cx)
 2761            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2762    }
 2763
 2764    pub fn mode(&self) -> &EditorMode {
 2765        &self.mode
 2766    }
 2767
 2768    pub fn set_mode(&mut self, mode: EditorMode) {
 2769        self.mode = mode;
 2770    }
 2771
 2772    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2773        self.collaboration_hub.as_deref()
 2774    }
 2775
 2776    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2777        self.collaboration_hub = Some(hub);
 2778    }
 2779
 2780    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2781        self.in_project_search = in_project_search;
 2782    }
 2783
 2784    pub fn set_custom_context_menu(
 2785        &mut self,
 2786        f: impl 'static
 2787        + Fn(
 2788            &mut Self,
 2789            DisplayPoint,
 2790            &mut Window,
 2791            &mut Context<Self>,
 2792        ) -> Option<Entity<ui::ContextMenu>>,
 2793    ) {
 2794        self.custom_context_menu = Some(Box::new(f))
 2795    }
 2796
 2797    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2798        self.completion_provider = provider;
 2799    }
 2800
 2801    #[cfg(any(test, feature = "test-support"))]
 2802    pub fn completion_provider(&self) -> Option<Rc<dyn CompletionProvider>> {
 2803        self.completion_provider.clone()
 2804    }
 2805
 2806    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2807        self.semantics_provider.clone()
 2808    }
 2809
 2810    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2811        self.semantics_provider = provider;
 2812    }
 2813
 2814    pub fn set_edit_prediction_provider<T>(
 2815        &mut self,
 2816        provider: Option<Entity<T>>,
 2817        window: &mut Window,
 2818        cx: &mut Context<Self>,
 2819    ) where
 2820        T: EditPredictionProvider,
 2821    {
 2822        self.edit_prediction_provider = provider.map(|provider| RegisteredEditPredictionProvider {
 2823            _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2824                if this.focus_handle.is_focused(window) {
 2825                    this.update_visible_edit_prediction(window, cx);
 2826                }
 2827            }),
 2828            provider: Arc::new(provider),
 2829        });
 2830        self.update_edit_prediction_settings(cx);
 2831        self.refresh_edit_prediction(false, false, window, cx);
 2832    }
 2833
 2834    pub fn placeholder_text(&self, cx: &mut App) -> Option<String> {
 2835        self.placeholder_display_map
 2836            .as_ref()
 2837            .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx)).text())
 2838    }
 2839
 2840    pub fn set_placeholder_text(
 2841        &mut self,
 2842        placeholder_text: &str,
 2843        window: &mut Window,
 2844        cx: &mut Context<Self>,
 2845    ) {
 2846        let multibuffer = cx
 2847            .new(|cx| MultiBuffer::singleton(cx.new(|cx| Buffer::local(placeholder_text, cx)), cx));
 2848
 2849        let style = window.text_style();
 2850
 2851        self.placeholder_display_map = Some(cx.new(|cx| {
 2852            DisplayMap::new(
 2853                multibuffer,
 2854                style.font(),
 2855                style.font_size.to_pixels(window.rem_size()),
 2856                None,
 2857                FILE_HEADER_HEIGHT,
 2858                MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 2859                Default::default(),
 2860                DiagnosticSeverity::Off,
 2861                cx,
 2862            )
 2863        }));
 2864        cx.notify();
 2865    }
 2866
 2867    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2868        self.cursor_shape = cursor_shape;
 2869
 2870        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2871        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2872
 2873        cx.notify();
 2874    }
 2875
 2876    pub fn set_current_line_highlight(
 2877        &mut self,
 2878        current_line_highlight: Option<CurrentLineHighlight>,
 2879    ) {
 2880        self.current_line_highlight = current_line_highlight;
 2881    }
 2882
 2883    pub fn range_for_match<T: std::marker::Copy>(
 2884        &self,
 2885        range: &Range<T>,
 2886        collapse: bool,
 2887    ) -> Range<T> {
 2888        if collapse {
 2889            return range.start..range.start;
 2890        }
 2891        range.clone()
 2892    }
 2893
 2894    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2895        if self.display_map.read(cx).clip_at_line_ends != clip {
 2896            self.display_map
 2897                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2898        }
 2899    }
 2900
 2901    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2902        self.input_enabled = input_enabled;
 2903    }
 2904
 2905    pub fn set_edit_predictions_hidden_for_vim_mode(
 2906        &mut self,
 2907        hidden: bool,
 2908        window: &mut Window,
 2909        cx: &mut Context<Self>,
 2910    ) {
 2911        if hidden != self.edit_predictions_hidden_for_vim_mode {
 2912            self.edit_predictions_hidden_for_vim_mode = hidden;
 2913            if hidden {
 2914                self.update_visible_edit_prediction(window, cx);
 2915            } else {
 2916                self.refresh_edit_prediction(true, false, window, cx);
 2917            }
 2918        }
 2919    }
 2920
 2921    pub fn set_menu_edit_predictions_policy(&mut self, value: MenuEditPredictionsPolicy) {
 2922        self.menu_edit_predictions_policy = value;
 2923    }
 2924
 2925    pub fn set_autoindent(&mut self, autoindent: bool) {
 2926        if autoindent {
 2927            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2928        } else {
 2929            self.autoindent_mode = None;
 2930        }
 2931    }
 2932
 2933    pub fn read_only(&self, cx: &App) -> bool {
 2934        self.read_only || self.buffer.read(cx).read_only()
 2935    }
 2936
 2937    pub fn set_read_only(&mut self, read_only: bool) {
 2938        self.read_only = read_only;
 2939    }
 2940
 2941    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2942        self.use_autoclose = autoclose;
 2943    }
 2944
 2945    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2946        self.use_auto_surround = auto_surround;
 2947    }
 2948
 2949    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2950        self.auto_replace_emoji_shortcode = auto_replace;
 2951    }
 2952
 2953    pub fn toggle_edit_predictions(
 2954        &mut self,
 2955        _: &ToggleEditPrediction,
 2956        window: &mut Window,
 2957        cx: &mut Context<Self>,
 2958    ) {
 2959        if self.show_edit_predictions_override.is_some() {
 2960            self.set_show_edit_predictions(None, window, cx);
 2961        } else {
 2962            let show_edit_predictions = !self.edit_predictions_enabled();
 2963            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2964        }
 2965    }
 2966
 2967    pub fn set_show_edit_predictions(
 2968        &mut self,
 2969        show_edit_predictions: Option<bool>,
 2970        window: &mut Window,
 2971        cx: &mut Context<Self>,
 2972    ) {
 2973        self.show_edit_predictions_override = show_edit_predictions;
 2974        self.update_edit_prediction_settings(cx);
 2975
 2976        if let Some(false) = show_edit_predictions {
 2977            self.discard_edit_prediction(false, cx);
 2978        } else {
 2979            self.refresh_edit_prediction(false, true, window, cx);
 2980        }
 2981    }
 2982
 2983    fn edit_predictions_disabled_in_scope(
 2984        &self,
 2985        buffer: &Entity<Buffer>,
 2986        buffer_position: language::Anchor,
 2987        cx: &App,
 2988    ) -> bool {
 2989        let snapshot = buffer.read(cx).snapshot();
 2990        let settings = snapshot.settings_at(buffer_position, cx);
 2991
 2992        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 2993            return false;
 2994        };
 2995
 2996        scope.override_name().is_some_and(|scope_name| {
 2997            settings
 2998                .edit_predictions_disabled_in
 2999                .iter()
 3000                .any(|s| s == scope_name)
 3001        })
 3002    }
 3003
 3004    pub fn set_use_modal_editing(&mut self, to: bool) {
 3005        self.use_modal_editing = to;
 3006    }
 3007
 3008    pub fn use_modal_editing(&self) -> bool {
 3009        self.use_modal_editing
 3010    }
 3011
 3012    fn selections_did_change(
 3013        &mut self,
 3014        local: bool,
 3015        old_cursor_position: &Anchor,
 3016        effects: SelectionEffects,
 3017        window: &mut Window,
 3018        cx: &mut Context<Self>,
 3019    ) {
 3020        window.invalidate_character_coordinates();
 3021
 3022        // Copy selections to primary selection buffer
 3023        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 3024        if local {
 3025            let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 3026            let buffer_handle = self.buffer.read(cx).read(cx);
 3027
 3028            let mut text = String::new();
 3029            for (index, selection) in selections.iter().enumerate() {
 3030                let text_for_selection = buffer_handle
 3031                    .text_for_range(selection.start..selection.end)
 3032                    .collect::<String>();
 3033
 3034                text.push_str(&text_for_selection);
 3035                if index != selections.len() - 1 {
 3036                    text.push('\n');
 3037                }
 3038            }
 3039
 3040            if !text.is_empty() {
 3041                cx.write_to_primary(ClipboardItem::new_string(text));
 3042            }
 3043        }
 3044
 3045        let selection_anchors = self.selections.disjoint_anchors_arc();
 3046
 3047        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 3048            self.buffer.update(cx, |buffer, cx| {
 3049                buffer.set_active_selections(
 3050                    &selection_anchors,
 3051                    self.selections.line_mode(),
 3052                    self.cursor_shape,
 3053                    cx,
 3054                )
 3055            });
 3056        }
 3057        let display_map = self
 3058            .display_map
 3059            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3060        let buffer = display_map.buffer_snapshot();
 3061        if self.selections.count() == 1 {
 3062            self.add_selections_state = None;
 3063        }
 3064        self.select_next_state = None;
 3065        self.select_prev_state = None;
 3066        self.select_syntax_node_history.try_clear();
 3067        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 3068        self.snippet_stack.invalidate(&selection_anchors, buffer);
 3069        self.take_rename(false, window, cx);
 3070
 3071        let newest_selection = self.selections.newest_anchor();
 3072        let new_cursor_position = newest_selection.head();
 3073        let selection_start = newest_selection.start;
 3074
 3075        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 3076            self.push_to_nav_history(
 3077                *old_cursor_position,
 3078                Some(new_cursor_position.to_point(buffer)),
 3079                false,
 3080                effects.nav_history == Some(true),
 3081                cx,
 3082            );
 3083        }
 3084
 3085        if local {
 3086            if let Some(buffer_id) = new_cursor_position.buffer_id {
 3087                self.register_buffer(buffer_id, cx);
 3088            }
 3089
 3090            let mut context_menu = self.context_menu.borrow_mut();
 3091            let completion_menu = match context_menu.as_ref() {
 3092                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3093                Some(CodeContextMenu::CodeActions(_)) => {
 3094                    *context_menu = None;
 3095                    None
 3096                }
 3097                None => None,
 3098            };
 3099            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3100            drop(context_menu);
 3101
 3102            if effects.completions
 3103                && let Some(completion_position) = completion_position
 3104            {
 3105                let start_offset = selection_start.to_offset(buffer);
 3106                let position_matches = start_offset == completion_position.to_offset(buffer);
 3107                let continue_showing = if position_matches {
 3108                    if self.snippet_stack.is_empty() {
 3109                        buffer.char_kind_before(start_offset, Some(CharScopeContext::Completion))
 3110                            == Some(CharKind::Word)
 3111                    } else {
 3112                        // Snippet choices can be shown even when the cursor is in whitespace.
 3113                        // Dismissing the menu with actions like backspace is handled by
 3114                        // invalidation regions.
 3115                        true
 3116                    }
 3117                } else {
 3118                    false
 3119                };
 3120
 3121                if continue_showing {
 3122                    self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 3123                } else {
 3124                    self.hide_context_menu(window, cx);
 3125                }
 3126            }
 3127
 3128            hide_hover(self, cx);
 3129
 3130            if old_cursor_position.to_display_point(&display_map).row()
 3131                != new_cursor_position.to_display_point(&display_map).row()
 3132            {
 3133                self.available_code_actions.take();
 3134            }
 3135            self.refresh_code_actions(window, cx);
 3136            self.refresh_document_highlights(cx);
 3137            refresh_linked_ranges(self, window, cx);
 3138
 3139            self.refresh_selected_text_highlights(false, window, cx);
 3140            self.refresh_matching_bracket_highlights(window, cx);
 3141            self.update_visible_edit_prediction(window, cx);
 3142            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3143            self.inline_blame_popover.take();
 3144            if self.git_blame_inline_enabled {
 3145                self.start_inline_blame_timer(window, cx);
 3146            }
 3147        }
 3148
 3149        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3150        cx.emit(EditorEvent::SelectionsChanged { local });
 3151
 3152        let selections = &self.selections.disjoint_anchors_arc();
 3153        if selections.len() == 1 {
 3154            cx.emit(SearchEvent::ActiveMatchChanged)
 3155        }
 3156        if local && let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3157            let inmemory_selections = selections
 3158                .iter()
 3159                .map(|s| {
 3160                    text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3161                        ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3162                })
 3163                .collect();
 3164            self.update_restoration_data(cx, |data| {
 3165                data.selections = inmemory_selections;
 3166            });
 3167
 3168            if WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
 3169                && let Some(workspace_id) =
 3170                    self.workspace.as_ref().and_then(|workspace| workspace.1)
 3171            {
 3172                let snapshot = self.buffer().read(cx).snapshot(cx);
 3173                let selections = selections.clone();
 3174                let background_executor = cx.background_executor().clone();
 3175                let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3176                self.serialize_selections = cx.background_spawn(async move {
 3177                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3178                    let db_selections = selections
 3179                        .iter()
 3180                        .map(|selection| {
 3181                            (
 3182                                selection.start.to_offset(&snapshot),
 3183                                selection.end.to_offset(&snapshot),
 3184                            )
 3185                        })
 3186                        .collect();
 3187
 3188                    DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3189                        .await
 3190                        .with_context(|| {
 3191                            format!(
 3192                                "persisting editor selections for editor {editor_id}, \
 3193                                workspace {workspace_id:?}"
 3194                            )
 3195                        })
 3196                        .log_err();
 3197                });
 3198            }
 3199        }
 3200
 3201        cx.notify();
 3202    }
 3203
 3204    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3205        use text::ToOffset as _;
 3206        use text::ToPoint as _;
 3207
 3208        if self.mode.is_minimap()
 3209            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3210        {
 3211            return;
 3212        }
 3213
 3214        if !self.buffer().read(cx).is_singleton() {
 3215            return;
 3216        }
 3217
 3218        let display_snapshot = self
 3219            .display_map
 3220            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3221        let Some((.., snapshot)) = display_snapshot.buffer_snapshot().as_singleton() else {
 3222            return;
 3223        };
 3224        let inmemory_folds = display_snapshot
 3225            .folds_in_range(0..display_snapshot.buffer_snapshot().len())
 3226            .map(|fold| {
 3227                fold.range.start.text_anchor.to_point(&snapshot)
 3228                    ..fold.range.end.text_anchor.to_point(&snapshot)
 3229            })
 3230            .collect();
 3231        self.update_restoration_data(cx, |data| {
 3232            data.folds = inmemory_folds;
 3233        });
 3234
 3235        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 3236            return;
 3237        };
 3238        let background_executor = cx.background_executor().clone();
 3239        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3240        let db_folds = display_snapshot
 3241            .folds_in_range(0..display_snapshot.buffer_snapshot().len())
 3242            .map(|fold| {
 3243                (
 3244                    fold.range.start.text_anchor.to_offset(&snapshot),
 3245                    fold.range.end.text_anchor.to_offset(&snapshot),
 3246                )
 3247            })
 3248            .collect();
 3249        self.serialize_folds = cx.background_spawn(async move {
 3250            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3251            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3252                .await
 3253                .with_context(|| {
 3254                    format!(
 3255                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3256                    )
 3257                })
 3258                .log_err();
 3259        });
 3260    }
 3261
 3262    pub fn sync_selections(
 3263        &mut self,
 3264        other: Entity<Editor>,
 3265        cx: &mut Context<Self>,
 3266    ) -> gpui::Subscription {
 3267        let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3268        if !other_selections.is_empty() {
 3269            self.selections.change_with(cx, |selections| {
 3270                selections.select_anchors(other_selections);
 3271            });
 3272        }
 3273
 3274        let other_subscription = cx.subscribe(&other, |this, other, other_evt, cx| {
 3275            if let EditorEvent::SelectionsChanged { local: true } = other_evt {
 3276                let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3277                if other_selections.is_empty() {
 3278                    return;
 3279                }
 3280                this.selections.change_with(cx, |selections| {
 3281                    selections.select_anchors(other_selections);
 3282                });
 3283            }
 3284        });
 3285
 3286        let this_subscription = cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| {
 3287            if let EditorEvent::SelectionsChanged { local: true } = this_evt {
 3288                let these_selections = this.selections.disjoint_anchors().to_vec();
 3289                if these_selections.is_empty() {
 3290                    return;
 3291                }
 3292                other.update(cx, |other_editor, cx| {
 3293                    other_editor.selections.change_with(cx, |selections| {
 3294                        selections.select_anchors(these_selections);
 3295                    })
 3296                });
 3297            }
 3298        });
 3299
 3300        Subscription::join(other_subscription, this_subscription)
 3301    }
 3302
 3303    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3304    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3305    /// effects of selection change occur at the end of the transaction.
 3306    pub fn change_selections<R>(
 3307        &mut self,
 3308        effects: SelectionEffects,
 3309        window: &mut Window,
 3310        cx: &mut Context<Self>,
 3311        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3312    ) -> R {
 3313        if let Some(state) = &mut self.deferred_selection_effects_state {
 3314            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3315            state.effects.completions = effects.completions;
 3316            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3317            let (changed, result) = self.selections.change_with(cx, change);
 3318            state.changed |= changed;
 3319            return result;
 3320        }
 3321        let mut state = DeferredSelectionEffectsState {
 3322            changed: false,
 3323            effects,
 3324            old_cursor_position: self.selections.newest_anchor().head(),
 3325            history_entry: SelectionHistoryEntry {
 3326                selections: self.selections.disjoint_anchors_arc(),
 3327                select_next_state: self.select_next_state.clone(),
 3328                select_prev_state: self.select_prev_state.clone(),
 3329                add_selections_state: self.add_selections_state.clone(),
 3330            },
 3331        };
 3332        let (changed, result) = self.selections.change_with(cx, change);
 3333        state.changed = state.changed || changed;
 3334        if self.defer_selection_effects {
 3335            self.deferred_selection_effects_state = Some(state);
 3336        } else {
 3337            self.apply_selection_effects(state, window, cx);
 3338        }
 3339        result
 3340    }
 3341
 3342    /// Defers the effects of selection change, so that the effects of multiple calls to
 3343    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3344    /// to selection history and the state of popovers based on selection position aren't
 3345    /// erroneously updated.
 3346    pub fn with_selection_effects_deferred<R>(
 3347        &mut self,
 3348        window: &mut Window,
 3349        cx: &mut Context<Self>,
 3350        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3351    ) -> R {
 3352        let already_deferred = self.defer_selection_effects;
 3353        self.defer_selection_effects = true;
 3354        let result = update(self, window, cx);
 3355        if !already_deferred {
 3356            self.defer_selection_effects = false;
 3357            if let Some(state) = self.deferred_selection_effects_state.take() {
 3358                self.apply_selection_effects(state, window, cx);
 3359            }
 3360        }
 3361        result
 3362    }
 3363
 3364    fn apply_selection_effects(
 3365        &mut self,
 3366        state: DeferredSelectionEffectsState,
 3367        window: &mut Window,
 3368        cx: &mut Context<Self>,
 3369    ) {
 3370        if state.changed {
 3371            self.selection_history.push(state.history_entry);
 3372
 3373            if let Some(autoscroll) = state.effects.scroll {
 3374                self.request_autoscroll(autoscroll, cx);
 3375            }
 3376
 3377            let old_cursor_position = &state.old_cursor_position;
 3378
 3379            self.selections_did_change(true, old_cursor_position, state.effects, window, cx);
 3380
 3381            if self.should_open_signature_help_automatically(old_cursor_position, cx) {
 3382                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3383            }
 3384        }
 3385    }
 3386
 3387    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3388    where
 3389        I: IntoIterator<Item = (Range<S>, T)>,
 3390        S: ToOffset,
 3391        T: Into<Arc<str>>,
 3392    {
 3393        if self.read_only(cx) {
 3394            return;
 3395        }
 3396
 3397        self.buffer
 3398            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3399    }
 3400
 3401    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3402    where
 3403        I: IntoIterator<Item = (Range<S>, T)>,
 3404        S: ToOffset,
 3405        T: Into<Arc<str>>,
 3406    {
 3407        if self.read_only(cx) {
 3408            return;
 3409        }
 3410
 3411        self.buffer.update(cx, |buffer, cx| {
 3412            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3413        });
 3414    }
 3415
 3416    pub fn edit_with_block_indent<I, S, T>(
 3417        &mut self,
 3418        edits: I,
 3419        original_indent_columns: Vec<Option<u32>>,
 3420        cx: &mut Context<Self>,
 3421    ) where
 3422        I: IntoIterator<Item = (Range<S>, T)>,
 3423        S: ToOffset,
 3424        T: Into<Arc<str>>,
 3425    {
 3426        if self.read_only(cx) {
 3427            return;
 3428        }
 3429
 3430        self.buffer.update(cx, |buffer, cx| {
 3431            buffer.edit(
 3432                edits,
 3433                Some(AutoindentMode::Block {
 3434                    original_indent_columns,
 3435                }),
 3436                cx,
 3437            )
 3438        });
 3439    }
 3440
 3441    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3442        self.hide_context_menu(window, cx);
 3443
 3444        match phase {
 3445            SelectPhase::Begin {
 3446                position,
 3447                add,
 3448                click_count,
 3449            } => self.begin_selection(position, add, click_count, window, cx),
 3450            SelectPhase::BeginColumnar {
 3451                position,
 3452                goal_column,
 3453                reset,
 3454                mode,
 3455            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3456            SelectPhase::Extend {
 3457                position,
 3458                click_count,
 3459            } => self.extend_selection(position, click_count, window, cx),
 3460            SelectPhase::Update {
 3461                position,
 3462                goal_column,
 3463                scroll_delta,
 3464            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3465            SelectPhase::End => self.end_selection(window, cx),
 3466        }
 3467    }
 3468
 3469    fn extend_selection(
 3470        &mut self,
 3471        position: DisplayPoint,
 3472        click_count: usize,
 3473        window: &mut Window,
 3474        cx: &mut Context<Self>,
 3475    ) {
 3476        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3477        let tail = self.selections.newest::<usize>(&display_map).tail();
 3478        let click_count = click_count.max(match self.selections.select_mode() {
 3479            SelectMode::Character => 1,
 3480            SelectMode::Word(_) => 2,
 3481            SelectMode::Line(_) => 3,
 3482            SelectMode::All => 4,
 3483        });
 3484        self.begin_selection(position, false, click_count, window, cx);
 3485
 3486        let tail_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3487
 3488        let current_selection = match self.selections.select_mode() {
 3489            SelectMode::Character | SelectMode::All => tail_anchor..tail_anchor,
 3490            SelectMode::Word(range) | SelectMode::Line(range) => range.clone(),
 3491        };
 3492
 3493        let mut pending_selection = self
 3494            .selections
 3495            .pending_anchor()
 3496            .cloned()
 3497            .expect("extend_selection not called with pending selection");
 3498
 3499        if pending_selection
 3500            .start
 3501            .cmp(&current_selection.start, display_map.buffer_snapshot())
 3502            == Ordering::Greater
 3503        {
 3504            pending_selection.start = current_selection.start;
 3505        }
 3506        if pending_selection
 3507            .end
 3508            .cmp(&current_selection.end, display_map.buffer_snapshot())
 3509            == Ordering::Less
 3510        {
 3511            pending_selection.end = current_selection.end;
 3512            pending_selection.reversed = true;
 3513        }
 3514
 3515        let mut pending_mode = self.selections.pending_mode().unwrap();
 3516        match &mut pending_mode {
 3517            SelectMode::Word(range) | SelectMode::Line(range) => *range = current_selection,
 3518            _ => {}
 3519        }
 3520
 3521        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3522            SelectionEffects::scroll(Autoscroll::fit())
 3523        } else {
 3524            SelectionEffects::no_scroll()
 3525        };
 3526
 3527        self.change_selections(effects, window, cx, |s| {
 3528            s.set_pending(pending_selection.clone(), pending_mode);
 3529            s.set_is_extending(true);
 3530        });
 3531    }
 3532
 3533    fn begin_selection(
 3534        &mut self,
 3535        position: DisplayPoint,
 3536        add: bool,
 3537        click_count: usize,
 3538        window: &mut Window,
 3539        cx: &mut Context<Self>,
 3540    ) {
 3541        if !self.focus_handle.is_focused(window) {
 3542            self.last_focused_descendant = None;
 3543            window.focus(&self.focus_handle);
 3544        }
 3545
 3546        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3547        let buffer = display_map.buffer_snapshot();
 3548        let position = display_map.clip_point(position, Bias::Left);
 3549
 3550        let start;
 3551        let end;
 3552        let mode;
 3553        let mut auto_scroll;
 3554        match click_count {
 3555            1 => {
 3556                start = buffer.anchor_before(position.to_point(&display_map));
 3557                end = start;
 3558                mode = SelectMode::Character;
 3559                auto_scroll = true;
 3560            }
 3561            2 => {
 3562                let position = display_map
 3563                    .clip_point(position, Bias::Left)
 3564                    .to_offset(&display_map, Bias::Left);
 3565                let (range, _) = buffer.surrounding_word(position, None);
 3566                start = buffer.anchor_before(range.start);
 3567                end = buffer.anchor_before(range.end);
 3568                mode = SelectMode::Word(start..end);
 3569                auto_scroll = true;
 3570            }
 3571            3 => {
 3572                let position = display_map
 3573                    .clip_point(position, Bias::Left)
 3574                    .to_point(&display_map);
 3575                let line_start = display_map.prev_line_boundary(position).0;
 3576                let next_line_start = buffer.clip_point(
 3577                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3578                    Bias::Left,
 3579                );
 3580                start = buffer.anchor_before(line_start);
 3581                end = buffer.anchor_before(next_line_start);
 3582                mode = SelectMode::Line(start..end);
 3583                auto_scroll = true;
 3584            }
 3585            _ => {
 3586                start = buffer.anchor_before(0);
 3587                end = buffer.anchor_before(buffer.len());
 3588                mode = SelectMode::All;
 3589                auto_scroll = false;
 3590            }
 3591        }
 3592        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3593
 3594        let point_to_delete: Option<usize> = {
 3595            let selected_points: Vec<Selection<Point>> =
 3596                self.selections.disjoint_in_range(start..end, &display_map);
 3597
 3598            if !add || click_count > 1 {
 3599                None
 3600            } else if !selected_points.is_empty() {
 3601                Some(selected_points[0].id)
 3602            } else {
 3603                let clicked_point_already_selected =
 3604                    self.selections.disjoint_anchors().iter().find(|selection| {
 3605                        selection.start.to_point(buffer) == start.to_point(buffer)
 3606                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3607                    });
 3608
 3609                clicked_point_already_selected.map(|selection| selection.id)
 3610            }
 3611        };
 3612
 3613        let selections_count = self.selections.count();
 3614        let effects = if auto_scroll {
 3615            SelectionEffects::default()
 3616        } else {
 3617            SelectionEffects::no_scroll()
 3618        };
 3619
 3620        self.change_selections(effects, window, cx, |s| {
 3621            if let Some(point_to_delete) = point_to_delete {
 3622                s.delete(point_to_delete);
 3623
 3624                if selections_count == 1 {
 3625                    s.set_pending_anchor_range(start..end, mode);
 3626                }
 3627            } else {
 3628                if !add {
 3629                    s.clear_disjoint();
 3630                }
 3631
 3632                s.set_pending_anchor_range(start..end, mode);
 3633            }
 3634        });
 3635    }
 3636
 3637    fn begin_columnar_selection(
 3638        &mut self,
 3639        position: DisplayPoint,
 3640        goal_column: u32,
 3641        reset: bool,
 3642        mode: ColumnarMode,
 3643        window: &mut Window,
 3644        cx: &mut Context<Self>,
 3645    ) {
 3646        if !self.focus_handle.is_focused(window) {
 3647            self.last_focused_descendant = None;
 3648            window.focus(&self.focus_handle);
 3649        }
 3650
 3651        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3652
 3653        if reset {
 3654            let pointer_position = display_map
 3655                .buffer_snapshot()
 3656                .anchor_before(position.to_point(&display_map));
 3657
 3658            self.change_selections(
 3659                SelectionEffects::scroll(Autoscroll::newest()),
 3660                window,
 3661                cx,
 3662                |s| {
 3663                    s.clear_disjoint();
 3664                    s.set_pending_anchor_range(
 3665                        pointer_position..pointer_position,
 3666                        SelectMode::Character,
 3667                    );
 3668                },
 3669            );
 3670        };
 3671
 3672        let tail = self.selections.newest::<Point>(&display_map).tail();
 3673        let selection_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3674        self.columnar_selection_state = match mode {
 3675            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3676                selection_tail: selection_anchor,
 3677                display_point: if reset {
 3678                    if position.column() != goal_column {
 3679                        Some(DisplayPoint::new(position.row(), goal_column))
 3680                    } else {
 3681                        None
 3682                    }
 3683                } else {
 3684                    None
 3685                },
 3686            }),
 3687            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3688                selection_tail: selection_anchor,
 3689            }),
 3690        };
 3691
 3692        if !reset {
 3693            self.select_columns(position, goal_column, &display_map, window, cx);
 3694        }
 3695    }
 3696
 3697    fn update_selection(
 3698        &mut self,
 3699        position: DisplayPoint,
 3700        goal_column: u32,
 3701        scroll_delta: gpui::Point<f32>,
 3702        window: &mut Window,
 3703        cx: &mut Context<Self>,
 3704    ) {
 3705        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3706
 3707        if self.columnar_selection_state.is_some() {
 3708            self.select_columns(position, goal_column, &display_map, window, cx);
 3709        } else if let Some(mut pending) = self.selections.pending_anchor().cloned() {
 3710            let buffer = display_map.buffer_snapshot();
 3711            let head;
 3712            let tail;
 3713            let mode = self.selections.pending_mode().unwrap();
 3714            match &mode {
 3715                SelectMode::Character => {
 3716                    head = position.to_point(&display_map);
 3717                    tail = pending.tail().to_point(buffer);
 3718                }
 3719                SelectMode::Word(original_range) => {
 3720                    let offset = display_map
 3721                        .clip_point(position, Bias::Left)
 3722                        .to_offset(&display_map, Bias::Left);
 3723                    let original_range = original_range.to_offset(buffer);
 3724
 3725                    let head_offset = if buffer.is_inside_word(offset, None)
 3726                        || original_range.contains(&offset)
 3727                    {
 3728                        let (word_range, _) = buffer.surrounding_word(offset, None);
 3729                        if word_range.start < original_range.start {
 3730                            word_range.start
 3731                        } else {
 3732                            word_range.end
 3733                        }
 3734                    } else {
 3735                        offset
 3736                    };
 3737
 3738                    head = head_offset.to_point(buffer);
 3739                    if head_offset <= original_range.start {
 3740                        tail = original_range.end.to_point(buffer);
 3741                    } else {
 3742                        tail = original_range.start.to_point(buffer);
 3743                    }
 3744                }
 3745                SelectMode::Line(original_range) => {
 3746                    let original_range = original_range.to_point(display_map.buffer_snapshot());
 3747
 3748                    let position = display_map
 3749                        .clip_point(position, Bias::Left)
 3750                        .to_point(&display_map);
 3751                    let line_start = display_map.prev_line_boundary(position).0;
 3752                    let next_line_start = buffer.clip_point(
 3753                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3754                        Bias::Left,
 3755                    );
 3756
 3757                    if line_start < original_range.start {
 3758                        head = line_start
 3759                    } else {
 3760                        head = next_line_start
 3761                    }
 3762
 3763                    if head <= original_range.start {
 3764                        tail = original_range.end;
 3765                    } else {
 3766                        tail = original_range.start;
 3767                    }
 3768                }
 3769                SelectMode::All => {
 3770                    return;
 3771                }
 3772            };
 3773
 3774            if head < tail {
 3775                pending.start = buffer.anchor_before(head);
 3776                pending.end = buffer.anchor_before(tail);
 3777                pending.reversed = true;
 3778            } else {
 3779                pending.start = buffer.anchor_before(tail);
 3780                pending.end = buffer.anchor_before(head);
 3781                pending.reversed = false;
 3782            }
 3783
 3784            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3785                s.set_pending(pending.clone(), mode);
 3786            });
 3787        } else {
 3788            log::error!("update_selection dispatched with no pending selection");
 3789            return;
 3790        }
 3791
 3792        self.apply_scroll_delta(scroll_delta, window, cx);
 3793        cx.notify();
 3794    }
 3795
 3796    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3797        self.columnar_selection_state.take();
 3798        if let Some(pending_mode) = self.selections.pending_mode() {
 3799            let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 3800            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3801                s.select(selections);
 3802                s.clear_pending();
 3803                if s.is_extending() {
 3804                    s.set_is_extending(false);
 3805                } else {
 3806                    s.set_select_mode(pending_mode);
 3807                }
 3808            });
 3809        }
 3810    }
 3811
 3812    fn select_columns(
 3813        &mut self,
 3814        head: DisplayPoint,
 3815        goal_column: u32,
 3816        display_map: &DisplaySnapshot,
 3817        window: &mut Window,
 3818        cx: &mut Context<Self>,
 3819    ) {
 3820        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 3821            return;
 3822        };
 3823
 3824        let tail = match columnar_state {
 3825            ColumnarSelectionState::FromMouse {
 3826                selection_tail,
 3827                display_point,
 3828            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(display_map)),
 3829            ColumnarSelectionState::FromSelection { selection_tail } => {
 3830                selection_tail.to_display_point(display_map)
 3831            }
 3832        };
 3833
 3834        let start_row = cmp::min(tail.row(), head.row());
 3835        let end_row = cmp::max(tail.row(), head.row());
 3836        let start_column = cmp::min(tail.column(), goal_column);
 3837        let end_column = cmp::max(tail.column(), goal_column);
 3838        let reversed = start_column < tail.column();
 3839
 3840        let selection_ranges = (start_row.0..=end_row.0)
 3841            .map(DisplayRow)
 3842            .filter_map(|row| {
 3843                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 3844                    || start_column <= display_map.line_len(row))
 3845                    && !display_map.is_block_line(row)
 3846                {
 3847                    let start = display_map
 3848                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3849                        .to_point(display_map);
 3850                    let end = display_map
 3851                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3852                        .to_point(display_map);
 3853                    if reversed {
 3854                        Some(end..start)
 3855                    } else {
 3856                        Some(start..end)
 3857                    }
 3858                } else {
 3859                    None
 3860                }
 3861            })
 3862            .collect::<Vec<_>>();
 3863        if selection_ranges.is_empty() {
 3864            return;
 3865        }
 3866
 3867        let ranges = match columnar_state {
 3868            ColumnarSelectionState::FromMouse { .. } => {
 3869                let mut non_empty_ranges = selection_ranges
 3870                    .iter()
 3871                    .filter(|selection_range| selection_range.start != selection_range.end)
 3872                    .peekable();
 3873                if non_empty_ranges.peek().is_some() {
 3874                    non_empty_ranges.cloned().collect()
 3875                } else {
 3876                    selection_ranges
 3877                }
 3878            }
 3879            _ => selection_ranges,
 3880        };
 3881
 3882        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3883            s.select_ranges(ranges);
 3884        });
 3885        cx.notify();
 3886    }
 3887
 3888    pub fn has_non_empty_selection(&self, snapshot: &DisplaySnapshot) -> bool {
 3889        self.selections
 3890            .all_adjusted(snapshot)
 3891            .iter()
 3892            .any(|selection| !selection.is_empty())
 3893    }
 3894
 3895    pub fn has_pending_nonempty_selection(&self) -> bool {
 3896        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3897            Some(Selection { start, end, .. }) => start != end,
 3898            None => false,
 3899        };
 3900
 3901        pending_nonempty_selection
 3902            || (self.columnar_selection_state.is_some()
 3903                && self.selections.disjoint_anchors().len() > 1)
 3904    }
 3905
 3906    pub fn has_pending_selection(&self) -> bool {
 3907        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 3908    }
 3909
 3910    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3911        self.selection_mark_mode = false;
 3912        self.selection_drag_state = SelectionDragState::None;
 3913
 3914        if self.clear_expanded_diff_hunks(cx) {
 3915            cx.notify();
 3916            return;
 3917        }
 3918        if self.dismiss_menus_and_popups(true, window, cx) {
 3919            return;
 3920        }
 3921
 3922        if self.mode.is_full()
 3923            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 3924        {
 3925            return;
 3926        }
 3927
 3928        cx.propagate();
 3929    }
 3930
 3931    pub fn dismiss_menus_and_popups(
 3932        &mut self,
 3933        is_user_requested: bool,
 3934        window: &mut Window,
 3935        cx: &mut Context<Self>,
 3936    ) -> bool {
 3937        if self.take_rename(false, window, cx).is_some() {
 3938            return true;
 3939        }
 3940
 3941        if self.hide_blame_popover(true, cx) {
 3942            return true;
 3943        }
 3944
 3945        if hide_hover(self, cx) {
 3946            return true;
 3947        }
 3948
 3949        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3950            return true;
 3951        }
 3952
 3953        if self.hide_context_menu(window, cx).is_some() {
 3954            return true;
 3955        }
 3956
 3957        if self.mouse_context_menu.take().is_some() {
 3958            return true;
 3959        }
 3960
 3961        if is_user_requested && self.discard_edit_prediction(true, cx) {
 3962            return true;
 3963        }
 3964
 3965        if self.snippet_stack.pop().is_some() {
 3966            return true;
 3967        }
 3968
 3969        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3970            self.dismiss_diagnostics(cx);
 3971            return true;
 3972        }
 3973
 3974        false
 3975    }
 3976
 3977    fn linked_editing_ranges_for(
 3978        &self,
 3979        selection: Range<text::Anchor>,
 3980        cx: &App,
 3981    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3982        if self.linked_edit_ranges.is_empty() {
 3983            return None;
 3984        }
 3985        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3986            selection.end.buffer_id.and_then(|end_buffer_id| {
 3987                if selection.start.buffer_id != Some(end_buffer_id) {
 3988                    return None;
 3989                }
 3990                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3991                let snapshot = buffer.read(cx).snapshot();
 3992                self.linked_edit_ranges
 3993                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3994                    .map(|ranges| (ranges, snapshot, buffer))
 3995            })?;
 3996        use text::ToOffset as TO;
 3997        // find offset from the start of current range to current cursor position
 3998        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 3999
 4000        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 4001        let start_difference = start_offset - start_byte_offset;
 4002        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 4003        let end_difference = end_offset - start_byte_offset;
 4004        // Current range has associated linked ranges.
 4005        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4006        for range in linked_ranges.iter() {
 4007            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 4008            let end_offset = start_offset + end_difference;
 4009            let start_offset = start_offset + start_difference;
 4010            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 4011                continue;
 4012            }
 4013            if self.selections.disjoint_anchor_ranges().any(|s| {
 4014                if s.start.buffer_id != selection.start.buffer_id
 4015                    || s.end.buffer_id != selection.end.buffer_id
 4016                {
 4017                    return false;
 4018                }
 4019                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 4020                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 4021            }) {
 4022                continue;
 4023            }
 4024            let start = buffer_snapshot.anchor_after(start_offset);
 4025            let end = buffer_snapshot.anchor_after(end_offset);
 4026            linked_edits
 4027                .entry(buffer.clone())
 4028                .or_default()
 4029                .push(start..end);
 4030        }
 4031        Some(linked_edits)
 4032    }
 4033
 4034    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4035        let text: Arc<str> = text.into();
 4036
 4037        if self.read_only(cx) {
 4038            return;
 4039        }
 4040
 4041        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4042
 4043        let selections = self.selections.all_adjusted(&self.display_snapshot(cx));
 4044        let mut bracket_inserted = false;
 4045        let mut edits = Vec::new();
 4046        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4047        let mut new_selections = Vec::with_capacity(selections.len());
 4048        let mut new_autoclose_regions = Vec::new();
 4049        let snapshot = self.buffer.read(cx).read(cx);
 4050        let mut clear_linked_edit_ranges = false;
 4051
 4052        for (selection, autoclose_region) in
 4053            self.selections_with_autoclose_regions(selections, &snapshot)
 4054        {
 4055            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 4056                // Determine if the inserted text matches the opening or closing
 4057                // bracket of any of this language's bracket pairs.
 4058                let mut bracket_pair = None;
 4059                let mut is_bracket_pair_start = false;
 4060                let mut is_bracket_pair_end = false;
 4061                if !text.is_empty() {
 4062                    let mut bracket_pair_matching_end = None;
 4063                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 4064                    //  and they are removing the character that triggered IME popup.
 4065                    for (pair, enabled) in scope.brackets() {
 4066                        if !pair.close && !pair.surround {
 4067                            continue;
 4068                        }
 4069
 4070                        if enabled && pair.start.ends_with(text.as_ref()) {
 4071                            let prefix_len = pair.start.len() - text.len();
 4072                            let preceding_text_matches_prefix = prefix_len == 0
 4073                                || (selection.start.column >= (prefix_len as u32)
 4074                                    && snapshot.contains_str_at(
 4075                                        Point::new(
 4076                                            selection.start.row,
 4077                                            selection.start.column - (prefix_len as u32),
 4078                                        ),
 4079                                        &pair.start[..prefix_len],
 4080                                    ));
 4081                            if preceding_text_matches_prefix {
 4082                                bracket_pair = Some(pair.clone());
 4083                                is_bracket_pair_start = true;
 4084                                break;
 4085                            }
 4086                        }
 4087                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 4088                        {
 4089                            // take first bracket pair matching end, but don't break in case a later bracket
 4090                            // pair matches start
 4091                            bracket_pair_matching_end = Some(pair.clone());
 4092                        }
 4093                    }
 4094                    if let Some(end) = bracket_pair_matching_end
 4095                        && bracket_pair.is_none()
 4096                    {
 4097                        bracket_pair = Some(end);
 4098                        is_bracket_pair_end = true;
 4099                    }
 4100                }
 4101
 4102                if let Some(bracket_pair) = bracket_pair {
 4103                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 4104                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 4105                    let auto_surround =
 4106                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 4107                    if selection.is_empty() {
 4108                        if is_bracket_pair_start {
 4109                            // If the inserted text is a suffix of an opening bracket and the
 4110                            // selection is preceded by the rest of the opening bracket, then
 4111                            // insert the closing bracket.
 4112                            let following_text_allows_autoclose = snapshot
 4113                                .chars_at(selection.start)
 4114                                .next()
 4115                                .is_none_or(|c| scope.should_autoclose_before(c));
 4116
 4117                            let preceding_text_allows_autoclose = selection.start.column == 0
 4118                                || snapshot
 4119                                    .reversed_chars_at(selection.start)
 4120                                    .next()
 4121                                    .is_none_or(|c| {
 4122                                        bracket_pair.start != bracket_pair.end
 4123                                            || !snapshot
 4124                                                .char_classifier_at(selection.start)
 4125                                                .is_word(c)
 4126                                    });
 4127
 4128                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4129                                && bracket_pair.start.len() == 1
 4130                            {
 4131                                let target = bracket_pair.start.chars().next().unwrap();
 4132                                let current_line_count = snapshot
 4133                                    .reversed_chars_at(selection.start)
 4134                                    .take_while(|&c| c != '\n')
 4135                                    .filter(|&c| c == target)
 4136                                    .count();
 4137                                current_line_count % 2 == 1
 4138                            } else {
 4139                                false
 4140                            };
 4141
 4142                            if autoclose
 4143                                && bracket_pair.close
 4144                                && following_text_allows_autoclose
 4145                                && preceding_text_allows_autoclose
 4146                                && !is_closing_quote
 4147                            {
 4148                                let anchor = snapshot.anchor_before(selection.end);
 4149                                new_selections.push((selection.map(|_| anchor), text.len()));
 4150                                new_autoclose_regions.push((
 4151                                    anchor,
 4152                                    text.len(),
 4153                                    selection.id,
 4154                                    bracket_pair.clone(),
 4155                                ));
 4156                                edits.push((
 4157                                    selection.range(),
 4158                                    format!("{}{}", text, bracket_pair.end).into(),
 4159                                ));
 4160                                bracket_inserted = true;
 4161                                continue;
 4162                            }
 4163                        }
 4164
 4165                        if let Some(region) = autoclose_region {
 4166                            // If the selection is followed by an auto-inserted closing bracket,
 4167                            // then don't insert that closing bracket again; just move the selection
 4168                            // past the closing bracket.
 4169                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4170                                && text.as_ref() == region.pair.end.as_str()
 4171                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4172                            if should_skip {
 4173                                let anchor = snapshot.anchor_after(selection.end);
 4174                                new_selections
 4175                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4176                                continue;
 4177                            }
 4178                        }
 4179
 4180                        let always_treat_brackets_as_autoclosed = snapshot
 4181                            .language_settings_at(selection.start, cx)
 4182                            .always_treat_brackets_as_autoclosed;
 4183                        if always_treat_brackets_as_autoclosed
 4184                            && is_bracket_pair_end
 4185                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4186                        {
 4187                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4188                            // and the inserted text is a closing bracket and the selection is followed
 4189                            // by the closing bracket then move the selection past the closing bracket.
 4190                            let anchor = snapshot.anchor_after(selection.end);
 4191                            new_selections.push((selection.map(|_| anchor), text.len()));
 4192                            continue;
 4193                        }
 4194                    }
 4195                    // If an opening bracket is 1 character long and is typed while
 4196                    // text is selected, then surround that text with the bracket pair.
 4197                    else if auto_surround
 4198                        && bracket_pair.surround
 4199                        && is_bracket_pair_start
 4200                        && bracket_pair.start.chars().count() == 1
 4201                    {
 4202                        edits.push((selection.start..selection.start, text.clone()));
 4203                        edits.push((
 4204                            selection.end..selection.end,
 4205                            bracket_pair.end.as_str().into(),
 4206                        ));
 4207                        bracket_inserted = true;
 4208                        new_selections.push((
 4209                            Selection {
 4210                                id: selection.id,
 4211                                start: snapshot.anchor_after(selection.start),
 4212                                end: snapshot.anchor_before(selection.end),
 4213                                reversed: selection.reversed,
 4214                                goal: selection.goal,
 4215                            },
 4216                            0,
 4217                        ));
 4218                        continue;
 4219                    }
 4220                }
 4221            }
 4222
 4223            if self.auto_replace_emoji_shortcode
 4224                && selection.is_empty()
 4225                && text.as_ref().ends_with(':')
 4226                && let Some(possible_emoji_short_code) =
 4227                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4228                && !possible_emoji_short_code.is_empty()
 4229                && let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code)
 4230            {
 4231                let emoji_shortcode_start = Point::new(
 4232                    selection.start.row,
 4233                    selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4234                );
 4235
 4236                // Remove shortcode from buffer
 4237                edits.push((
 4238                    emoji_shortcode_start..selection.start,
 4239                    "".to_string().into(),
 4240                ));
 4241                new_selections.push((
 4242                    Selection {
 4243                        id: selection.id,
 4244                        start: snapshot.anchor_after(emoji_shortcode_start),
 4245                        end: snapshot.anchor_before(selection.start),
 4246                        reversed: selection.reversed,
 4247                        goal: selection.goal,
 4248                    },
 4249                    0,
 4250                ));
 4251
 4252                // Insert emoji
 4253                let selection_start_anchor = snapshot.anchor_after(selection.start);
 4254                new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4255                edits.push((selection.start..selection.end, emoji.to_string().into()));
 4256
 4257                continue;
 4258            }
 4259
 4260            // If not handling any auto-close operation, then just replace the selected
 4261            // text with the given input and move the selection to the end of the
 4262            // newly inserted text.
 4263            let anchor = snapshot.anchor_after(selection.end);
 4264            if !self.linked_edit_ranges.is_empty() {
 4265                let start_anchor = snapshot.anchor_before(selection.start);
 4266
 4267                let is_word_char = text.chars().next().is_none_or(|char| {
 4268                    let classifier = snapshot
 4269                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4270                        .scope_context(Some(CharScopeContext::LinkedEdit));
 4271                    classifier.is_word(char)
 4272                });
 4273
 4274                if is_word_char {
 4275                    if let Some(ranges) = self
 4276                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4277                    {
 4278                        for (buffer, edits) in ranges {
 4279                            linked_edits
 4280                                .entry(buffer.clone())
 4281                                .or_default()
 4282                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4283                        }
 4284                    }
 4285                } else {
 4286                    clear_linked_edit_ranges = true;
 4287                }
 4288            }
 4289
 4290            new_selections.push((selection.map(|_| anchor), 0));
 4291            edits.push((selection.start..selection.end, text.clone()));
 4292        }
 4293
 4294        drop(snapshot);
 4295
 4296        self.transact(window, cx, |this, window, cx| {
 4297            if clear_linked_edit_ranges {
 4298                this.linked_edit_ranges.clear();
 4299            }
 4300            let initial_buffer_versions =
 4301                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4302
 4303            this.buffer.update(cx, |buffer, cx| {
 4304                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4305            });
 4306            for (buffer, edits) in linked_edits {
 4307                buffer.update(cx, |buffer, cx| {
 4308                    let snapshot = buffer.snapshot();
 4309                    let edits = edits
 4310                        .into_iter()
 4311                        .map(|(range, text)| {
 4312                            use text::ToPoint as TP;
 4313                            let end_point = TP::to_point(&range.end, &snapshot);
 4314                            let start_point = TP::to_point(&range.start, &snapshot);
 4315                            (start_point..end_point, text)
 4316                        })
 4317                        .sorted_by_key(|(range, _)| range.start);
 4318                    buffer.edit(edits, None, cx);
 4319                })
 4320            }
 4321            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4322            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4323            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4324            let new_selections =
 4325                resolve_selections_wrapping_blocks::<usize, _>(new_anchor_selections, &map)
 4326                    .zip(new_selection_deltas)
 4327                    .map(|(selection, delta)| Selection {
 4328                        id: selection.id,
 4329                        start: selection.start + delta,
 4330                        end: selection.end + delta,
 4331                        reversed: selection.reversed,
 4332                        goal: SelectionGoal::None,
 4333                    })
 4334                    .collect::<Vec<_>>();
 4335
 4336            let mut i = 0;
 4337            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4338                let position = position.to_offset(map.buffer_snapshot()) + delta;
 4339                let start = map.buffer_snapshot().anchor_before(position);
 4340                let end = map.buffer_snapshot().anchor_after(position);
 4341                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4342                    match existing_state
 4343                        .range
 4344                        .start
 4345                        .cmp(&start, map.buffer_snapshot())
 4346                    {
 4347                        Ordering::Less => i += 1,
 4348                        Ordering::Greater => break,
 4349                        Ordering::Equal => {
 4350                            match end.cmp(&existing_state.range.end, map.buffer_snapshot()) {
 4351                                Ordering::Less => i += 1,
 4352                                Ordering::Equal => break,
 4353                                Ordering::Greater => break,
 4354                            }
 4355                        }
 4356                    }
 4357                }
 4358                this.autoclose_regions.insert(
 4359                    i,
 4360                    AutocloseRegion {
 4361                        selection_id,
 4362                        range: start..end,
 4363                        pair,
 4364                    },
 4365                );
 4366            }
 4367
 4368            let had_active_edit_prediction = this.has_active_edit_prediction();
 4369            this.change_selections(
 4370                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4371                window,
 4372                cx,
 4373                |s| s.select(new_selections),
 4374            );
 4375
 4376            if !bracket_inserted
 4377                && let Some(on_type_format_task) =
 4378                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4379            {
 4380                on_type_format_task.detach_and_log_err(cx);
 4381            }
 4382
 4383            let editor_settings = EditorSettings::get_global(cx);
 4384            if bracket_inserted
 4385                && (editor_settings.auto_signature_help
 4386                    || editor_settings.show_signature_help_after_edits)
 4387            {
 4388                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4389            }
 4390
 4391            let trigger_in_words =
 4392                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 4393            if this.hard_wrap.is_some() {
 4394                let latest: Range<Point> = this.selections.newest(&map).range();
 4395                if latest.is_empty()
 4396                    && this
 4397                        .buffer()
 4398                        .read(cx)
 4399                        .snapshot(cx)
 4400                        .line_len(MultiBufferRow(latest.start.row))
 4401                        == latest.start.column
 4402                {
 4403                    this.rewrap_impl(
 4404                        RewrapOptions {
 4405                            override_language_settings: true,
 4406                            preserve_existing_whitespace: true,
 4407                        },
 4408                        cx,
 4409                    )
 4410                }
 4411            }
 4412            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4413            refresh_linked_ranges(this, window, cx);
 4414            this.refresh_edit_prediction(true, false, window, cx);
 4415            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4416        });
 4417    }
 4418
 4419    fn find_possible_emoji_shortcode_at_position(
 4420        snapshot: &MultiBufferSnapshot,
 4421        position: Point,
 4422    ) -> Option<String> {
 4423        let mut chars = Vec::new();
 4424        let mut found_colon = false;
 4425        for char in snapshot.reversed_chars_at(position).take(100) {
 4426            // Found a possible emoji shortcode in the middle of the buffer
 4427            if found_colon {
 4428                if char.is_whitespace() {
 4429                    chars.reverse();
 4430                    return Some(chars.iter().collect());
 4431                }
 4432                // If the previous character is not a whitespace, we are in the middle of a word
 4433                // and we only want to complete the shortcode if the word is made up of other emojis
 4434                let mut containing_word = String::new();
 4435                for ch in snapshot
 4436                    .reversed_chars_at(position)
 4437                    .skip(chars.len() + 1)
 4438                    .take(100)
 4439                {
 4440                    if ch.is_whitespace() {
 4441                        break;
 4442                    }
 4443                    containing_word.push(ch);
 4444                }
 4445                let containing_word = containing_word.chars().rev().collect::<String>();
 4446                if util::word_consists_of_emojis(containing_word.as_str()) {
 4447                    chars.reverse();
 4448                    return Some(chars.iter().collect());
 4449                }
 4450            }
 4451
 4452            if char.is_whitespace() || !char.is_ascii() {
 4453                return None;
 4454            }
 4455            if char == ':' {
 4456                found_colon = true;
 4457            } else {
 4458                chars.push(char);
 4459            }
 4460        }
 4461        // Found a possible emoji shortcode at the beginning of the buffer
 4462        chars.reverse();
 4463        Some(chars.iter().collect())
 4464    }
 4465
 4466    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4467        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4468        self.transact(window, cx, |this, window, cx| {
 4469            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4470                let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
 4471                let multi_buffer = this.buffer.read(cx);
 4472                let buffer = multi_buffer.snapshot(cx);
 4473                selections
 4474                    .iter()
 4475                    .map(|selection| {
 4476                        let start_point = selection.start.to_point(&buffer);
 4477                        let mut existing_indent =
 4478                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4479                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4480                        let start = selection.start;
 4481                        let end = selection.end;
 4482                        let selection_is_empty = start == end;
 4483                        let language_scope = buffer.language_scope_at(start);
 4484                        let (
 4485                            comment_delimiter,
 4486                            doc_delimiter,
 4487                            insert_extra_newline,
 4488                            indent_on_newline,
 4489                            indent_on_extra_newline,
 4490                        ) = if let Some(language) = &language_scope {
 4491                            let mut insert_extra_newline =
 4492                                insert_extra_newline_brackets(&buffer, start..end, language)
 4493                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4494
 4495                            // Comment extension on newline is allowed only for cursor selections
 4496                            let comment_delimiter = maybe!({
 4497                                if !selection_is_empty {
 4498                                    return None;
 4499                                }
 4500
 4501                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4502                                    return None;
 4503                                }
 4504
 4505                                let delimiters = language.line_comment_prefixes();
 4506                                let max_len_of_delimiter =
 4507                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4508                                let (snapshot, range) =
 4509                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4510
 4511                                let num_of_whitespaces = snapshot
 4512                                    .chars_for_range(range.clone())
 4513                                    .take_while(|c| c.is_whitespace())
 4514                                    .count();
 4515                                let comment_candidate = snapshot
 4516                                    .chars_for_range(range.clone())
 4517                                    .skip(num_of_whitespaces)
 4518                                    .take(max_len_of_delimiter)
 4519                                    .collect::<String>();
 4520                                let (delimiter, trimmed_len) = delimiters
 4521                                    .iter()
 4522                                    .filter_map(|delimiter| {
 4523                                        let prefix = delimiter.trim_end();
 4524                                        if comment_candidate.starts_with(prefix) {
 4525                                            Some((delimiter, prefix.len()))
 4526                                        } else {
 4527                                            None
 4528                                        }
 4529                                    })
 4530                                    .max_by_key(|(_, len)| *len)?;
 4531
 4532                                if let Some(BlockCommentConfig {
 4533                                    start: block_start, ..
 4534                                }) = language.block_comment()
 4535                                {
 4536                                    let block_start_trimmed = block_start.trim_end();
 4537                                    if block_start_trimmed.starts_with(delimiter.trim_end()) {
 4538                                        let line_content = snapshot
 4539                                            .chars_for_range(range)
 4540                                            .skip(num_of_whitespaces)
 4541                                            .take(block_start_trimmed.len())
 4542                                            .collect::<String>();
 4543
 4544                                        if line_content.starts_with(block_start_trimmed) {
 4545                                            return None;
 4546                                        }
 4547                                    }
 4548                                }
 4549
 4550                                let cursor_is_placed_after_comment_marker =
 4551                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4552                                if cursor_is_placed_after_comment_marker {
 4553                                    Some(delimiter.clone())
 4554                                } else {
 4555                                    None
 4556                                }
 4557                            });
 4558
 4559                            let mut indent_on_newline = IndentSize::spaces(0);
 4560                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4561
 4562                            let doc_delimiter = maybe!({
 4563                                if !selection_is_empty {
 4564                                    return None;
 4565                                }
 4566
 4567                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4568                                    return None;
 4569                                }
 4570
 4571                                let BlockCommentConfig {
 4572                                    start: start_tag,
 4573                                    end: end_tag,
 4574                                    prefix: delimiter,
 4575                                    tab_size: len,
 4576                                } = language.documentation_comment()?;
 4577                                let is_within_block_comment = buffer
 4578                                    .language_scope_at(start_point)
 4579                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4580                                if !is_within_block_comment {
 4581                                    return None;
 4582                                }
 4583
 4584                                let (snapshot, range) =
 4585                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4586
 4587                                let num_of_whitespaces = snapshot
 4588                                    .chars_for_range(range.clone())
 4589                                    .take_while(|c| c.is_whitespace())
 4590                                    .count();
 4591
 4592                                // 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.
 4593                                let column = start_point.column;
 4594                                let cursor_is_after_start_tag = {
 4595                                    let start_tag_len = start_tag.len();
 4596                                    let start_tag_line = snapshot
 4597                                        .chars_for_range(range.clone())
 4598                                        .skip(num_of_whitespaces)
 4599                                        .take(start_tag_len)
 4600                                        .collect::<String>();
 4601                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4602                                        num_of_whitespaces + start_tag_len <= column as usize
 4603                                    } else {
 4604                                        false
 4605                                    }
 4606                                };
 4607
 4608                                let cursor_is_after_delimiter = {
 4609                                    let delimiter_trim = delimiter.trim_end();
 4610                                    let delimiter_line = snapshot
 4611                                        .chars_for_range(range.clone())
 4612                                        .skip(num_of_whitespaces)
 4613                                        .take(delimiter_trim.len())
 4614                                        .collect::<String>();
 4615                                    if delimiter_line.starts_with(delimiter_trim) {
 4616                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4617                                    } else {
 4618                                        false
 4619                                    }
 4620                                };
 4621
 4622                                let cursor_is_before_end_tag_if_exists = {
 4623                                    let mut char_position = 0u32;
 4624                                    let mut end_tag_offset = None;
 4625
 4626                                    'outer: for chunk in snapshot.text_for_range(range) {
 4627                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4628                                            let chars_before_match =
 4629                                                chunk[..byte_pos].chars().count() as u32;
 4630                                            end_tag_offset =
 4631                                                Some(char_position + chars_before_match);
 4632                                            break 'outer;
 4633                                        }
 4634                                        char_position += chunk.chars().count() as u32;
 4635                                    }
 4636
 4637                                    if let Some(end_tag_offset) = end_tag_offset {
 4638                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4639                                        if cursor_is_after_start_tag {
 4640                                            if cursor_is_before_end_tag {
 4641                                                insert_extra_newline = true;
 4642                                            }
 4643                                            let cursor_is_at_start_of_end_tag =
 4644                                                column == end_tag_offset;
 4645                                            if cursor_is_at_start_of_end_tag {
 4646                                                indent_on_extra_newline.len = *len;
 4647                                            }
 4648                                        }
 4649                                        cursor_is_before_end_tag
 4650                                    } else {
 4651                                        true
 4652                                    }
 4653                                };
 4654
 4655                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4656                                    && cursor_is_before_end_tag_if_exists
 4657                                {
 4658                                    if cursor_is_after_start_tag {
 4659                                        indent_on_newline.len = *len;
 4660                                    }
 4661                                    Some(delimiter.clone())
 4662                                } else {
 4663                                    None
 4664                                }
 4665                            });
 4666
 4667                            (
 4668                                comment_delimiter,
 4669                                doc_delimiter,
 4670                                insert_extra_newline,
 4671                                indent_on_newline,
 4672                                indent_on_extra_newline,
 4673                            )
 4674                        } else {
 4675                            (
 4676                                None,
 4677                                None,
 4678                                false,
 4679                                IndentSize::default(),
 4680                                IndentSize::default(),
 4681                            )
 4682                        };
 4683
 4684                        let prevent_auto_indent = doc_delimiter.is_some();
 4685                        let delimiter = comment_delimiter.or(doc_delimiter);
 4686
 4687                        let capacity_for_delimiter =
 4688                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4689                        let mut new_text = String::with_capacity(
 4690                            1 + capacity_for_delimiter
 4691                                + existing_indent.len as usize
 4692                                + indent_on_newline.len as usize
 4693                                + indent_on_extra_newline.len as usize,
 4694                        );
 4695                        new_text.push('\n');
 4696                        new_text.extend(existing_indent.chars());
 4697                        new_text.extend(indent_on_newline.chars());
 4698
 4699                        if let Some(delimiter) = &delimiter {
 4700                            new_text.push_str(delimiter);
 4701                        }
 4702
 4703                        if insert_extra_newline {
 4704                            new_text.push('\n');
 4705                            new_text.extend(existing_indent.chars());
 4706                            new_text.extend(indent_on_extra_newline.chars());
 4707                        }
 4708
 4709                        let anchor = buffer.anchor_after(end);
 4710                        let new_selection = selection.map(|_| anchor);
 4711                        (
 4712                            ((start..end, new_text), prevent_auto_indent),
 4713                            (insert_extra_newline, new_selection),
 4714                        )
 4715                    })
 4716                    .unzip()
 4717            };
 4718
 4719            let mut auto_indent_edits = Vec::new();
 4720            let mut edits = Vec::new();
 4721            for (edit, prevent_auto_indent) in edits_with_flags {
 4722                if prevent_auto_indent {
 4723                    edits.push(edit);
 4724                } else {
 4725                    auto_indent_edits.push(edit);
 4726                }
 4727            }
 4728            if !edits.is_empty() {
 4729                this.edit(edits, cx);
 4730            }
 4731            if !auto_indent_edits.is_empty() {
 4732                this.edit_with_autoindent(auto_indent_edits, cx);
 4733            }
 4734
 4735            let buffer = this.buffer.read(cx).snapshot(cx);
 4736            let new_selections = selection_info
 4737                .into_iter()
 4738                .map(|(extra_newline_inserted, new_selection)| {
 4739                    let mut cursor = new_selection.end.to_point(&buffer);
 4740                    if extra_newline_inserted {
 4741                        cursor.row -= 1;
 4742                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4743                    }
 4744                    new_selection.map(|_| cursor)
 4745                })
 4746                .collect();
 4747
 4748            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 4749            this.refresh_edit_prediction(true, false, window, cx);
 4750        });
 4751    }
 4752
 4753    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4754        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4755
 4756        let buffer = self.buffer.read(cx);
 4757        let snapshot = buffer.snapshot(cx);
 4758
 4759        let mut edits = Vec::new();
 4760        let mut rows = Vec::new();
 4761
 4762        for (rows_inserted, selection) in self
 4763            .selections
 4764            .all_adjusted(&self.display_snapshot(cx))
 4765            .into_iter()
 4766            .enumerate()
 4767        {
 4768            let cursor = selection.head();
 4769            let row = cursor.row;
 4770
 4771            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4772
 4773            let newline = "\n".to_string();
 4774            edits.push((start_of_line..start_of_line, newline));
 4775
 4776            rows.push(row + rows_inserted as u32);
 4777        }
 4778
 4779        self.transact(window, cx, |editor, window, cx| {
 4780            editor.edit(edits, cx);
 4781
 4782            editor.change_selections(Default::default(), window, cx, |s| {
 4783                let mut index = 0;
 4784                s.move_cursors_with(|map, _, _| {
 4785                    let row = rows[index];
 4786                    index += 1;
 4787
 4788                    let point = Point::new(row, 0);
 4789                    let boundary = map.next_line_boundary(point).1;
 4790                    let clipped = map.clip_point(boundary, Bias::Left);
 4791
 4792                    (clipped, SelectionGoal::None)
 4793                });
 4794            });
 4795
 4796            let mut indent_edits = Vec::new();
 4797            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4798            for row in rows {
 4799                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4800                for (row, indent) in indents {
 4801                    if indent.len == 0 {
 4802                        continue;
 4803                    }
 4804
 4805                    let text = match indent.kind {
 4806                        IndentKind::Space => " ".repeat(indent.len as usize),
 4807                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4808                    };
 4809                    let point = Point::new(row.0, 0);
 4810                    indent_edits.push((point..point, text));
 4811                }
 4812            }
 4813            editor.edit(indent_edits, cx);
 4814        });
 4815    }
 4816
 4817    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4818        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4819
 4820        let buffer = self.buffer.read(cx);
 4821        let snapshot = buffer.snapshot(cx);
 4822
 4823        let mut edits = Vec::new();
 4824        let mut rows = Vec::new();
 4825        let mut rows_inserted = 0;
 4826
 4827        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
 4828            let cursor = selection.head();
 4829            let row = cursor.row;
 4830
 4831            let point = Point::new(row + 1, 0);
 4832            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4833
 4834            let newline = "\n".to_string();
 4835            edits.push((start_of_line..start_of_line, newline));
 4836
 4837            rows_inserted += 1;
 4838            rows.push(row + rows_inserted);
 4839        }
 4840
 4841        self.transact(window, cx, |editor, window, cx| {
 4842            editor.edit(edits, cx);
 4843
 4844            editor.change_selections(Default::default(), window, cx, |s| {
 4845                let mut index = 0;
 4846                s.move_cursors_with(|map, _, _| {
 4847                    let row = rows[index];
 4848                    index += 1;
 4849
 4850                    let point = Point::new(row, 0);
 4851                    let boundary = map.next_line_boundary(point).1;
 4852                    let clipped = map.clip_point(boundary, Bias::Left);
 4853
 4854                    (clipped, SelectionGoal::None)
 4855                });
 4856            });
 4857
 4858            let mut indent_edits = Vec::new();
 4859            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4860            for row in rows {
 4861                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4862                for (row, indent) in indents {
 4863                    if indent.len == 0 {
 4864                        continue;
 4865                    }
 4866
 4867                    let text = match indent.kind {
 4868                        IndentKind::Space => " ".repeat(indent.len as usize),
 4869                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4870                    };
 4871                    let point = Point::new(row.0, 0);
 4872                    indent_edits.push((point..point, text));
 4873                }
 4874            }
 4875            editor.edit(indent_edits, cx);
 4876        });
 4877    }
 4878
 4879    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4880        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4881            original_indent_columns: Vec::new(),
 4882        });
 4883        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4884    }
 4885
 4886    fn insert_with_autoindent_mode(
 4887        &mut self,
 4888        text: &str,
 4889        autoindent_mode: Option<AutoindentMode>,
 4890        window: &mut Window,
 4891        cx: &mut Context<Self>,
 4892    ) {
 4893        if self.read_only(cx) {
 4894            return;
 4895        }
 4896
 4897        let text: Arc<str> = text.into();
 4898        self.transact(window, cx, |this, window, cx| {
 4899            let old_selections = this.selections.all_adjusted(&this.display_snapshot(cx));
 4900            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4901                let anchors = {
 4902                    let snapshot = buffer.read(cx);
 4903                    old_selections
 4904                        .iter()
 4905                        .map(|s| {
 4906                            let anchor = snapshot.anchor_after(s.head());
 4907                            s.map(|_| anchor)
 4908                        })
 4909                        .collect::<Vec<_>>()
 4910                };
 4911                buffer.edit(
 4912                    old_selections
 4913                        .iter()
 4914                        .map(|s| (s.start..s.end, text.clone())),
 4915                    autoindent_mode,
 4916                    cx,
 4917                );
 4918                anchors
 4919            });
 4920
 4921            this.change_selections(Default::default(), window, cx, |s| {
 4922                s.select_anchors(selection_anchors);
 4923            });
 4924
 4925            cx.notify();
 4926        });
 4927    }
 4928
 4929    fn trigger_completion_on_input(
 4930        &mut self,
 4931        text: &str,
 4932        trigger_in_words: bool,
 4933        window: &mut Window,
 4934        cx: &mut Context<Self>,
 4935    ) {
 4936        let completions_source = self
 4937            .context_menu
 4938            .borrow()
 4939            .as_ref()
 4940            .and_then(|menu| match menu {
 4941                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 4942                CodeContextMenu::CodeActions(_) => None,
 4943            });
 4944
 4945        match completions_source {
 4946            Some(CompletionsMenuSource::Words { .. }) => {
 4947                self.open_or_update_completions_menu(
 4948                    Some(CompletionsMenuSource::Words {
 4949                        ignore_threshold: false,
 4950                    }),
 4951                    None,
 4952                    window,
 4953                    cx,
 4954                );
 4955            }
 4956            Some(CompletionsMenuSource::Normal)
 4957            | Some(CompletionsMenuSource::SnippetChoices)
 4958            | None
 4959                if self.is_completion_trigger(
 4960                    text,
 4961                    trigger_in_words,
 4962                    completions_source.is_some(),
 4963                    cx,
 4964                ) =>
 4965            {
 4966                self.show_completions(
 4967                    &ShowCompletions {
 4968                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4969                    },
 4970                    window,
 4971                    cx,
 4972                )
 4973            }
 4974            _ => {
 4975                self.hide_context_menu(window, cx);
 4976            }
 4977        }
 4978    }
 4979
 4980    fn is_completion_trigger(
 4981        &self,
 4982        text: &str,
 4983        trigger_in_words: bool,
 4984        menu_is_open: bool,
 4985        cx: &mut Context<Self>,
 4986    ) -> bool {
 4987        let position = self.selections.newest_anchor().head();
 4988        let Some(buffer) = self.buffer.read(cx).buffer_for_anchor(position, cx) else {
 4989            return false;
 4990        };
 4991
 4992        if let Some(completion_provider) = &self.completion_provider {
 4993            completion_provider.is_completion_trigger(
 4994                &buffer,
 4995                position.text_anchor,
 4996                text,
 4997                trigger_in_words,
 4998                menu_is_open,
 4999                cx,
 5000            )
 5001        } else {
 5002            false
 5003        }
 5004    }
 5005
 5006    /// If any empty selections is touching the start of its innermost containing autoclose
 5007    /// region, expand it to select the brackets.
 5008    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 5009        let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 5010        let buffer = self.buffer.read(cx).read(cx);
 5011        let new_selections = self
 5012            .selections_with_autoclose_regions(selections, &buffer)
 5013            .map(|(mut selection, region)| {
 5014                if !selection.is_empty() {
 5015                    return selection;
 5016                }
 5017
 5018                if let Some(region) = region {
 5019                    let mut range = region.range.to_offset(&buffer);
 5020                    if selection.start == range.start && range.start >= region.pair.start.len() {
 5021                        range.start -= region.pair.start.len();
 5022                        if buffer.contains_str_at(range.start, &region.pair.start)
 5023                            && buffer.contains_str_at(range.end, &region.pair.end)
 5024                        {
 5025                            range.end += region.pair.end.len();
 5026                            selection.start = range.start;
 5027                            selection.end = range.end;
 5028
 5029                            return selection;
 5030                        }
 5031                    }
 5032                }
 5033
 5034                let always_treat_brackets_as_autoclosed = buffer
 5035                    .language_settings_at(selection.start, cx)
 5036                    .always_treat_brackets_as_autoclosed;
 5037
 5038                if !always_treat_brackets_as_autoclosed {
 5039                    return selection;
 5040                }
 5041
 5042                if let Some(scope) = buffer.language_scope_at(selection.start) {
 5043                    for (pair, enabled) in scope.brackets() {
 5044                        if !enabled || !pair.close {
 5045                            continue;
 5046                        }
 5047
 5048                        if buffer.contains_str_at(selection.start, &pair.end) {
 5049                            let pair_start_len = pair.start.len();
 5050                            if buffer.contains_str_at(
 5051                                selection.start.saturating_sub(pair_start_len),
 5052                                &pair.start,
 5053                            ) {
 5054                                selection.start -= pair_start_len;
 5055                                selection.end += pair.end.len();
 5056
 5057                                return selection;
 5058                            }
 5059                        }
 5060                    }
 5061                }
 5062
 5063                selection
 5064            })
 5065            .collect();
 5066
 5067        drop(buffer);
 5068        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 5069            selections.select(new_selections)
 5070        });
 5071    }
 5072
 5073    /// Iterate the given selections, and for each one, find the smallest surrounding
 5074    /// autoclose region. This uses the ordering of the selections and the autoclose
 5075    /// regions to avoid repeated comparisons.
 5076    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 5077        &'a self,
 5078        selections: impl IntoIterator<Item = Selection<D>>,
 5079        buffer: &'a MultiBufferSnapshot,
 5080    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 5081        let mut i = 0;
 5082        let mut regions = self.autoclose_regions.as_slice();
 5083        selections.into_iter().map(move |selection| {
 5084            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 5085
 5086            let mut enclosing = None;
 5087            while let Some(pair_state) = regions.get(i) {
 5088                if pair_state.range.end.to_offset(buffer) < range.start {
 5089                    regions = &regions[i + 1..];
 5090                    i = 0;
 5091                } else if pair_state.range.start.to_offset(buffer) > range.end {
 5092                    break;
 5093                } else {
 5094                    if pair_state.selection_id == selection.id {
 5095                        enclosing = Some(pair_state);
 5096                    }
 5097                    i += 1;
 5098                }
 5099            }
 5100
 5101            (selection, enclosing)
 5102        })
 5103    }
 5104
 5105    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 5106    fn invalidate_autoclose_regions(
 5107        &mut self,
 5108        mut selections: &[Selection<Anchor>],
 5109        buffer: &MultiBufferSnapshot,
 5110    ) {
 5111        self.autoclose_regions.retain(|state| {
 5112            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 5113                return false;
 5114            }
 5115
 5116            let mut i = 0;
 5117            while let Some(selection) = selections.get(i) {
 5118                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 5119                    selections = &selections[1..];
 5120                    continue;
 5121                }
 5122                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 5123                    break;
 5124                }
 5125                if selection.id == state.selection_id {
 5126                    return true;
 5127                } else {
 5128                    i += 1;
 5129                }
 5130            }
 5131            false
 5132        });
 5133    }
 5134
 5135    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5136        let offset = position.to_offset(buffer);
 5137        let (word_range, kind) =
 5138            buffer.surrounding_word(offset, Some(CharScopeContext::Completion));
 5139        if offset > word_range.start && kind == Some(CharKind::Word) {
 5140            Some(
 5141                buffer
 5142                    .text_for_range(word_range.start..offset)
 5143                    .collect::<String>(),
 5144            )
 5145        } else {
 5146            None
 5147        }
 5148    }
 5149
 5150    pub fn visible_excerpts(
 5151        &self,
 5152        cx: &mut Context<Editor>,
 5153    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5154        let Some(project) = self.project() else {
 5155            return HashMap::default();
 5156        };
 5157        let project = project.read(cx);
 5158        let multi_buffer = self.buffer().read(cx);
 5159        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5160        let multi_buffer_visible_start = self
 5161            .scroll_manager
 5162            .anchor()
 5163            .anchor
 5164            .to_point(&multi_buffer_snapshot);
 5165        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5166            multi_buffer_visible_start
 5167                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5168            Bias::Left,
 5169        );
 5170        multi_buffer_snapshot
 5171            .range_to_buffer_ranges(multi_buffer_visible_start..multi_buffer_visible_end)
 5172            .into_iter()
 5173            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5174            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5175                let buffer_file = project::File::from_dyn(buffer.file())?;
 5176                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5177                let worktree_entry = buffer_worktree
 5178                    .read(cx)
 5179                    .entry_for_id(buffer_file.project_entry_id()?)?;
 5180                if worktree_entry.is_ignored {
 5181                    None
 5182                } else {
 5183                    Some((
 5184                        excerpt_id,
 5185                        (
 5186                            multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5187                            buffer.version().clone(),
 5188                            excerpt_visible_range,
 5189                        ),
 5190                    ))
 5191                }
 5192            })
 5193            .collect()
 5194    }
 5195
 5196    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5197        TextLayoutDetails {
 5198            text_system: window.text_system().clone(),
 5199            editor_style: self.style.clone().unwrap(),
 5200            rem_size: window.rem_size(),
 5201            scroll_anchor: self.scroll_manager.anchor(),
 5202            visible_rows: self.visible_line_count(),
 5203            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5204        }
 5205    }
 5206
 5207    fn trigger_on_type_formatting(
 5208        &self,
 5209        input: String,
 5210        window: &mut Window,
 5211        cx: &mut Context<Self>,
 5212    ) -> Option<Task<Result<()>>> {
 5213        if input.len() != 1 {
 5214            return None;
 5215        }
 5216
 5217        let project = self.project()?;
 5218        let position = self.selections.newest_anchor().head();
 5219        let (buffer, buffer_position) = self
 5220            .buffer
 5221            .read(cx)
 5222            .text_anchor_for_position(position, cx)?;
 5223
 5224        let settings = language_settings::language_settings(
 5225            buffer
 5226                .read(cx)
 5227                .language_at(buffer_position)
 5228                .map(|l| l.name()),
 5229            buffer.read(cx).file(),
 5230            cx,
 5231        );
 5232        if !settings.use_on_type_format {
 5233            return None;
 5234        }
 5235
 5236        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5237        // hence we do LSP request & edit on host side only — add formats to host's history.
 5238        let push_to_lsp_host_history = true;
 5239        // If this is not the host, append its history with new edits.
 5240        let push_to_client_history = project.read(cx).is_via_collab();
 5241
 5242        let on_type_formatting = project.update(cx, |project, cx| {
 5243            project.on_type_format(
 5244                buffer.clone(),
 5245                buffer_position,
 5246                input,
 5247                push_to_lsp_host_history,
 5248                cx,
 5249            )
 5250        });
 5251        Some(cx.spawn_in(window, async move |editor, cx| {
 5252            if let Some(transaction) = on_type_formatting.await? {
 5253                if push_to_client_history {
 5254                    buffer
 5255                        .update(cx, |buffer, _| {
 5256                            buffer.push_transaction(transaction, Instant::now());
 5257                            buffer.finalize_last_transaction();
 5258                        })
 5259                        .ok();
 5260                }
 5261                editor.update(cx, |editor, cx| {
 5262                    editor.refresh_document_highlights(cx);
 5263                })?;
 5264            }
 5265            Ok(())
 5266        }))
 5267    }
 5268
 5269    pub fn show_word_completions(
 5270        &mut self,
 5271        _: &ShowWordCompletions,
 5272        window: &mut Window,
 5273        cx: &mut Context<Self>,
 5274    ) {
 5275        self.open_or_update_completions_menu(
 5276            Some(CompletionsMenuSource::Words {
 5277                ignore_threshold: true,
 5278            }),
 5279            None,
 5280            window,
 5281            cx,
 5282        );
 5283    }
 5284
 5285    pub fn show_completions(
 5286        &mut self,
 5287        options: &ShowCompletions,
 5288        window: &mut Window,
 5289        cx: &mut Context<Self>,
 5290    ) {
 5291        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5292    }
 5293
 5294    fn open_or_update_completions_menu(
 5295        &mut self,
 5296        requested_source: Option<CompletionsMenuSource>,
 5297        trigger: Option<&str>,
 5298        window: &mut Window,
 5299        cx: &mut Context<Self>,
 5300    ) {
 5301        if self.pending_rename.is_some() {
 5302            return;
 5303        }
 5304
 5305        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5306
 5307        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5308        // inserted and selected. To handle that case, the start of the selection is used so that
 5309        // the menu starts with all choices.
 5310        let position = self
 5311            .selections
 5312            .newest_anchor()
 5313            .start
 5314            .bias_right(&multibuffer_snapshot);
 5315        if position.diff_base_anchor.is_some() {
 5316            return;
 5317        }
 5318        let buffer_position = multibuffer_snapshot.anchor_before(position);
 5319        let Some(buffer) = buffer_position
 5320            .buffer_id
 5321            .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
 5322        else {
 5323            return;
 5324        };
 5325        let buffer_snapshot = buffer.read(cx).snapshot();
 5326
 5327        let query: Option<Arc<String>> =
 5328            Self::completion_query(&multibuffer_snapshot, buffer_position)
 5329                .map(|query| query.into());
 5330
 5331        drop(multibuffer_snapshot);
 5332
 5333        // Hide the current completions menu when query is empty. Without this, cached
 5334        // completions from before the trigger char may be reused (#32774).
 5335        if query.is_none() {
 5336            let menu_is_open = matches!(
 5337                self.context_menu.borrow().as_ref(),
 5338                Some(CodeContextMenu::Completions(_))
 5339            );
 5340            if menu_is_open {
 5341                self.hide_context_menu(window, cx);
 5342            }
 5343        }
 5344
 5345        let mut ignore_word_threshold = false;
 5346        let provider = match requested_source {
 5347            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5348            Some(CompletionsMenuSource::Words { ignore_threshold }) => {
 5349                ignore_word_threshold = ignore_threshold;
 5350                None
 5351            }
 5352            Some(CompletionsMenuSource::SnippetChoices) => {
 5353                log::error!("bug: SnippetChoices requested_source is not handled");
 5354                None
 5355            }
 5356        };
 5357
 5358        let sort_completions = provider
 5359            .as_ref()
 5360            .is_some_and(|provider| provider.sort_completions());
 5361
 5362        let filter_completions = provider
 5363            .as_ref()
 5364            .is_none_or(|provider| provider.filter_completions());
 5365
 5366        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5367            if filter_completions {
 5368                menu.filter(query.clone(), provider.clone(), window, cx);
 5369            }
 5370            // When `is_incomplete` is false, no need to re-query completions when the current query
 5371            // is a suffix of the initial query.
 5372            if !menu.is_incomplete {
 5373                // If the new query is a suffix of the old query (typing more characters) and
 5374                // the previous result was complete, the existing completions can be filtered.
 5375                //
 5376                // Note that this is always true for snippet completions.
 5377                let query_matches = match (&menu.initial_query, &query) {
 5378                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5379                    (None, _) => true,
 5380                    _ => false,
 5381                };
 5382                if query_matches {
 5383                    let position_matches = if menu.initial_position == position {
 5384                        true
 5385                    } else {
 5386                        let snapshot = self.buffer.read(cx).read(cx);
 5387                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5388                    };
 5389                    if position_matches {
 5390                        return;
 5391                    }
 5392                }
 5393            }
 5394        };
 5395
 5396        let trigger_kind = match trigger {
 5397            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5398                CompletionTriggerKind::TRIGGER_CHARACTER
 5399            }
 5400            _ => CompletionTriggerKind::INVOKED,
 5401        };
 5402        let completion_context = CompletionContext {
 5403            trigger_character: trigger.and_then(|trigger| {
 5404                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5405                    Some(String::from(trigger))
 5406                } else {
 5407                    None
 5408                }
 5409            }),
 5410            trigger_kind,
 5411        };
 5412
 5413        let Anchor {
 5414            excerpt_id: buffer_excerpt_id,
 5415            text_anchor: buffer_position,
 5416            ..
 5417        } = buffer_position;
 5418
 5419        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5420            buffer_snapshot.surrounding_word(buffer_position, None)
 5421        {
 5422            let word_to_exclude = buffer_snapshot
 5423                .text_for_range(word_range.clone())
 5424                .collect::<String>();
 5425            (
 5426                buffer_snapshot.anchor_before(word_range.start)
 5427                    ..buffer_snapshot.anchor_after(buffer_position),
 5428                Some(word_to_exclude),
 5429            )
 5430        } else {
 5431            (buffer_position..buffer_position, None)
 5432        };
 5433
 5434        let language = buffer_snapshot
 5435            .language_at(buffer_position)
 5436            .map(|language| language.name());
 5437
 5438        let completion_settings = language_settings(language.clone(), buffer_snapshot.file(), cx)
 5439            .completions
 5440            .clone();
 5441
 5442        let show_completion_documentation = buffer_snapshot
 5443            .settings_at(buffer_position, cx)
 5444            .show_completion_documentation;
 5445
 5446        // The document can be large, so stay in reasonable bounds when searching for words,
 5447        // otherwise completion pop-up might be slow to appear.
 5448        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5449        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5450        let min_word_search = buffer_snapshot.clip_point(
 5451            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5452            Bias::Left,
 5453        );
 5454        let max_word_search = buffer_snapshot.clip_point(
 5455            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5456            Bias::Right,
 5457        );
 5458        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5459            ..buffer_snapshot.point_to_offset(max_word_search);
 5460
 5461        let skip_digits = query
 5462            .as_ref()
 5463            .is_none_or(|query| !query.chars().any(|c| c.is_digit(10)));
 5464
 5465        let omit_word_completions = !self.word_completions_enabled
 5466            || (!ignore_word_threshold
 5467                && match &query {
 5468                    Some(query) => query.chars().count() < completion_settings.words_min_length,
 5469                    None => completion_settings.words_min_length != 0,
 5470                });
 5471
 5472        let (mut words, provider_responses) = match &provider {
 5473            Some(provider) => {
 5474                let provider_responses = provider.completions(
 5475                    buffer_excerpt_id,
 5476                    &buffer,
 5477                    buffer_position,
 5478                    completion_context,
 5479                    window,
 5480                    cx,
 5481                );
 5482
 5483                let words = match (omit_word_completions, completion_settings.words) {
 5484                    (true, _) | (_, WordsCompletionMode::Disabled) => {
 5485                        Task::ready(BTreeMap::default())
 5486                    }
 5487                    (false, WordsCompletionMode::Enabled | WordsCompletionMode::Fallback) => cx
 5488                        .background_spawn(async move {
 5489                            buffer_snapshot.words_in_range(WordsQuery {
 5490                                fuzzy_contents: None,
 5491                                range: word_search_range,
 5492                                skip_digits,
 5493                            })
 5494                        }),
 5495                };
 5496
 5497                (words, provider_responses)
 5498            }
 5499            None => {
 5500                let words = if omit_word_completions {
 5501                    Task::ready(BTreeMap::default())
 5502                } else {
 5503                    cx.background_spawn(async move {
 5504                        buffer_snapshot.words_in_range(WordsQuery {
 5505                            fuzzy_contents: None,
 5506                            range: word_search_range,
 5507                            skip_digits,
 5508                        })
 5509                    })
 5510                };
 5511                (words, Task::ready(Ok(Vec::new())))
 5512            }
 5513        };
 5514
 5515        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5516
 5517        let id = post_inc(&mut self.next_completion_id);
 5518        let task = cx.spawn_in(window, async move |editor, cx| {
 5519            let Ok(()) = editor.update(cx, |this, _| {
 5520                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5521            }) else {
 5522                return;
 5523            };
 5524
 5525            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5526            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5527            let mut completions = Vec::new();
 5528            let mut is_incomplete = false;
 5529            let mut display_options: Option<CompletionDisplayOptions> = None;
 5530            if let Some(provider_responses) = provider_responses.await.log_err()
 5531                && !provider_responses.is_empty()
 5532            {
 5533                for response in provider_responses {
 5534                    completions.extend(response.completions);
 5535                    is_incomplete = is_incomplete || response.is_incomplete;
 5536                    match display_options.as_mut() {
 5537                        None => {
 5538                            display_options = Some(response.display_options);
 5539                        }
 5540                        Some(options) => options.merge(&response.display_options),
 5541                    }
 5542                }
 5543                if completion_settings.words == WordsCompletionMode::Fallback {
 5544                    words = Task::ready(BTreeMap::default());
 5545                }
 5546            }
 5547            let display_options = display_options.unwrap_or_default();
 5548
 5549            let mut words = words.await;
 5550            if let Some(word_to_exclude) = &word_to_exclude {
 5551                words.remove(word_to_exclude);
 5552            }
 5553            for lsp_completion in &completions {
 5554                words.remove(&lsp_completion.new_text);
 5555            }
 5556            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5557                replace_range: word_replace_range.clone(),
 5558                new_text: word.clone(),
 5559                label: CodeLabel::plain(word, None),
 5560                icon_path: None,
 5561                documentation: None,
 5562                source: CompletionSource::BufferWord {
 5563                    word_range,
 5564                    resolved: false,
 5565                },
 5566                insert_text_mode: Some(InsertTextMode::AS_IS),
 5567                confirm: None,
 5568            }));
 5569
 5570            let menu = if completions.is_empty() {
 5571                None
 5572            } else {
 5573                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5574                    let languages = editor
 5575                        .workspace
 5576                        .as_ref()
 5577                        .and_then(|(workspace, _)| workspace.upgrade())
 5578                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5579                    let menu = CompletionsMenu::new(
 5580                        id,
 5581                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5582                        sort_completions,
 5583                        show_completion_documentation,
 5584                        position,
 5585                        query.clone(),
 5586                        is_incomplete,
 5587                        buffer.clone(),
 5588                        completions.into(),
 5589                        display_options,
 5590                        snippet_sort_order,
 5591                        languages,
 5592                        language,
 5593                        cx,
 5594                    );
 5595
 5596                    let query = if filter_completions { query } else { None };
 5597                    let matches_task = if let Some(query) = query {
 5598                        menu.do_async_filtering(query, cx)
 5599                    } else {
 5600                        Task::ready(menu.unfiltered_matches())
 5601                    };
 5602                    (menu, matches_task)
 5603                }) else {
 5604                    return;
 5605                };
 5606
 5607                let matches = matches_task.await;
 5608
 5609                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5610                    // Newer menu already set, so exit.
 5611                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5612                        editor.context_menu.borrow().as_ref()
 5613                        && prev_menu.id > id
 5614                    {
 5615                        return;
 5616                    };
 5617
 5618                    // Only valid to take prev_menu because it the new menu is immediately set
 5619                    // below, or the menu is hidden.
 5620                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5621                        editor.context_menu.borrow_mut().take()
 5622                    {
 5623                        let position_matches =
 5624                            if prev_menu.initial_position == menu.initial_position {
 5625                                true
 5626                            } else {
 5627                                let snapshot = editor.buffer.read(cx).read(cx);
 5628                                prev_menu.initial_position.to_offset(&snapshot)
 5629                                    == menu.initial_position.to_offset(&snapshot)
 5630                            };
 5631                        if position_matches {
 5632                            // Preserve markdown cache before `set_filter_results` because it will
 5633                            // try to populate the documentation cache.
 5634                            menu.preserve_markdown_cache(prev_menu);
 5635                        }
 5636                    };
 5637
 5638                    menu.set_filter_results(matches, provider, window, cx);
 5639                }) else {
 5640                    return;
 5641                };
 5642
 5643                menu.visible().then_some(menu)
 5644            };
 5645
 5646            editor
 5647                .update_in(cx, |editor, window, cx| {
 5648                    if editor.focus_handle.is_focused(window)
 5649                        && let Some(menu) = menu
 5650                    {
 5651                        *editor.context_menu.borrow_mut() =
 5652                            Some(CodeContextMenu::Completions(menu));
 5653
 5654                        crate::hover_popover::hide_hover(editor, cx);
 5655                        if editor.show_edit_predictions_in_menu() {
 5656                            editor.update_visible_edit_prediction(window, cx);
 5657                        } else {
 5658                            editor.discard_edit_prediction(false, cx);
 5659                        }
 5660
 5661                        cx.notify();
 5662                        return;
 5663                    }
 5664
 5665                    if editor.completion_tasks.len() <= 1 {
 5666                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5667                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5668                        // If it was already hidden and we don't show edit predictions in the menu,
 5669                        // we should also show the edit prediction when available.
 5670                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5671                            editor.update_visible_edit_prediction(window, cx);
 5672                        }
 5673                    }
 5674                })
 5675                .ok();
 5676        });
 5677
 5678        self.completion_tasks.push((id, task));
 5679    }
 5680
 5681    #[cfg(feature = "test-support")]
 5682    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5683        let menu = self.context_menu.borrow();
 5684        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5685            let completions = menu.completions.borrow();
 5686            Some(completions.to_vec())
 5687        } else {
 5688            None
 5689        }
 5690    }
 5691
 5692    pub fn with_completions_menu_matching_id<R>(
 5693        &self,
 5694        id: CompletionId,
 5695        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5696    ) -> R {
 5697        let mut context_menu = self.context_menu.borrow_mut();
 5698        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5699            return f(None);
 5700        };
 5701        if completions_menu.id != id {
 5702            return f(None);
 5703        }
 5704        f(Some(completions_menu))
 5705    }
 5706
 5707    pub fn confirm_completion(
 5708        &mut self,
 5709        action: &ConfirmCompletion,
 5710        window: &mut Window,
 5711        cx: &mut Context<Self>,
 5712    ) -> Option<Task<Result<()>>> {
 5713        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5714        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5715    }
 5716
 5717    pub fn confirm_completion_insert(
 5718        &mut self,
 5719        _: &ConfirmCompletionInsert,
 5720        window: &mut Window,
 5721        cx: &mut Context<Self>,
 5722    ) -> Option<Task<Result<()>>> {
 5723        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5724        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5725    }
 5726
 5727    pub fn confirm_completion_replace(
 5728        &mut self,
 5729        _: &ConfirmCompletionReplace,
 5730        window: &mut Window,
 5731        cx: &mut Context<Self>,
 5732    ) -> Option<Task<Result<()>>> {
 5733        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5734        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5735    }
 5736
 5737    pub fn compose_completion(
 5738        &mut self,
 5739        action: &ComposeCompletion,
 5740        window: &mut Window,
 5741        cx: &mut Context<Self>,
 5742    ) -> Option<Task<Result<()>>> {
 5743        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5744        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5745    }
 5746
 5747    fn do_completion(
 5748        &mut self,
 5749        item_ix: Option<usize>,
 5750        intent: CompletionIntent,
 5751        window: &mut Window,
 5752        cx: &mut Context<Editor>,
 5753    ) -> Option<Task<Result<()>>> {
 5754        use language::ToOffset as _;
 5755
 5756        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5757        else {
 5758            return None;
 5759        };
 5760
 5761        let candidate_id = {
 5762            let entries = completions_menu.entries.borrow();
 5763            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5764            if self.show_edit_predictions_in_menu() {
 5765                self.discard_edit_prediction(true, cx);
 5766            }
 5767            mat.candidate_id
 5768        };
 5769
 5770        let completion = completions_menu
 5771            .completions
 5772            .borrow()
 5773            .get(candidate_id)?
 5774            .clone();
 5775        cx.stop_propagation();
 5776
 5777        let buffer_handle = completions_menu.buffer.clone();
 5778
 5779        let CompletionEdit {
 5780            new_text,
 5781            snippet,
 5782            replace_range,
 5783        } = process_completion_for_edit(
 5784            &completion,
 5785            intent,
 5786            &buffer_handle,
 5787            &completions_menu.initial_position.text_anchor,
 5788            cx,
 5789        );
 5790
 5791        let buffer = buffer_handle.read(cx);
 5792        let snapshot = self.buffer.read(cx).snapshot(cx);
 5793        let newest_anchor = self.selections.newest_anchor();
 5794        let replace_range_multibuffer = {
 5795            let mut excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5796            excerpt.map_range_from_buffer(replace_range.clone())
 5797        };
 5798        if snapshot.buffer_id_for_anchor(newest_anchor.head()) != Some(buffer.remote_id()) {
 5799            return None;
 5800        }
 5801
 5802        let old_text = buffer
 5803            .text_for_range(replace_range.clone())
 5804            .collect::<String>();
 5805        let lookbehind = newest_anchor
 5806            .start
 5807            .text_anchor
 5808            .to_offset(buffer)
 5809            .saturating_sub(replace_range.start);
 5810        let lookahead = replace_range
 5811            .end
 5812            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5813        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5814        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5815
 5816        let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 5817        let mut ranges = Vec::new();
 5818        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5819
 5820        for selection in &selections {
 5821            let range = if selection.id == newest_anchor.id {
 5822                replace_range_multibuffer.clone()
 5823            } else {
 5824                let mut range = selection.range();
 5825
 5826                // if prefix is present, don't duplicate it
 5827                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5828                    range.start = range.start.saturating_sub(lookbehind);
 5829
 5830                    // if suffix is also present, mimic the newest cursor and replace it
 5831                    if selection.id != newest_anchor.id
 5832                        && snapshot.contains_str_at(range.end, suffix)
 5833                    {
 5834                        range.end += lookahead;
 5835                    }
 5836                }
 5837                range
 5838            };
 5839
 5840            ranges.push(range.clone());
 5841
 5842            if !self.linked_edit_ranges.is_empty() {
 5843                let start_anchor = snapshot.anchor_before(range.start);
 5844                let end_anchor = snapshot.anchor_after(range.end);
 5845                if let Some(ranges) = self
 5846                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 5847                {
 5848                    for (buffer, edits) in ranges {
 5849                        linked_edits
 5850                            .entry(buffer.clone())
 5851                            .or_default()
 5852                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 5853                    }
 5854                }
 5855            }
 5856        }
 5857
 5858        let common_prefix_len = old_text
 5859            .chars()
 5860            .zip(new_text.chars())
 5861            .take_while(|(a, b)| a == b)
 5862            .map(|(a, _)| a.len_utf8())
 5863            .sum::<usize>();
 5864
 5865        cx.emit(EditorEvent::InputHandled {
 5866            utf16_range_to_replace: None,
 5867            text: new_text[common_prefix_len..].into(),
 5868        });
 5869
 5870        self.transact(window, cx, |editor, window, cx| {
 5871            if let Some(mut snippet) = snippet {
 5872                snippet.text = new_text.to_string();
 5873                editor
 5874                    .insert_snippet(&ranges, snippet, window, cx)
 5875                    .log_err();
 5876            } else {
 5877                editor.buffer.update(cx, |multi_buffer, cx| {
 5878                    let auto_indent = match completion.insert_text_mode {
 5879                        Some(InsertTextMode::AS_IS) => None,
 5880                        _ => editor.autoindent_mode.clone(),
 5881                    };
 5882                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 5883                    multi_buffer.edit(edits, auto_indent, cx);
 5884                });
 5885            }
 5886            for (buffer, edits) in linked_edits {
 5887                buffer.update(cx, |buffer, cx| {
 5888                    let snapshot = buffer.snapshot();
 5889                    let edits = edits
 5890                        .into_iter()
 5891                        .map(|(range, text)| {
 5892                            use text::ToPoint as TP;
 5893                            let end_point = TP::to_point(&range.end, &snapshot);
 5894                            let start_point = TP::to_point(&range.start, &snapshot);
 5895                            (start_point..end_point, text)
 5896                        })
 5897                        .sorted_by_key(|(range, _)| range.start);
 5898                    buffer.edit(edits, None, cx);
 5899                })
 5900            }
 5901
 5902            editor.refresh_edit_prediction(true, false, window, cx);
 5903        });
 5904        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors_arc(), &snapshot);
 5905
 5906        let show_new_completions_on_confirm = completion
 5907            .confirm
 5908            .as_ref()
 5909            .is_some_and(|confirm| confirm(intent, window, cx));
 5910        if show_new_completions_on_confirm {
 5911            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 5912        }
 5913
 5914        let provider = self.completion_provider.as_ref()?;
 5915        drop(completion);
 5916        let apply_edits = provider.apply_additional_edits_for_completion(
 5917            buffer_handle,
 5918            completions_menu.completions.clone(),
 5919            candidate_id,
 5920            true,
 5921            cx,
 5922        );
 5923
 5924        let editor_settings = EditorSettings::get_global(cx);
 5925        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 5926            // After the code completion is finished, users often want to know what signatures are needed.
 5927            // so we should automatically call signature_help
 5928            self.show_signature_help(&ShowSignatureHelp, window, cx);
 5929        }
 5930
 5931        Some(cx.foreground_executor().spawn(async move {
 5932            apply_edits.await?;
 5933            Ok(())
 5934        }))
 5935    }
 5936
 5937    pub fn toggle_code_actions(
 5938        &mut self,
 5939        action: &ToggleCodeActions,
 5940        window: &mut Window,
 5941        cx: &mut Context<Self>,
 5942    ) {
 5943        let quick_launch = action.quick_launch;
 5944        let mut context_menu = self.context_menu.borrow_mut();
 5945        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 5946            if code_actions.deployed_from == action.deployed_from {
 5947                // Toggle if we're selecting the same one
 5948                *context_menu = None;
 5949                cx.notify();
 5950                return;
 5951            } else {
 5952                // Otherwise, clear it and start a new one
 5953                *context_menu = None;
 5954                cx.notify();
 5955            }
 5956        }
 5957        drop(context_menu);
 5958        let snapshot = self.snapshot(window, cx);
 5959        let deployed_from = action.deployed_from.clone();
 5960        let action = action.clone();
 5961        self.completion_tasks.clear();
 5962        self.discard_edit_prediction(false, cx);
 5963
 5964        let multibuffer_point = match &action.deployed_from {
 5965            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 5966                DisplayPoint::new(*row, 0).to_point(&snapshot)
 5967            }
 5968            _ => self
 5969                .selections
 5970                .newest::<Point>(&snapshot.display_snapshot)
 5971                .head(),
 5972        };
 5973        let Some((buffer, buffer_row)) = snapshot
 5974            .buffer_snapshot()
 5975            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 5976            .and_then(|(buffer_snapshot, range)| {
 5977                self.buffer()
 5978                    .read(cx)
 5979                    .buffer(buffer_snapshot.remote_id())
 5980                    .map(|buffer| (buffer, range.start.row))
 5981            })
 5982        else {
 5983            return;
 5984        };
 5985        let buffer_id = buffer.read(cx).remote_id();
 5986        let tasks = self
 5987            .tasks
 5988            .get(&(buffer_id, buffer_row))
 5989            .map(|t| Arc::new(t.to_owned()));
 5990
 5991        if !self.focus_handle.is_focused(window) {
 5992            return;
 5993        }
 5994        let project = self.project.clone();
 5995
 5996        let code_actions_task = match deployed_from {
 5997            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 5998            _ => self.code_actions(buffer_row, window, cx),
 5999        };
 6000
 6001        let runnable_task = match deployed_from {
 6002            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6003            _ => {
 6004                let mut task_context_task = Task::ready(None);
 6005                if let Some(tasks) = &tasks
 6006                    && let Some(project) = project
 6007                {
 6008                    task_context_task =
 6009                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6010                }
 6011
 6012                cx.spawn_in(window, {
 6013                    let buffer = buffer.clone();
 6014                    async move |editor, cx| {
 6015                        let task_context = task_context_task.await;
 6016
 6017                        let resolved_tasks =
 6018                            tasks
 6019                                .zip(task_context.clone())
 6020                                .map(|(tasks, task_context)| ResolvedTasks {
 6021                                    templates: tasks.resolve(&task_context).collect(),
 6022                                    position: snapshot.buffer_snapshot().anchor_before(Point::new(
 6023                                        multibuffer_point.row,
 6024                                        tasks.column,
 6025                                    )),
 6026                                });
 6027                        let debug_scenarios = editor
 6028                            .update(cx, |editor, cx| {
 6029                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6030                            })?
 6031                            .await;
 6032                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6033                    }
 6034                })
 6035            }
 6036        };
 6037
 6038        cx.spawn_in(window, async move |editor, cx| {
 6039            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6040            let code_actions = code_actions_task.await;
 6041            let spawn_straight_away = quick_launch
 6042                && resolved_tasks
 6043                    .as_ref()
 6044                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6045                && code_actions
 6046                    .as_ref()
 6047                    .is_none_or(|actions| actions.is_empty())
 6048                && debug_scenarios.is_empty();
 6049
 6050            editor.update_in(cx, |editor, window, cx| {
 6051                crate::hover_popover::hide_hover(editor, cx);
 6052                let actions = CodeActionContents::new(
 6053                    resolved_tasks,
 6054                    code_actions,
 6055                    debug_scenarios,
 6056                    task_context.unwrap_or_default(),
 6057                );
 6058
 6059                // Don't show the menu if there are no actions available
 6060                if actions.is_empty() {
 6061                    cx.notify();
 6062                    return Task::ready(Ok(()));
 6063                }
 6064
 6065                *editor.context_menu.borrow_mut() =
 6066                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6067                        buffer,
 6068                        actions,
 6069                        selected_item: Default::default(),
 6070                        scroll_handle: UniformListScrollHandle::default(),
 6071                        deployed_from,
 6072                    }));
 6073                cx.notify();
 6074                if spawn_straight_away
 6075                    && let Some(task) = editor.confirm_code_action(
 6076                        &ConfirmCodeAction { item_ix: Some(0) },
 6077                        window,
 6078                        cx,
 6079                    )
 6080                {
 6081                    return task;
 6082                }
 6083
 6084                Task::ready(Ok(()))
 6085            })
 6086        })
 6087        .detach_and_log_err(cx);
 6088    }
 6089
 6090    fn debug_scenarios(
 6091        &mut self,
 6092        resolved_tasks: &Option<ResolvedTasks>,
 6093        buffer: &Entity<Buffer>,
 6094        cx: &mut App,
 6095    ) -> Task<Vec<task::DebugScenario>> {
 6096        maybe!({
 6097            let project = self.project()?;
 6098            let dap_store = project.read(cx).dap_store();
 6099            let mut scenarios = vec![];
 6100            let resolved_tasks = resolved_tasks.as_ref()?;
 6101            let buffer = buffer.read(cx);
 6102            let language = buffer.language()?;
 6103            let file = buffer.file();
 6104            let debug_adapter = language_settings(language.name().into(), file, cx)
 6105                .debuggers
 6106                .first()
 6107                .map(SharedString::from)
 6108                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6109
 6110            dap_store.update(cx, |dap_store, cx| {
 6111                for (_, task) in &resolved_tasks.templates {
 6112                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6113                        task.original_task().clone(),
 6114                        debug_adapter.clone().into(),
 6115                        task.display_label().to_owned().into(),
 6116                        cx,
 6117                    );
 6118                    scenarios.push(maybe_scenario);
 6119                }
 6120            });
 6121            Some(cx.background_spawn(async move {
 6122                futures::future::join_all(scenarios)
 6123                    .await
 6124                    .into_iter()
 6125                    .flatten()
 6126                    .collect::<Vec<_>>()
 6127            }))
 6128        })
 6129        .unwrap_or_else(|| Task::ready(vec![]))
 6130    }
 6131
 6132    fn code_actions(
 6133        &mut self,
 6134        buffer_row: u32,
 6135        window: &mut Window,
 6136        cx: &mut Context<Self>,
 6137    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6138        let mut task = self.code_actions_task.take();
 6139        cx.spawn_in(window, async move |editor, cx| {
 6140            while let Some(prev_task) = task {
 6141                prev_task.await.log_err();
 6142                task = editor
 6143                    .update(cx, |this, _| this.code_actions_task.take())
 6144                    .ok()?;
 6145            }
 6146
 6147            editor
 6148                .update(cx, |editor, cx| {
 6149                    editor
 6150                        .available_code_actions
 6151                        .clone()
 6152                        .and_then(|(location, code_actions)| {
 6153                            let snapshot = location.buffer.read(cx).snapshot();
 6154                            let point_range = location.range.to_point(&snapshot);
 6155                            let point_range = point_range.start.row..=point_range.end.row;
 6156                            if point_range.contains(&buffer_row) {
 6157                                Some(code_actions)
 6158                            } else {
 6159                                None
 6160                            }
 6161                        })
 6162                })
 6163                .ok()
 6164                .flatten()
 6165        })
 6166    }
 6167
 6168    pub fn confirm_code_action(
 6169        &mut self,
 6170        action: &ConfirmCodeAction,
 6171        window: &mut Window,
 6172        cx: &mut Context<Self>,
 6173    ) -> Option<Task<Result<()>>> {
 6174        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6175
 6176        let actions_menu =
 6177            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6178                menu
 6179            } else {
 6180                return None;
 6181            };
 6182
 6183        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6184        let action = actions_menu.actions.get(action_ix)?;
 6185        let title = action.label();
 6186        let buffer = actions_menu.buffer;
 6187        let workspace = self.workspace()?;
 6188
 6189        match action {
 6190            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6191                workspace.update(cx, |workspace, cx| {
 6192                    workspace.schedule_resolved_task(
 6193                        task_source_kind,
 6194                        resolved_task,
 6195                        false,
 6196                        window,
 6197                        cx,
 6198                    );
 6199
 6200                    Some(Task::ready(Ok(())))
 6201                })
 6202            }
 6203            CodeActionsItem::CodeAction {
 6204                excerpt_id,
 6205                action,
 6206                provider,
 6207            } => {
 6208                let apply_code_action =
 6209                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6210                let workspace = workspace.downgrade();
 6211                Some(cx.spawn_in(window, async move |editor, cx| {
 6212                    let project_transaction = apply_code_action.await?;
 6213                    Self::open_project_transaction(
 6214                        &editor,
 6215                        workspace,
 6216                        project_transaction,
 6217                        title,
 6218                        cx,
 6219                    )
 6220                    .await
 6221                }))
 6222            }
 6223            CodeActionsItem::DebugScenario(scenario) => {
 6224                let context = actions_menu.actions.context;
 6225
 6226                workspace.update(cx, |workspace, cx| {
 6227                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6228                    workspace.start_debug_session(
 6229                        scenario,
 6230                        context,
 6231                        Some(buffer),
 6232                        None,
 6233                        window,
 6234                        cx,
 6235                    );
 6236                });
 6237                Some(Task::ready(Ok(())))
 6238            }
 6239        }
 6240    }
 6241
 6242    pub async fn open_project_transaction(
 6243        editor: &WeakEntity<Editor>,
 6244        workspace: WeakEntity<Workspace>,
 6245        transaction: ProjectTransaction,
 6246        title: String,
 6247        cx: &mut AsyncWindowContext,
 6248    ) -> Result<()> {
 6249        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6250        cx.update(|_, cx| {
 6251            entries.sort_unstable_by_key(|(buffer, _)| {
 6252                buffer.read(cx).file().map(|f| f.path().clone())
 6253            });
 6254        })?;
 6255        if entries.is_empty() {
 6256            return Ok(());
 6257        }
 6258
 6259        // If the project transaction's edits are all contained within this editor, then
 6260        // avoid opening a new editor to display them.
 6261
 6262        if let [(buffer, transaction)] = &*entries {
 6263            let excerpt = editor.update(cx, |editor, cx| {
 6264                editor
 6265                    .buffer()
 6266                    .read(cx)
 6267                    .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6268            })?;
 6269            if let Some((_, excerpted_buffer, excerpt_range)) = excerpt
 6270                && excerpted_buffer == *buffer
 6271            {
 6272                let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6273                    let excerpt_range = excerpt_range.to_offset(buffer);
 6274                    buffer
 6275                        .edited_ranges_for_transaction::<usize>(transaction)
 6276                        .all(|range| {
 6277                            excerpt_range.start <= range.start && excerpt_range.end >= range.end
 6278                        })
 6279                })?;
 6280
 6281                if all_edits_within_excerpt {
 6282                    return Ok(());
 6283                }
 6284            }
 6285        }
 6286
 6287        let mut ranges_to_highlight = Vec::new();
 6288        let excerpt_buffer = cx.new(|cx| {
 6289            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6290            for (buffer_handle, transaction) in &entries {
 6291                let edited_ranges = buffer_handle
 6292                    .read(cx)
 6293                    .edited_ranges_for_transaction::<Point>(transaction)
 6294                    .collect::<Vec<_>>();
 6295                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6296                    PathKey::for_buffer(buffer_handle, cx),
 6297                    buffer_handle.clone(),
 6298                    edited_ranges,
 6299                    multibuffer_context_lines(cx),
 6300                    cx,
 6301                );
 6302
 6303                ranges_to_highlight.extend(ranges);
 6304            }
 6305            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6306            multibuffer
 6307        })?;
 6308
 6309        workspace.update_in(cx, |workspace, window, cx| {
 6310            let project = workspace.project().clone();
 6311            let editor =
 6312                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6313            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6314            editor.update(cx, |editor, cx| {
 6315                editor.highlight_background::<Self>(
 6316                    &ranges_to_highlight,
 6317                    |theme| theme.colors().editor_highlighted_line_background,
 6318                    cx,
 6319                );
 6320            });
 6321        })?;
 6322
 6323        Ok(())
 6324    }
 6325
 6326    pub fn clear_code_action_providers(&mut self) {
 6327        self.code_action_providers.clear();
 6328        self.available_code_actions.take();
 6329    }
 6330
 6331    pub fn add_code_action_provider(
 6332        &mut self,
 6333        provider: Rc<dyn CodeActionProvider>,
 6334        window: &mut Window,
 6335        cx: &mut Context<Self>,
 6336    ) {
 6337        if self
 6338            .code_action_providers
 6339            .iter()
 6340            .any(|existing_provider| existing_provider.id() == provider.id())
 6341        {
 6342            return;
 6343        }
 6344
 6345        self.code_action_providers.push(provider);
 6346        self.refresh_code_actions(window, cx);
 6347    }
 6348
 6349    pub fn remove_code_action_provider(
 6350        &mut self,
 6351        id: Arc<str>,
 6352        window: &mut Window,
 6353        cx: &mut Context<Self>,
 6354    ) {
 6355        self.code_action_providers
 6356            .retain(|provider| provider.id() != id);
 6357        self.refresh_code_actions(window, cx);
 6358    }
 6359
 6360    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6361        !self.code_action_providers.is_empty()
 6362            && EditorSettings::get_global(cx).toolbar.code_actions
 6363    }
 6364
 6365    pub fn has_available_code_actions(&self) -> bool {
 6366        self.available_code_actions
 6367            .as_ref()
 6368            .is_some_and(|(_, actions)| !actions.is_empty())
 6369    }
 6370
 6371    fn render_inline_code_actions(
 6372        &self,
 6373        icon_size: ui::IconSize,
 6374        display_row: DisplayRow,
 6375        is_active: bool,
 6376        cx: &mut Context<Self>,
 6377    ) -> AnyElement {
 6378        let show_tooltip = !self.context_menu_visible();
 6379        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6380            .icon_size(icon_size)
 6381            .shape(ui::IconButtonShape::Square)
 6382            .icon_color(ui::Color::Hidden)
 6383            .toggle_state(is_active)
 6384            .when(show_tooltip, |this| {
 6385                this.tooltip({
 6386                    let focus_handle = self.focus_handle.clone();
 6387                    move |_window, cx| {
 6388                        Tooltip::for_action_in(
 6389                            "Toggle Code Actions",
 6390                            &ToggleCodeActions {
 6391                                deployed_from: None,
 6392                                quick_launch: false,
 6393                            },
 6394                            &focus_handle,
 6395                            cx,
 6396                        )
 6397                    }
 6398                })
 6399            })
 6400            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6401                window.focus(&editor.focus_handle(cx));
 6402                editor.toggle_code_actions(
 6403                    &crate::actions::ToggleCodeActions {
 6404                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6405                            display_row,
 6406                        )),
 6407                        quick_launch: false,
 6408                    },
 6409                    window,
 6410                    cx,
 6411                );
 6412            }))
 6413            .into_any_element()
 6414    }
 6415
 6416    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6417        &self.context_menu
 6418    }
 6419
 6420    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6421        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6422            cx.background_executor()
 6423                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6424                .await;
 6425
 6426            let (start_buffer, start, _, end, newest_selection) = this
 6427                .update(cx, |this, cx| {
 6428                    let newest_selection = this.selections.newest_anchor().clone();
 6429                    if newest_selection.head().diff_base_anchor.is_some() {
 6430                        return None;
 6431                    }
 6432                    let display_snapshot = this.display_snapshot(cx);
 6433                    let newest_selection_adjusted =
 6434                        this.selections.newest_adjusted(&display_snapshot);
 6435                    let buffer = this.buffer.read(cx);
 6436
 6437                    let (start_buffer, start) =
 6438                        buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6439                    let (end_buffer, end) =
 6440                        buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6441
 6442                    Some((start_buffer, start, end_buffer, end, newest_selection))
 6443                })?
 6444                .filter(|(start_buffer, _, end_buffer, _, _)| start_buffer == end_buffer)
 6445                .context(
 6446                    "Expected selection to lie in a single buffer when refreshing code actions",
 6447                )?;
 6448            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6449                let providers = this.code_action_providers.clone();
 6450                let tasks = this
 6451                    .code_action_providers
 6452                    .iter()
 6453                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6454                    .collect::<Vec<_>>();
 6455                (providers, tasks)
 6456            })?;
 6457
 6458            let mut actions = Vec::new();
 6459            for (provider, provider_actions) in
 6460                providers.into_iter().zip(future::join_all(tasks).await)
 6461            {
 6462                if let Some(provider_actions) = provider_actions.log_err() {
 6463                    actions.extend(provider_actions.into_iter().map(|action| {
 6464                        AvailableCodeAction {
 6465                            excerpt_id: newest_selection.start.excerpt_id,
 6466                            action,
 6467                            provider: provider.clone(),
 6468                        }
 6469                    }));
 6470                }
 6471            }
 6472
 6473            this.update(cx, |this, cx| {
 6474                this.available_code_actions = if actions.is_empty() {
 6475                    None
 6476                } else {
 6477                    Some((
 6478                        Location {
 6479                            buffer: start_buffer,
 6480                            range: start..end,
 6481                        },
 6482                        actions.into(),
 6483                    ))
 6484                };
 6485                cx.notify();
 6486            })
 6487        }));
 6488    }
 6489
 6490    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6491        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6492            self.show_git_blame_inline = false;
 6493
 6494            self.show_git_blame_inline_delay_task =
 6495                Some(cx.spawn_in(window, async move |this, cx| {
 6496                    cx.background_executor().timer(delay).await;
 6497
 6498                    this.update(cx, |this, cx| {
 6499                        this.show_git_blame_inline = true;
 6500                        cx.notify();
 6501                    })
 6502                    .log_err();
 6503                }));
 6504        }
 6505    }
 6506
 6507    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6508        let snapshot = self.snapshot(window, cx);
 6509        let cursor = self
 6510            .selections
 6511            .newest::<Point>(&snapshot.display_snapshot)
 6512            .head();
 6513        let Some((buffer, point, _)) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)
 6514        else {
 6515            return;
 6516        };
 6517
 6518        let Some(blame) = self.blame.as_ref() else {
 6519            return;
 6520        };
 6521
 6522        let row_info = RowInfo {
 6523            buffer_id: Some(buffer.remote_id()),
 6524            buffer_row: Some(point.row),
 6525            ..Default::default()
 6526        };
 6527        let Some((buffer, blame_entry)) = blame
 6528            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6529            .flatten()
 6530        else {
 6531            return;
 6532        };
 6533
 6534        let anchor = self.selections.newest_anchor().head();
 6535        let position = self.to_pixel_point(anchor, &snapshot, window);
 6536        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6537            self.show_blame_popover(
 6538                buffer,
 6539                &blame_entry,
 6540                position + last_bounds.origin,
 6541                true,
 6542                cx,
 6543            );
 6544        };
 6545    }
 6546
 6547    fn show_blame_popover(
 6548        &mut self,
 6549        buffer: BufferId,
 6550        blame_entry: &BlameEntry,
 6551        position: gpui::Point<Pixels>,
 6552        ignore_timeout: bool,
 6553        cx: &mut Context<Self>,
 6554    ) {
 6555        if let Some(state) = &mut self.inline_blame_popover {
 6556            state.hide_task.take();
 6557        } else {
 6558            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay.0;
 6559            let blame_entry = blame_entry.clone();
 6560            let show_task = cx.spawn(async move |editor, cx| {
 6561                if !ignore_timeout {
 6562                    cx.background_executor()
 6563                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6564                        .await;
 6565                }
 6566                editor
 6567                    .update(cx, |editor, cx| {
 6568                        editor.inline_blame_popover_show_task.take();
 6569                        let Some(blame) = editor.blame.as_ref() else {
 6570                            return;
 6571                        };
 6572                        let blame = blame.read(cx);
 6573                        let details = blame.details_for_entry(buffer, &blame_entry);
 6574                        let markdown = cx.new(|cx| {
 6575                            Markdown::new(
 6576                                details
 6577                                    .as_ref()
 6578                                    .map(|message| message.message.clone())
 6579                                    .unwrap_or_default(),
 6580                                None,
 6581                                None,
 6582                                cx,
 6583                            )
 6584                        });
 6585                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6586                            position,
 6587                            hide_task: None,
 6588                            popover_bounds: None,
 6589                            popover_state: InlineBlamePopoverState {
 6590                                scroll_handle: ScrollHandle::new(),
 6591                                commit_message: details,
 6592                                markdown,
 6593                            },
 6594                            keyboard_grace: ignore_timeout,
 6595                        });
 6596                        cx.notify();
 6597                    })
 6598                    .ok();
 6599            });
 6600            self.inline_blame_popover_show_task = Some(show_task);
 6601        }
 6602    }
 6603
 6604    fn hide_blame_popover(&mut self, ignore_timeout: bool, cx: &mut Context<Self>) -> bool {
 6605        self.inline_blame_popover_show_task.take();
 6606        if let Some(state) = &mut self.inline_blame_popover {
 6607            let hide_task = cx.spawn(async move |editor, cx| {
 6608                if !ignore_timeout {
 6609                    cx.background_executor()
 6610                        .timer(std::time::Duration::from_millis(100))
 6611                        .await;
 6612                }
 6613                editor
 6614                    .update(cx, |editor, cx| {
 6615                        editor.inline_blame_popover.take();
 6616                        cx.notify();
 6617                    })
 6618                    .ok();
 6619            });
 6620            state.hide_task = Some(hide_task);
 6621            true
 6622        } else {
 6623            false
 6624        }
 6625    }
 6626
 6627    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6628        if self.pending_rename.is_some() {
 6629            return None;
 6630        }
 6631
 6632        let provider = self.semantics_provider.clone()?;
 6633        let buffer = self.buffer.read(cx);
 6634        let newest_selection = self.selections.newest_anchor().clone();
 6635        let cursor_position = newest_selection.head();
 6636        let (cursor_buffer, cursor_buffer_position) =
 6637            buffer.text_anchor_for_position(cursor_position, cx)?;
 6638        let (tail_buffer, tail_buffer_position) =
 6639            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6640        if cursor_buffer != tail_buffer {
 6641            return None;
 6642        }
 6643
 6644        let snapshot = cursor_buffer.read(cx).snapshot();
 6645        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, None);
 6646        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, None);
 6647        if start_word_range != end_word_range {
 6648            self.document_highlights_task.take();
 6649            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6650            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6651            return None;
 6652        }
 6653
 6654        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce.0;
 6655        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6656            cx.background_executor()
 6657                .timer(Duration::from_millis(debounce))
 6658                .await;
 6659
 6660            let highlights = if let Some(highlights) = cx
 6661                .update(|cx| {
 6662                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6663                })
 6664                .ok()
 6665                .flatten()
 6666            {
 6667                highlights.await.log_err()
 6668            } else {
 6669                None
 6670            };
 6671
 6672            if let Some(highlights) = highlights {
 6673                this.update(cx, |this, cx| {
 6674                    if this.pending_rename.is_some() {
 6675                        return;
 6676                    }
 6677
 6678                    let buffer = this.buffer.read(cx);
 6679                    if buffer
 6680                        .text_anchor_for_position(cursor_position, cx)
 6681                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 6682                    {
 6683                        return;
 6684                    }
 6685
 6686                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6687                    let mut write_ranges = Vec::new();
 6688                    let mut read_ranges = Vec::new();
 6689                    for highlight in highlights {
 6690                        let buffer_id = cursor_buffer.read(cx).remote_id();
 6691                        for (excerpt_id, excerpt_range) in buffer.excerpts_for_buffer(buffer_id, cx)
 6692                        {
 6693                            let start = highlight
 6694                                .range
 6695                                .start
 6696                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6697                            let end = highlight
 6698                                .range
 6699                                .end
 6700                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6701                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6702                                continue;
 6703                            }
 6704
 6705                            let range =
 6706                                Anchor::range_in_buffer(excerpt_id, buffer_id, *start..*end);
 6707                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6708                                write_ranges.push(range);
 6709                            } else {
 6710                                read_ranges.push(range);
 6711                            }
 6712                        }
 6713                    }
 6714
 6715                    this.highlight_background::<DocumentHighlightRead>(
 6716                        &read_ranges,
 6717                        |theme| theme.colors().editor_document_highlight_read_background,
 6718                        cx,
 6719                    );
 6720                    this.highlight_background::<DocumentHighlightWrite>(
 6721                        &write_ranges,
 6722                        |theme| theme.colors().editor_document_highlight_write_background,
 6723                        cx,
 6724                    );
 6725                    cx.notify();
 6726                })
 6727                .log_err();
 6728            }
 6729        }));
 6730        None
 6731    }
 6732
 6733    fn prepare_highlight_query_from_selection(
 6734        &mut self,
 6735        window: &Window,
 6736        cx: &mut Context<Editor>,
 6737    ) -> Option<(String, Range<Anchor>)> {
 6738        if matches!(self.mode, EditorMode::SingleLine) {
 6739            return None;
 6740        }
 6741        if !EditorSettings::get_global(cx).selection_highlight {
 6742            return None;
 6743        }
 6744        if self.selections.count() != 1 || self.selections.line_mode() {
 6745            return None;
 6746        }
 6747        let snapshot = self.snapshot(window, cx);
 6748        let selection = self.selections.newest::<Point>(&snapshot);
 6749        // If the selection spans multiple rows OR it is empty
 6750        if selection.start.row != selection.end.row
 6751            || selection.start.column == selection.end.column
 6752        {
 6753            return None;
 6754        }
 6755        let selection_anchor_range = selection.range().to_anchors(snapshot.buffer_snapshot());
 6756        let query = snapshot
 6757            .buffer_snapshot()
 6758            .text_for_range(selection_anchor_range.clone())
 6759            .collect::<String>();
 6760        if query.trim().is_empty() {
 6761            return None;
 6762        }
 6763        Some((query, selection_anchor_range))
 6764    }
 6765
 6766    fn update_selection_occurrence_highlights(
 6767        &mut self,
 6768        query_text: String,
 6769        query_range: Range<Anchor>,
 6770        multi_buffer_range_to_query: Range<Point>,
 6771        use_debounce: bool,
 6772        window: &mut Window,
 6773        cx: &mut Context<Editor>,
 6774    ) -> Task<()> {
 6775        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6776        cx.spawn_in(window, async move |editor, cx| {
 6777            if use_debounce {
 6778                cx.background_executor()
 6779                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6780                    .await;
 6781            }
 6782            let match_task = cx.background_spawn(async move {
 6783                let buffer_ranges = multi_buffer_snapshot
 6784                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6785                    .into_iter()
 6786                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6787                let mut match_ranges = Vec::new();
 6788                let Ok(regex) = project::search::SearchQuery::text(
 6789                    query_text.clone(),
 6790                    false,
 6791                    false,
 6792                    false,
 6793                    Default::default(),
 6794                    Default::default(),
 6795                    false,
 6796                    None,
 6797                ) else {
 6798                    return Vec::default();
 6799                };
 6800                let query_range = query_range.to_anchors(&multi_buffer_snapshot);
 6801                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6802                    match_ranges.extend(
 6803                        regex
 6804                            .search(buffer_snapshot, Some(search_range.clone()))
 6805                            .await
 6806                            .into_iter()
 6807                            .filter_map(|match_range| {
 6808                                let match_start = buffer_snapshot
 6809                                    .anchor_after(search_range.start + match_range.start);
 6810                                let match_end = buffer_snapshot
 6811                                    .anchor_before(search_range.start + match_range.end);
 6812                                let match_anchor_range = Anchor::range_in_buffer(
 6813                                    excerpt_id,
 6814                                    buffer_snapshot.remote_id(),
 6815                                    match_start..match_end,
 6816                                );
 6817                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6818                            }),
 6819                    );
 6820                }
 6821                match_ranges
 6822            });
 6823            let match_ranges = match_task.await;
 6824            editor
 6825                .update_in(cx, |editor, _, cx| {
 6826                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6827                    if !match_ranges.is_empty() {
 6828                        editor.highlight_background::<SelectedTextHighlight>(
 6829                            &match_ranges,
 6830                            |theme| theme.colors().editor_document_highlight_bracket_background,
 6831                            cx,
 6832                        )
 6833                    }
 6834                })
 6835                .log_err();
 6836        })
 6837    }
 6838
 6839    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 6840        struct NewlineFold;
 6841        let type_id = std::any::TypeId::of::<NewlineFold>();
 6842        if !self.mode.is_single_line() {
 6843            return;
 6844        }
 6845        let snapshot = self.snapshot(window, cx);
 6846        if snapshot.buffer_snapshot().max_point().row == 0 {
 6847            return;
 6848        }
 6849        let task = cx.background_spawn(async move {
 6850            let new_newlines = snapshot
 6851                .buffer_chars_at(0)
 6852                .filter_map(|(c, i)| {
 6853                    if c == '\n' {
 6854                        Some(
 6855                            snapshot.buffer_snapshot().anchor_after(i)
 6856                                ..snapshot.buffer_snapshot().anchor_before(i + 1),
 6857                        )
 6858                    } else {
 6859                        None
 6860                    }
 6861                })
 6862                .collect::<Vec<_>>();
 6863            let existing_newlines = snapshot
 6864                .folds_in_range(0..snapshot.buffer_snapshot().len())
 6865                .filter_map(|fold| {
 6866                    if fold.placeholder.type_tag == Some(type_id) {
 6867                        Some(fold.range.start..fold.range.end)
 6868                    } else {
 6869                        None
 6870                    }
 6871                })
 6872                .collect::<Vec<_>>();
 6873
 6874            (new_newlines, existing_newlines)
 6875        });
 6876        self.folding_newlines = cx.spawn(async move |this, cx| {
 6877            let (new_newlines, existing_newlines) = task.await;
 6878            if new_newlines == existing_newlines {
 6879                return;
 6880            }
 6881            let placeholder = FoldPlaceholder {
 6882                render: Arc::new(move |_, _, cx| {
 6883                    div()
 6884                        .bg(cx.theme().status().hint_background)
 6885                        .border_b_1()
 6886                        .size_full()
 6887                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 6888                        .border_color(cx.theme().status().hint)
 6889                        .child("\\n")
 6890                        .into_any()
 6891                }),
 6892                constrain_width: false,
 6893                merge_adjacent: false,
 6894                type_tag: Some(type_id),
 6895            };
 6896            let creases = new_newlines
 6897                .into_iter()
 6898                .map(|range| Crease::simple(range, placeholder.clone()))
 6899                .collect();
 6900            this.update(cx, |this, cx| {
 6901                this.display_map.update(cx, |display_map, cx| {
 6902                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 6903                    display_map.fold(creases, cx);
 6904                });
 6905            })
 6906            .ok();
 6907        });
 6908    }
 6909
 6910    fn refresh_selected_text_highlights(
 6911        &mut self,
 6912        on_buffer_edit: bool,
 6913        window: &mut Window,
 6914        cx: &mut Context<Editor>,
 6915    ) {
 6916        let Some((query_text, query_range)) =
 6917            self.prepare_highlight_query_from_selection(window, cx)
 6918        else {
 6919            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 6920            self.quick_selection_highlight_task.take();
 6921            self.debounced_selection_highlight_task.take();
 6922            return;
 6923        };
 6924        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6925        if on_buffer_edit
 6926            || self
 6927                .quick_selection_highlight_task
 6928                .as_ref()
 6929                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 6930        {
 6931            let multi_buffer_visible_start = self
 6932                .scroll_manager
 6933                .anchor()
 6934                .anchor
 6935                .to_point(&multi_buffer_snapshot);
 6936            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 6937                multi_buffer_visible_start
 6938                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 6939                Bias::Left,
 6940            );
 6941            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 6942            self.quick_selection_highlight_task = Some((
 6943                query_range.clone(),
 6944                self.update_selection_occurrence_highlights(
 6945                    query_text.clone(),
 6946                    query_range.clone(),
 6947                    multi_buffer_visible_range,
 6948                    false,
 6949                    window,
 6950                    cx,
 6951                ),
 6952            ));
 6953        }
 6954        if on_buffer_edit
 6955            || self
 6956                .debounced_selection_highlight_task
 6957                .as_ref()
 6958                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 6959        {
 6960            let multi_buffer_start = multi_buffer_snapshot
 6961                .anchor_before(0)
 6962                .to_point(&multi_buffer_snapshot);
 6963            let multi_buffer_end = multi_buffer_snapshot
 6964                .anchor_after(multi_buffer_snapshot.len())
 6965                .to_point(&multi_buffer_snapshot);
 6966            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 6967            self.debounced_selection_highlight_task = Some((
 6968                query_range.clone(),
 6969                self.update_selection_occurrence_highlights(
 6970                    query_text,
 6971                    query_range,
 6972                    multi_buffer_full_range,
 6973                    true,
 6974                    window,
 6975                    cx,
 6976                ),
 6977            ));
 6978        }
 6979    }
 6980
 6981    pub fn refresh_edit_prediction(
 6982        &mut self,
 6983        debounce: bool,
 6984        user_requested: bool,
 6985        window: &mut Window,
 6986        cx: &mut Context<Self>,
 6987    ) -> Option<()> {
 6988        if DisableAiSettings::get_global(cx).disable_ai {
 6989            return None;
 6990        }
 6991
 6992        let provider = self.edit_prediction_provider()?;
 6993        let cursor = self.selections.newest_anchor().head();
 6994        let (buffer, cursor_buffer_position) =
 6995            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6996
 6997        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 6998            self.discard_edit_prediction(false, cx);
 6999            return None;
 7000        }
 7001
 7002        self.update_visible_edit_prediction(window, cx);
 7003
 7004        if !user_requested
 7005            && (!self.should_show_edit_predictions()
 7006                || !self.is_focused(window)
 7007                || buffer.read(cx).is_empty())
 7008        {
 7009            self.discard_edit_prediction(false, cx);
 7010            return None;
 7011        }
 7012
 7013        provider.refresh(buffer, cursor_buffer_position, debounce, cx);
 7014        Some(())
 7015    }
 7016
 7017    fn show_edit_predictions_in_menu(&self) -> bool {
 7018        match self.edit_prediction_settings {
 7019            EditPredictionSettings::Disabled => false,
 7020            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7021        }
 7022    }
 7023
 7024    pub fn edit_predictions_enabled(&self) -> bool {
 7025        match self.edit_prediction_settings {
 7026            EditPredictionSettings::Disabled => false,
 7027            EditPredictionSettings::Enabled { .. } => true,
 7028        }
 7029    }
 7030
 7031    fn edit_prediction_requires_modifier(&self) -> bool {
 7032        match self.edit_prediction_settings {
 7033            EditPredictionSettings::Disabled => false,
 7034            EditPredictionSettings::Enabled {
 7035                preview_requires_modifier,
 7036                ..
 7037            } => preview_requires_modifier,
 7038        }
 7039    }
 7040
 7041    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7042        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7043            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7044            self.discard_edit_prediction(false, cx);
 7045        } else {
 7046            let selection = self.selections.newest_anchor();
 7047            let cursor = selection.head();
 7048
 7049            if let Some((buffer, cursor_buffer_position)) =
 7050                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7051            {
 7052                self.edit_prediction_settings =
 7053                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7054            }
 7055        }
 7056    }
 7057
 7058    fn edit_prediction_settings_at_position(
 7059        &self,
 7060        buffer: &Entity<Buffer>,
 7061        buffer_position: language::Anchor,
 7062        cx: &App,
 7063    ) -> EditPredictionSettings {
 7064        if !self.mode.is_full()
 7065            || !self.show_edit_predictions_override.unwrap_or(true)
 7066            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7067        {
 7068            return EditPredictionSettings::Disabled;
 7069        }
 7070
 7071        let buffer = buffer.read(cx);
 7072
 7073        let file = buffer.file();
 7074
 7075        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7076            return EditPredictionSettings::Disabled;
 7077        };
 7078
 7079        let by_provider = matches!(
 7080            self.menu_edit_predictions_policy,
 7081            MenuEditPredictionsPolicy::ByProvider
 7082        );
 7083
 7084        let show_in_menu = by_provider
 7085            && self
 7086                .edit_prediction_provider
 7087                .as_ref()
 7088                .is_some_and(|provider| provider.provider.show_completions_in_menu());
 7089
 7090        let preview_requires_modifier =
 7091            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7092
 7093        EditPredictionSettings::Enabled {
 7094            show_in_menu,
 7095            preview_requires_modifier,
 7096        }
 7097    }
 7098
 7099    fn should_show_edit_predictions(&self) -> bool {
 7100        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7101    }
 7102
 7103    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7104        matches!(
 7105            self.edit_prediction_preview,
 7106            EditPredictionPreview::Active { .. }
 7107        )
 7108    }
 7109
 7110    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7111        let cursor = self.selections.newest_anchor().head();
 7112        if let Some((buffer, cursor_position)) =
 7113            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7114        {
 7115            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7116        } else {
 7117            false
 7118        }
 7119    }
 7120
 7121    pub fn supports_minimap(&self, cx: &App) -> bool {
 7122        !self.minimap_visibility.disabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton
 7123    }
 7124
 7125    fn edit_predictions_enabled_in_buffer(
 7126        &self,
 7127        buffer: &Entity<Buffer>,
 7128        buffer_position: language::Anchor,
 7129        cx: &App,
 7130    ) -> bool {
 7131        maybe!({
 7132            if self.read_only(cx) {
 7133                return Some(false);
 7134            }
 7135            let provider = self.edit_prediction_provider()?;
 7136            if !provider.is_enabled(buffer, buffer_position, cx) {
 7137                return Some(false);
 7138            }
 7139            let buffer = buffer.read(cx);
 7140            let Some(file) = buffer.file() else {
 7141                return Some(true);
 7142            };
 7143            let settings = all_language_settings(Some(file), cx);
 7144            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7145        })
 7146        .unwrap_or(false)
 7147    }
 7148
 7149    fn cycle_edit_prediction(
 7150        &mut self,
 7151        direction: Direction,
 7152        window: &mut Window,
 7153        cx: &mut Context<Self>,
 7154    ) -> Option<()> {
 7155        let provider = self.edit_prediction_provider()?;
 7156        let cursor = self.selections.newest_anchor().head();
 7157        let (buffer, cursor_buffer_position) =
 7158            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7159        if self.edit_predictions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7160            return None;
 7161        }
 7162
 7163        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7164        self.update_visible_edit_prediction(window, cx);
 7165
 7166        Some(())
 7167    }
 7168
 7169    pub fn show_edit_prediction(
 7170        &mut self,
 7171        _: &ShowEditPrediction,
 7172        window: &mut Window,
 7173        cx: &mut Context<Self>,
 7174    ) {
 7175        if !self.has_active_edit_prediction() {
 7176            self.refresh_edit_prediction(false, true, window, cx);
 7177            return;
 7178        }
 7179
 7180        self.update_visible_edit_prediction(window, cx);
 7181    }
 7182
 7183    pub fn display_cursor_names(
 7184        &mut self,
 7185        _: &DisplayCursorNames,
 7186        window: &mut Window,
 7187        cx: &mut Context<Self>,
 7188    ) {
 7189        self.show_cursor_names(window, cx);
 7190    }
 7191
 7192    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7193        self.show_cursor_names = true;
 7194        cx.notify();
 7195        cx.spawn_in(window, async move |this, cx| {
 7196            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7197            this.update(cx, |this, cx| {
 7198                this.show_cursor_names = false;
 7199                cx.notify()
 7200            })
 7201            .ok()
 7202        })
 7203        .detach();
 7204    }
 7205
 7206    pub fn next_edit_prediction(
 7207        &mut self,
 7208        _: &NextEditPrediction,
 7209        window: &mut Window,
 7210        cx: &mut Context<Self>,
 7211    ) {
 7212        if self.has_active_edit_prediction() {
 7213            self.cycle_edit_prediction(Direction::Next, window, cx);
 7214        } else {
 7215            let is_copilot_disabled = self
 7216                .refresh_edit_prediction(false, true, window, cx)
 7217                .is_none();
 7218            if is_copilot_disabled {
 7219                cx.propagate();
 7220            }
 7221        }
 7222    }
 7223
 7224    pub fn previous_edit_prediction(
 7225        &mut self,
 7226        _: &PreviousEditPrediction,
 7227        window: &mut Window,
 7228        cx: &mut Context<Self>,
 7229    ) {
 7230        if self.has_active_edit_prediction() {
 7231            self.cycle_edit_prediction(Direction::Prev, window, cx);
 7232        } else {
 7233            let is_copilot_disabled = self
 7234                .refresh_edit_prediction(false, true, window, cx)
 7235                .is_none();
 7236            if is_copilot_disabled {
 7237                cx.propagate();
 7238            }
 7239        }
 7240    }
 7241
 7242    pub fn accept_edit_prediction(
 7243        &mut self,
 7244        _: &AcceptEditPrediction,
 7245        window: &mut Window,
 7246        cx: &mut Context<Self>,
 7247    ) {
 7248        if self.show_edit_predictions_in_menu() {
 7249            self.hide_context_menu(window, cx);
 7250        }
 7251
 7252        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7253            return;
 7254        };
 7255
 7256        match &active_edit_prediction.completion {
 7257            EditPrediction::MoveWithin { target, .. } => {
 7258                let target = *target;
 7259
 7260                if let Some(position_map) = &self.last_position_map {
 7261                    if position_map
 7262                        .visible_row_range
 7263                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7264                        || !self.edit_prediction_requires_modifier()
 7265                    {
 7266                        self.unfold_ranges(&[target..target], true, false, cx);
 7267                        // Note that this is also done in vim's handler of the Tab action.
 7268                        self.change_selections(
 7269                            SelectionEffects::scroll(Autoscroll::newest()),
 7270                            window,
 7271                            cx,
 7272                            |selections| {
 7273                                selections.select_anchor_ranges([target..target]);
 7274                            },
 7275                        );
 7276                        self.clear_row_highlights::<EditPredictionPreview>();
 7277
 7278                        self.edit_prediction_preview
 7279                            .set_previous_scroll_position(None);
 7280                    } else {
 7281                        self.edit_prediction_preview
 7282                            .set_previous_scroll_position(Some(
 7283                                position_map.snapshot.scroll_anchor,
 7284                            ));
 7285
 7286                        self.highlight_rows::<EditPredictionPreview>(
 7287                            target..target,
 7288                            cx.theme().colors().editor_highlighted_line_background,
 7289                            RowHighlightOptions {
 7290                                autoscroll: true,
 7291                                ..Default::default()
 7292                            },
 7293                            cx,
 7294                        );
 7295                        self.request_autoscroll(Autoscroll::fit(), cx);
 7296                    }
 7297                }
 7298            }
 7299            EditPrediction::MoveOutside { snapshot, target } => {
 7300                if let Some(workspace) = self.workspace() {
 7301                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7302                        .detach_and_log_err(cx);
 7303                }
 7304            }
 7305            EditPrediction::Edit { edits, .. } => {
 7306                self.report_edit_prediction_event(
 7307                    active_edit_prediction.completion_id.clone(),
 7308                    true,
 7309                    cx,
 7310                );
 7311
 7312                if let Some(provider) = self.edit_prediction_provider() {
 7313                    provider.accept(cx);
 7314                }
 7315
 7316                // Store the transaction ID and selections before applying the edit
 7317                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7318
 7319                let snapshot = self.buffer.read(cx).snapshot(cx);
 7320                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7321
 7322                self.buffer.update(cx, |buffer, cx| {
 7323                    buffer.edit(edits.iter().cloned(), None, cx)
 7324                });
 7325
 7326                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7327                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7328                });
 7329
 7330                let selections = self.selections.disjoint_anchors_arc();
 7331                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7332                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7333                    if has_new_transaction {
 7334                        self.selection_history
 7335                            .insert_transaction(transaction_id_now, selections);
 7336                    }
 7337                }
 7338
 7339                self.update_visible_edit_prediction(window, cx);
 7340                if self.active_edit_prediction.is_none() {
 7341                    self.refresh_edit_prediction(true, true, window, cx);
 7342                }
 7343
 7344                cx.notify();
 7345            }
 7346        }
 7347
 7348        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7349    }
 7350
 7351    pub fn accept_partial_edit_prediction(
 7352        &mut self,
 7353        _: &AcceptPartialEditPrediction,
 7354        window: &mut Window,
 7355        cx: &mut Context<Self>,
 7356    ) {
 7357        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7358            return;
 7359        };
 7360        if self.selections.count() != 1 {
 7361            return;
 7362        }
 7363
 7364        match &active_edit_prediction.completion {
 7365            EditPrediction::MoveWithin { target, .. } => {
 7366                let target = *target;
 7367                self.change_selections(
 7368                    SelectionEffects::scroll(Autoscroll::newest()),
 7369                    window,
 7370                    cx,
 7371                    |selections| {
 7372                        selections.select_anchor_ranges([target..target]);
 7373                    },
 7374                );
 7375            }
 7376            EditPrediction::MoveOutside { snapshot, target } => {
 7377                if let Some(workspace) = self.workspace() {
 7378                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7379                        .detach_and_log_err(cx);
 7380                }
 7381            }
 7382            EditPrediction::Edit { edits, .. } => {
 7383                self.report_edit_prediction_event(
 7384                    active_edit_prediction.completion_id.clone(),
 7385                    true,
 7386                    cx,
 7387                );
 7388
 7389                // Find an insertion that starts at the cursor position.
 7390                let snapshot = self.buffer.read(cx).snapshot(cx);
 7391                let cursor_offset = self
 7392                    .selections
 7393                    .newest::<usize>(&self.display_snapshot(cx))
 7394                    .head();
 7395                let insertion = edits.iter().find_map(|(range, text)| {
 7396                    let range = range.to_offset(&snapshot);
 7397                    if range.is_empty() && range.start == cursor_offset {
 7398                        Some(text)
 7399                    } else {
 7400                        None
 7401                    }
 7402                });
 7403
 7404                if let Some(text) = insertion {
 7405                    let mut partial_completion = text
 7406                        .chars()
 7407                        .by_ref()
 7408                        .take_while(|c| c.is_alphabetic())
 7409                        .collect::<String>();
 7410                    if partial_completion.is_empty() {
 7411                        partial_completion = text
 7412                            .chars()
 7413                            .by_ref()
 7414                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7415                            .collect::<String>();
 7416                    }
 7417
 7418                    cx.emit(EditorEvent::InputHandled {
 7419                        utf16_range_to_replace: None,
 7420                        text: partial_completion.clone().into(),
 7421                    });
 7422
 7423                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7424
 7425                    self.refresh_edit_prediction(true, true, window, cx);
 7426                    cx.notify();
 7427                } else {
 7428                    self.accept_edit_prediction(&Default::default(), window, cx);
 7429                }
 7430            }
 7431        }
 7432    }
 7433
 7434    fn discard_edit_prediction(
 7435        &mut self,
 7436        should_report_edit_prediction_event: bool,
 7437        cx: &mut Context<Self>,
 7438    ) -> bool {
 7439        if should_report_edit_prediction_event {
 7440            let completion_id = self
 7441                .active_edit_prediction
 7442                .as_ref()
 7443                .and_then(|active_completion| active_completion.completion_id.clone());
 7444
 7445            self.report_edit_prediction_event(completion_id, false, cx);
 7446        }
 7447
 7448        if let Some(provider) = self.edit_prediction_provider() {
 7449            provider.discard(cx);
 7450        }
 7451
 7452        self.take_active_edit_prediction(cx)
 7453    }
 7454
 7455    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7456        let Some(provider) = self.edit_prediction_provider() else {
 7457            return;
 7458        };
 7459
 7460        let Some((_, buffer, _)) = self
 7461            .buffer
 7462            .read(cx)
 7463            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7464        else {
 7465            return;
 7466        };
 7467
 7468        let extension = buffer
 7469            .read(cx)
 7470            .file()
 7471            .and_then(|file| Some(file.path().extension()?.to_string()));
 7472
 7473        let event_type = match accepted {
 7474            true => "Edit Prediction Accepted",
 7475            false => "Edit Prediction Discarded",
 7476        };
 7477        telemetry::event!(
 7478            event_type,
 7479            provider = provider.name(),
 7480            prediction_id = id,
 7481            suggestion_accepted = accepted,
 7482            file_extension = extension,
 7483        );
 7484    }
 7485
 7486    fn open_editor_at_anchor(
 7487        snapshot: &language::BufferSnapshot,
 7488        target: language::Anchor,
 7489        workspace: &Entity<Workspace>,
 7490        window: &mut Window,
 7491        cx: &mut App,
 7492    ) -> Task<Result<()>> {
 7493        workspace.update(cx, |workspace, cx| {
 7494            let path = snapshot.file().map(|file| file.full_path(cx));
 7495            let Some(path) =
 7496                path.and_then(|path| workspace.project().read(cx).find_project_path(path, cx))
 7497            else {
 7498                return Task::ready(Err(anyhow::anyhow!("Project path not found")));
 7499            };
 7500            let target = text::ToPoint::to_point(&target, snapshot);
 7501            let item = workspace.open_path(path, None, true, window, cx);
 7502            window.spawn(cx, async move |cx| {
 7503                let Some(editor) = item.await?.downcast::<Editor>() else {
 7504                    return Ok(());
 7505                };
 7506                editor
 7507                    .update_in(cx, |editor, window, cx| {
 7508                        editor.go_to_singleton_buffer_point(target, window, cx);
 7509                    })
 7510                    .ok();
 7511                anyhow::Ok(())
 7512            })
 7513        })
 7514    }
 7515
 7516    pub fn has_active_edit_prediction(&self) -> bool {
 7517        self.active_edit_prediction.is_some()
 7518    }
 7519
 7520    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7521        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7522            return false;
 7523        };
 7524
 7525        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7526        self.clear_highlights::<EditPredictionHighlight>(cx);
 7527        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7528        true
 7529    }
 7530
 7531    /// Returns true when we're displaying the edit prediction popover below the cursor
 7532    /// like we are not previewing and the LSP autocomplete menu is visible
 7533    /// or we are in `when_holding_modifier` mode.
 7534    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7535        if self.edit_prediction_preview_is_active()
 7536            || !self.show_edit_predictions_in_menu()
 7537            || !self.edit_predictions_enabled()
 7538        {
 7539            return false;
 7540        }
 7541
 7542        if self.has_visible_completions_menu() {
 7543            return true;
 7544        }
 7545
 7546        has_completion && self.edit_prediction_requires_modifier()
 7547    }
 7548
 7549    fn handle_modifiers_changed(
 7550        &mut self,
 7551        modifiers: Modifiers,
 7552        position_map: &PositionMap,
 7553        window: &mut Window,
 7554        cx: &mut Context<Self>,
 7555    ) {
 7556        if self.show_edit_predictions_in_menu() {
 7557            self.update_edit_prediction_preview(&modifiers, window, cx);
 7558        }
 7559
 7560        self.update_selection_mode(&modifiers, position_map, window, cx);
 7561
 7562        let mouse_position = window.mouse_position();
 7563        if !position_map.text_hitbox.is_hovered(window) {
 7564            return;
 7565        }
 7566
 7567        self.update_hovered_link(
 7568            position_map.point_for_position(mouse_position),
 7569            &position_map.snapshot,
 7570            modifiers,
 7571            window,
 7572            cx,
 7573        )
 7574    }
 7575
 7576    fn multi_cursor_modifier(invert: bool, modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7577        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7578        if invert {
 7579            match multi_cursor_setting {
 7580                MultiCursorModifier::Alt => modifiers.alt,
 7581                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7582            }
 7583        } else {
 7584            match multi_cursor_setting {
 7585                MultiCursorModifier::Alt => modifiers.secondary(),
 7586                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7587            }
 7588        }
 7589    }
 7590
 7591    fn columnar_selection_mode(
 7592        modifiers: &Modifiers,
 7593        cx: &mut Context<Self>,
 7594    ) -> Option<ColumnarMode> {
 7595        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7596            if Self::multi_cursor_modifier(false, modifiers, cx) {
 7597                Some(ColumnarMode::FromMouse)
 7598            } else if Self::multi_cursor_modifier(true, modifiers, cx) {
 7599                Some(ColumnarMode::FromSelection)
 7600            } else {
 7601                None
 7602            }
 7603        } else {
 7604            None
 7605        }
 7606    }
 7607
 7608    fn update_selection_mode(
 7609        &mut self,
 7610        modifiers: &Modifiers,
 7611        position_map: &PositionMap,
 7612        window: &mut Window,
 7613        cx: &mut Context<Self>,
 7614    ) {
 7615        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7616            return;
 7617        };
 7618        if self.selections.pending_anchor().is_none() {
 7619            return;
 7620        }
 7621
 7622        let mouse_position = window.mouse_position();
 7623        let point_for_position = position_map.point_for_position(mouse_position);
 7624        let position = point_for_position.previous_valid;
 7625
 7626        self.select(
 7627            SelectPhase::BeginColumnar {
 7628                position,
 7629                reset: false,
 7630                mode,
 7631                goal_column: point_for_position.exact_unclipped.column(),
 7632            },
 7633            window,
 7634            cx,
 7635        );
 7636    }
 7637
 7638    fn update_edit_prediction_preview(
 7639        &mut self,
 7640        modifiers: &Modifiers,
 7641        window: &mut Window,
 7642        cx: &mut Context<Self>,
 7643    ) {
 7644        let mut modifiers_held = false;
 7645        if let Some(accept_keystroke) = self
 7646            .accept_edit_prediction_keybind(false, window, cx)
 7647            .keystroke()
 7648        {
 7649            modifiers_held = modifiers_held
 7650                || (accept_keystroke.modifiers() == modifiers
 7651                    && accept_keystroke.modifiers().modified());
 7652        };
 7653        if let Some(accept_partial_keystroke) = self
 7654            .accept_edit_prediction_keybind(true, window, cx)
 7655            .keystroke()
 7656        {
 7657            modifiers_held = modifiers_held
 7658                || (accept_partial_keystroke.modifiers() == modifiers
 7659                    && accept_partial_keystroke.modifiers().modified());
 7660        }
 7661
 7662        if modifiers_held {
 7663            if matches!(
 7664                self.edit_prediction_preview,
 7665                EditPredictionPreview::Inactive { .. }
 7666            ) {
 7667                self.edit_prediction_preview = EditPredictionPreview::Active {
 7668                    previous_scroll_position: None,
 7669                    since: Instant::now(),
 7670                };
 7671
 7672                self.update_visible_edit_prediction(window, cx);
 7673                cx.notify();
 7674            }
 7675        } else if let EditPredictionPreview::Active {
 7676            previous_scroll_position,
 7677            since,
 7678        } = self.edit_prediction_preview
 7679        {
 7680            if let (Some(previous_scroll_position), Some(position_map)) =
 7681                (previous_scroll_position, self.last_position_map.as_ref())
 7682            {
 7683                self.set_scroll_position(
 7684                    previous_scroll_position
 7685                        .scroll_position(&position_map.snapshot.display_snapshot),
 7686                    window,
 7687                    cx,
 7688                );
 7689            }
 7690
 7691            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7692                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7693            };
 7694            self.clear_row_highlights::<EditPredictionPreview>();
 7695            self.update_visible_edit_prediction(window, cx);
 7696            cx.notify();
 7697        }
 7698    }
 7699
 7700    fn update_visible_edit_prediction(
 7701        &mut self,
 7702        _window: &mut Window,
 7703        cx: &mut Context<Self>,
 7704    ) -> Option<()> {
 7705        if DisableAiSettings::get_global(cx).disable_ai {
 7706            return None;
 7707        }
 7708
 7709        if self.ime_transaction.is_some() {
 7710            self.discard_edit_prediction(false, cx);
 7711            return None;
 7712        }
 7713
 7714        let selection = self.selections.newest_anchor();
 7715        let cursor = selection.head();
 7716        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7717        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7718        let excerpt_id = cursor.excerpt_id;
 7719
 7720        let show_in_menu = self.show_edit_predictions_in_menu();
 7721        let completions_menu_has_precedence = !show_in_menu
 7722            && (self.context_menu.borrow().is_some()
 7723                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 7724
 7725        if completions_menu_has_precedence
 7726            || !offset_selection.is_empty()
 7727            || self
 7728                .active_edit_prediction
 7729                .as_ref()
 7730                .is_some_and(|completion| {
 7731                    let Some(invalidation_range) = completion.invalidation_range.as_ref() else {
 7732                        return false;
 7733                    };
 7734                    let invalidation_range = invalidation_range.to_offset(&multibuffer);
 7735                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7736                    !invalidation_range.contains(&offset_selection.head())
 7737                })
 7738        {
 7739            self.discard_edit_prediction(false, cx);
 7740            return None;
 7741        }
 7742
 7743        self.take_active_edit_prediction(cx);
 7744        let Some(provider) = self.edit_prediction_provider() else {
 7745            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7746            return None;
 7747        };
 7748
 7749        let (buffer, cursor_buffer_position) =
 7750            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7751
 7752        self.edit_prediction_settings =
 7753            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7754
 7755        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7756
 7757        if self.edit_prediction_indent_conflict {
 7758            let cursor_point = cursor.to_point(&multibuffer);
 7759
 7760            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7761
 7762            if let Some((_, indent)) = indents.iter().next()
 7763                && indent.len == cursor_point.column
 7764            {
 7765                self.edit_prediction_indent_conflict = false;
 7766            }
 7767        }
 7768
 7769        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7770
 7771        let (completion_id, edits, edit_preview) = match edit_prediction {
 7772            edit_prediction::EditPrediction::Local {
 7773                id,
 7774                edits,
 7775                edit_preview,
 7776            } => (id, edits, edit_preview),
 7777            edit_prediction::EditPrediction::Jump {
 7778                id,
 7779                snapshot,
 7780                target,
 7781            } => {
 7782                self.stale_edit_prediction_in_menu = None;
 7783                self.active_edit_prediction = Some(EditPredictionState {
 7784                    inlay_ids: vec![],
 7785                    completion: EditPrediction::MoveOutside { snapshot, target },
 7786                    completion_id: id,
 7787                    invalidation_range: None,
 7788                });
 7789                cx.notify();
 7790                return Some(());
 7791            }
 7792        };
 7793
 7794        let edits = edits
 7795            .into_iter()
 7796            .flat_map(|(range, new_text)| {
 7797                Some((
 7798                    multibuffer.anchor_range_in_excerpt(excerpt_id, range)?,
 7799                    new_text,
 7800                ))
 7801            })
 7802            .collect::<Vec<_>>();
 7803        if edits.is_empty() {
 7804            return None;
 7805        }
 7806
 7807        let first_edit_start = edits.first().unwrap().0.start;
 7808        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7809        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7810
 7811        let last_edit_end = edits.last().unwrap().0.end;
 7812        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7813        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7814
 7815        let cursor_row = cursor.to_point(&multibuffer).row;
 7816
 7817        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7818
 7819        let mut inlay_ids = Vec::new();
 7820        let invalidation_row_range;
 7821        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7822            Some(cursor_row..edit_end_row)
 7823        } else if cursor_row > edit_end_row {
 7824            Some(edit_start_row..cursor_row)
 7825        } else {
 7826            None
 7827        };
 7828        let supports_jump = self
 7829            .edit_prediction_provider
 7830            .as_ref()
 7831            .map(|provider| provider.provider.supports_jump_to_edit())
 7832            .unwrap_or(true);
 7833
 7834        let is_move = supports_jump
 7835            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 7836        let completion = if is_move {
 7837            invalidation_row_range =
 7838                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7839            let target = first_edit_start;
 7840            EditPrediction::MoveWithin { target, snapshot }
 7841        } else {
 7842            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7843                && !self.edit_predictions_hidden_for_vim_mode;
 7844
 7845            if show_completions_in_buffer {
 7846                if edits
 7847                    .iter()
 7848                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7849                {
 7850                    let mut inlays = Vec::new();
 7851                    for (range, new_text) in &edits {
 7852                        let inlay = Inlay::edit_prediction(
 7853                            post_inc(&mut self.next_inlay_id),
 7854                            range.start,
 7855                            Rope::from_str_small(new_text.as_str()),
 7856                        );
 7857                        inlay_ids.push(inlay.id);
 7858                        inlays.push(inlay);
 7859                    }
 7860
 7861                    self.splice_inlays(&[], inlays, cx);
 7862                } else {
 7863                    let background_color = cx.theme().status().deleted_background;
 7864                    self.highlight_text::<EditPredictionHighlight>(
 7865                        edits.iter().map(|(range, _)| range.clone()).collect(),
 7866                        HighlightStyle {
 7867                            background_color: Some(background_color),
 7868                            ..Default::default()
 7869                        },
 7870                        cx,
 7871                    );
 7872                }
 7873            }
 7874
 7875            invalidation_row_range = edit_start_row..edit_end_row;
 7876
 7877            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7878                if provider.show_tab_accept_marker() {
 7879                    EditDisplayMode::TabAccept
 7880                } else {
 7881                    EditDisplayMode::Inline
 7882                }
 7883            } else {
 7884                EditDisplayMode::DiffPopover
 7885            };
 7886
 7887            EditPrediction::Edit {
 7888                edits,
 7889                edit_preview,
 7890                display_mode,
 7891                snapshot,
 7892            }
 7893        };
 7894
 7895        let invalidation_range = multibuffer
 7896            .anchor_before(Point::new(invalidation_row_range.start, 0))
 7897            ..multibuffer.anchor_after(Point::new(
 7898                invalidation_row_range.end,
 7899                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7900            ));
 7901
 7902        self.stale_edit_prediction_in_menu = None;
 7903        self.active_edit_prediction = Some(EditPredictionState {
 7904            inlay_ids,
 7905            completion,
 7906            completion_id,
 7907            invalidation_range: Some(invalidation_range),
 7908        });
 7909
 7910        cx.notify();
 7911
 7912        Some(())
 7913    }
 7914
 7915    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionProviderHandle>> {
 7916        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 7917    }
 7918
 7919    fn clear_tasks(&mut self) {
 7920        self.tasks.clear()
 7921    }
 7922
 7923    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 7924        if self.tasks.insert(key, value).is_some() {
 7925            // This case should hopefully be rare, but just in case...
 7926            log::error!(
 7927                "multiple different run targets found on a single line, only the last target will be rendered"
 7928            )
 7929        }
 7930    }
 7931
 7932    /// Get all display points of breakpoints that will be rendered within editor
 7933    ///
 7934    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 7935    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 7936    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 7937    fn active_breakpoints(
 7938        &self,
 7939        range: Range<DisplayRow>,
 7940        window: &mut Window,
 7941        cx: &mut Context<Self>,
 7942    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 7943        let mut breakpoint_display_points = HashMap::default();
 7944
 7945        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 7946            return breakpoint_display_points;
 7947        };
 7948
 7949        let snapshot = self.snapshot(window, cx);
 7950
 7951        let multi_buffer_snapshot = snapshot.buffer_snapshot();
 7952        let Some(project) = self.project() else {
 7953            return breakpoint_display_points;
 7954        };
 7955
 7956        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 7957            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 7958
 7959        for (buffer_snapshot, range, excerpt_id) in
 7960            multi_buffer_snapshot.range_to_buffer_ranges(range)
 7961        {
 7962            let Some(buffer) = project
 7963                .read(cx)
 7964                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 7965            else {
 7966                continue;
 7967            };
 7968            let breakpoints = breakpoint_store.read(cx).breakpoints(
 7969                &buffer,
 7970                Some(
 7971                    buffer_snapshot.anchor_before(range.start)
 7972                        ..buffer_snapshot.anchor_after(range.end),
 7973                ),
 7974                buffer_snapshot,
 7975                cx,
 7976            );
 7977            for (breakpoint, state) in breakpoints {
 7978                let multi_buffer_anchor =
 7979                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 7980                let position = multi_buffer_anchor
 7981                    .to_point(&multi_buffer_snapshot)
 7982                    .to_display_point(&snapshot);
 7983
 7984                breakpoint_display_points.insert(
 7985                    position.row(),
 7986                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 7987                );
 7988            }
 7989        }
 7990
 7991        breakpoint_display_points
 7992    }
 7993
 7994    fn breakpoint_context_menu(
 7995        &self,
 7996        anchor: Anchor,
 7997        window: &mut Window,
 7998        cx: &mut Context<Self>,
 7999    ) -> Entity<ui::ContextMenu> {
 8000        let weak_editor = cx.weak_entity();
 8001        let focus_handle = self.focus_handle(cx);
 8002
 8003        let row = self
 8004            .buffer
 8005            .read(cx)
 8006            .snapshot(cx)
 8007            .summary_for_anchor::<Point>(&anchor)
 8008            .row;
 8009
 8010        let breakpoint = self
 8011            .breakpoint_at_row(row, window, cx)
 8012            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 8013
 8014        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 8015            "Edit Log Breakpoint"
 8016        } else {
 8017            "Set Log Breakpoint"
 8018        };
 8019
 8020        let condition_breakpoint_msg = if breakpoint
 8021            .as_ref()
 8022            .is_some_and(|bp| bp.1.condition.is_some())
 8023        {
 8024            "Edit Condition Breakpoint"
 8025        } else {
 8026            "Set Condition Breakpoint"
 8027        };
 8028
 8029        let hit_condition_breakpoint_msg = if breakpoint
 8030            .as_ref()
 8031            .is_some_and(|bp| bp.1.hit_condition.is_some())
 8032        {
 8033            "Edit Hit Condition Breakpoint"
 8034        } else {
 8035            "Set Hit Condition Breakpoint"
 8036        };
 8037
 8038        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 8039            "Unset Breakpoint"
 8040        } else {
 8041            "Set Breakpoint"
 8042        };
 8043
 8044        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8045
 8046        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8047            BreakpointState::Enabled => Some("Disable"),
 8048            BreakpointState::Disabled => Some("Enable"),
 8049        });
 8050
 8051        let (anchor, breakpoint) =
 8052            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8053
 8054        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8055            menu.on_blur_subscription(Subscription::new(|| {}))
 8056                .context(focus_handle)
 8057                .when(run_to_cursor, |this| {
 8058                    let weak_editor = weak_editor.clone();
 8059                    this.entry("Run to cursor", None, move |window, cx| {
 8060                        weak_editor
 8061                            .update(cx, |editor, cx| {
 8062                                editor.change_selections(
 8063                                    SelectionEffects::no_scroll(),
 8064                                    window,
 8065                                    cx,
 8066                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8067                                );
 8068                            })
 8069                            .ok();
 8070
 8071                        window.dispatch_action(Box::new(RunToCursor), cx);
 8072                    })
 8073                    .separator()
 8074                })
 8075                .when_some(toggle_state_msg, |this, msg| {
 8076                    this.entry(msg, None, {
 8077                        let weak_editor = weak_editor.clone();
 8078                        let breakpoint = breakpoint.clone();
 8079                        move |_window, cx| {
 8080                            weak_editor
 8081                                .update(cx, |this, cx| {
 8082                                    this.edit_breakpoint_at_anchor(
 8083                                        anchor,
 8084                                        breakpoint.as_ref().clone(),
 8085                                        BreakpointEditAction::InvertState,
 8086                                        cx,
 8087                                    );
 8088                                })
 8089                                .log_err();
 8090                        }
 8091                    })
 8092                })
 8093                .entry(set_breakpoint_msg, None, {
 8094                    let weak_editor = weak_editor.clone();
 8095                    let breakpoint = breakpoint.clone();
 8096                    move |_window, cx| {
 8097                        weak_editor
 8098                            .update(cx, |this, cx| {
 8099                                this.edit_breakpoint_at_anchor(
 8100                                    anchor,
 8101                                    breakpoint.as_ref().clone(),
 8102                                    BreakpointEditAction::Toggle,
 8103                                    cx,
 8104                                );
 8105                            })
 8106                            .log_err();
 8107                    }
 8108                })
 8109                .entry(log_breakpoint_msg, None, {
 8110                    let breakpoint = breakpoint.clone();
 8111                    let weak_editor = weak_editor.clone();
 8112                    move |window, cx| {
 8113                        weak_editor
 8114                            .update(cx, |this, cx| {
 8115                                this.add_edit_breakpoint_block(
 8116                                    anchor,
 8117                                    breakpoint.as_ref(),
 8118                                    BreakpointPromptEditAction::Log,
 8119                                    window,
 8120                                    cx,
 8121                                );
 8122                            })
 8123                            .log_err();
 8124                    }
 8125                })
 8126                .entry(condition_breakpoint_msg, None, {
 8127                    let breakpoint = breakpoint.clone();
 8128                    let weak_editor = weak_editor.clone();
 8129                    move |window, cx| {
 8130                        weak_editor
 8131                            .update(cx, |this, cx| {
 8132                                this.add_edit_breakpoint_block(
 8133                                    anchor,
 8134                                    breakpoint.as_ref(),
 8135                                    BreakpointPromptEditAction::Condition,
 8136                                    window,
 8137                                    cx,
 8138                                );
 8139                            })
 8140                            .log_err();
 8141                    }
 8142                })
 8143                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8144                    weak_editor
 8145                        .update(cx, |this, cx| {
 8146                            this.add_edit_breakpoint_block(
 8147                                anchor,
 8148                                breakpoint.as_ref(),
 8149                                BreakpointPromptEditAction::HitCondition,
 8150                                window,
 8151                                cx,
 8152                            );
 8153                        })
 8154                        .log_err();
 8155                })
 8156        })
 8157    }
 8158
 8159    fn render_breakpoint(
 8160        &self,
 8161        position: Anchor,
 8162        row: DisplayRow,
 8163        breakpoint: &Breakpoint,
 8164        state: Option<BreakpointSessionState>,
 8165        cx: &mut Context<Self>,
 8166    ) -> IconButton {
 8167        let is_rejected = state.is_some_and(|s| !s.verified);
 8168        // Is it a breakpoint that shows up when hovering over gutter?
 8169        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8170            (false, false),
 8171            |PhantomBreakpointIndicator {
 8172                 is_active,
 8173                 display_row,
 8174                 collides_with_existing_breakpoint,
 8175             }| {
 8176                (
 8177                    is_active && display_row == row,
 8178                    collides_with_existing_breakpoint,
 8179                )
 8180            },
 8181        );
 8182
 8183        let (color, icon) = {
 8184            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8185                (false, false) => ui::IconName::DebugBreakpoint,
 8186                (true, false) => ui::IconName::DebugLogBreakpoint,
 8187                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8188                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8189            };
 8190
 8191            let color = if is_phantom {
 8192                Color::Hint
 8193            } else if is_rejected {
 8194                Color::Disabled
 8195            } else {
 8196                Color::Debugger
 8197            };
 8198
 8199            (color, icon)
 8200        };
 8201
 8202        let breakpoint = Arc::from(breakpoint.clone());
 8203
 8204        let alt_as_text = gpui::Keystroke {
 8205            modifiers: Modifiers::secondary_key(),
 8206            ..Default::default()
 8207        };
 8208        let primary_action_text = if breakpoint.is_disabled() {
 8209            "Enable breakpoint"
 8210        } else if is_phantom && !collides_with_existing {
 8211            "Set breakpoint"
 8212        } else {
 8213            "Unset breakpoint"
 8214        };
 8215        let focus_handle = self.focus_handle.clone();
 8216
 8217        let meta = if is_rejected {
 8218            SharedString::from("No executable code is associated with this line.")
 8219        } else if collides_with_existing && !breakpoint.is_disabled() {
 8220            SharedString::from(format!(
 8221                "{alt_as_text}-click to disable,\nright-click for more options."
 8222            ))
 8223        } else {
 8224            SharedString::from("Right-click for more options.")
 8225        };
 8226        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8227            .icon_size(IconSize::XSmall)
 8228            .size(ui::ButtonSize::None)
 8229            .when(is_rejected, |this| {
 8230                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8231            })
 8232            .icon_color(color)
 8233            .style(ButtonStyle::Transparent)
 8234            .on_click(cx.listener({
 8235                move |editor, event: &ClickEvent, window, cx| {
 8236                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8237                        BreakpointEditAction::InvertState
 8238                    } else {
 8239                        BreakpointEditAction::Toggle
 8240                    };
 8241
 8242                    window.focus(&editor.focus_handle(cx));
 8243                    editor.edit_breakpoint_at_anchor(
 8244                        position,
 8245                        breakpoint.as_ref().clone(),
 8246                        edit_action,
 8247                        cx,
 8248                    );
 8249                }
 8250            }))
 8251            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8252                editor.set_breakpoint_context_menu(
 8253                    row,
 8254                    Some(position),
 8255                    event.position(),
 8256                    window,
 8257                    cx,
 8258                );
 8259            }))
 8260            .tooltip(move |_window, cx| {
 8261                Tooltip::with_meta_in(
 8262                    primary_action_text,
 8263                    Some(&ToggleBreakpoint),
 8264                    meta.clone(),
 8265                    &focus_handle,
 8266                    cx,
 8267                )
 8268            })
 8269    }
 8270
 8271    fn build_tasks_context(
 8272        project: &Entity<Project>,
 8273        buffer: &Entity<Buffer>,
 8274        buffer_row: u32,
 8275        tasks: &Arc<RunnableTasks>,
 8276        cx: &mut Context<Self>,
 8277    ) -> Task<Option<task::TaskContext>> {
 8278        let position = Point::new(buffer_row, tasks.column);
 8279        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8280        let location = Location {
 8281            buffer: buffer.clone(),
 8282            range: range_start..range_start,
 8283        };
 8284        // Fill in the environmental variables from the tree-sitter captures
 8285        let mut captured_task_variables = TaskVariables::default();
 8286        for (capture_name, value) in tasks.extra_variables.clone() {
 8287            captured_task_variables.insert(
 8288                task::VariableName::Custom(capture_name.into()),
 8289                value.clone(),
 8290            );
 8291        }
 8292        project.update(cx, |project, cx| {
 8293            project.task_store().update(cx, |task_store, cx| {
 8294                task_store.task_context_for_location(captured_task_variables, location, cx)
 8295            })
 8296        })
 8297    }
 8298
 8299    pub fn spawn_nearest_task(
 8300        &mut self,
 8301        action: &SpawnNearestTask,
 8302        window: &mut Window,
 8303        cx: &mut Context<Self>,
 8304    ) {
 8305        let Some((workspace, _)) = self.workspace.clone() else {
 8306            return;
 8307        };
 8308        let Some(project) = self.project.clone() else {
 8309            return;
 8310        };
 8311
 8312        // Try to find a closest, enclosing node using tree-sitter that has a task
 8313        let Some((buffer, buffer_row, tasks)) = self
 8314            .find_enclosing_node_task(cx)
 8315            // Or find the task that's closest in row-distance.
 8316            .or_else(|| self.find_closest_task(cx))
 8317        else {
 8318            return;
 8319        };
 8320
 8321        let reveal_strategy = action.reveal;
 8322        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8323        cx.spawn_in(window, async move |_, cx| {
 8324            let context = task_context.await?;
 8325            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8326
 8327            let resolved = &mut resolved_task.resolved;
 8328            resolved.reveal = reveal_strategy;
 8329
 8330            workspace
 8331                .update_in(cx, |workspace, window, cx| {
 8332                    workspace.schedule_resolved_task(
 8333                        task_source_kind,
 8334                        resolved_task,
 8335                        false,
 8336                        window,
 8337                        cx,
 8338                    );
 8339                })
 8340                .ok()
 8341        })
 8342        .detach();
 8343    }
 8344
 8345    fn find_closest_task(
 8346        &mut self,
 8347        cx: &mut Context<Self>,
 8348    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8349        let cursor_row = self
 8350            .selections
 8351            .newest_adjusted(&self.display_snapshot(cx))
 8352            .head()
 8353            .row;
 8354
 8355        let ((buffer_id, row), tasks) = self
 8356            .tasks
 8357            .iter()
 8358            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8359
 8360        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8361        let tasks = Arc::new(tasks.to_owned());
 8362        Some((buffer, *row, tasks))
 8363    }
 8364
 8365    fn find_enclosing_node_task(
 8366        &mut self,
 8367        cx: &mut Context<Self>,
 8368    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8369        let snapshot = self.buffer.read(cx).snapshot(cx);
 8370        let offset = self
 8371            .selections
 8372            .newest::<usize>(&self.display_snapshot(cx))
 8373            .head();
 8374        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8375        let buffer_id = excerpt.buffer().remote_id();
 8376
 8377        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8378        let mut cursor = layer.node().walk();
 8379
 8380        while cursor.goto_first_child_for_byte(offset).is_some() {
 8381            if cursor.node().end_byte() == offset {
 8382                cursor.goto_next_sibling();
 8383            }
 8384        }
 8385
 8386        // Ascend to the smallest ancestor that contains the range and has a task.
 8387        loop {
 8388            let node = cursor.node();
 8389            let node_range = node.byte_range();
 8390            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8391
 8392            // Check if this node contains our offset
 8393            if node_range.start <= offset && node_range.end >= offset {
 8394                // If it contains offset, check for task
 8395                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8396                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8397                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8398                }
 8399            }
 8400
 8401            if !cursor.goto_parent() {
 8402                break;
 8403            }
 8404        }
 8405        None
 8406    }
 8407
 8408    fn render_run_indicator(
 8409        &self,
 8410        _style: &EditorStyle,
 8411        is_active: bool,
 8412        row: DisplayRow,
 8413        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8414        cx: &mut Context<Self>,
 8415    ) -> IconButton {
 8416        let color = Color::Muted;
 8417        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8418
 8419        IconButton::new(
 8420            ("run_indicator", row.0 as usize),
 8421            ui::IconName::PlayOutlined,
 8422        )
 8423        .shape(ui::IconButtonShape::Square)
 8424        .icon_size(IconSize::XSmall)
 8425        .icon_color(color)
 8426        .toggle_state(is_active)
 8427        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8428            let quick_launch = match e {
 8429                ClickEvent::Keyboard(_) => true,
 8430                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8431            };
 8432
 8433            window.focus(&editor.focus_handle(cx));
 8434            editor.toggle_code_actions(
 8435                &ToggleCodeActions {
 8436                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8437                    quick_launch,
 8438                },
 8439                window,
 8440                cx,
 8441            );
 8442        }))
 8443        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8444            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8445        }))
 8446    }
 8447
 8448    pub fn context_menu_visible(&self) -> bool {
 8449        !self.edit_prediction_preview_is_active()
 8450            && self
 8451                .context_menu
 8452                .borrow()
 8453                .as_ref()
 8454                .is_some_and(|menu| menu.visible())
 8455    }
 8456
 8457    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8458        self.context_menu
 8459            .borrow()
 8460            .as_ref()
 8461            .map(|menu| menu.origin())
 8462    }
 8463
 8464    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8465        self.context_menu_options = Some(options);
 8466    }
 8467
 8468    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = px(24.);
 8469    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = px(2.);
 8470
 8471    fn render_edit_prediction_popover(
 8472        &mut self,
 8473        text_bounds: &Bounds<Pixels>,
 8474        content_origin: gpui::Point<Pixels>,
 8475        right_margin: Pixels,
 8476        editor_snapshot: &EditorSnapshot,
 8477        visible_row_range: Range<DisplayRow>,
 8478        scroll_top: ScrollOffset,
 8479        scroll_bottom: ScrollOffset,
 8480        line_layouts: &[LineWithInvisibles],
 8481        line_height: Pixels,
 8482        scroll_position: gpui::Point<ScrollOffset>,
 8483        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8484        newest_selection_head: Option<DisplayPoint>,
 8485        editor_width: Pixels,
 8486        style: &EditorStyle,
 8487        window: &mut Window,
 8488        cx: &mut App,
 8489    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8490        if self.mode().is_minimap() {
 8491            return None;
 8492        }
 8493        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8494
 8495        if self.edit_prediction_visible_in_cursor_popover(true) {
 8496            return None;
 8497        }
 8498
 8499        match &active_edit_prediction.completion {
 8500            EditPrediction::MoveWithin { target, .. } => {
 8501                let target_display_point = target.to_display_point(editor_snapshot);
 8502
 8503                if self.edit_prediction_requires_modifier() {
 8504                    if !self.edit_prediction_preview_is_active() {
 8505                        return None;
 8506                    }
 8507
 8508                    self.render_edit_prediction_modifier_jump_popover(
 8509                        text_bounds,
 8510                        content_origin,
 8511                        visible_row_range,
 8512                        line_layouts,
 8513                        line_height,
 8514                        scroll_pixel_position,
 8515                        newest_selection_head,
 8516                        target_display_point,
 8517                        window,
 8518                        cx,
 8519                    )
 8520                } else {
 8521                    self.render_edit_prediction_eager_jump_popover(
 8522                        text_bounds,
 8523                        content_origin,
 8524                        editor_snapshot,
 8525                        visible_row_range,
 8526                        scroll_top,
 8527                        scroll_bottom,
 8528                        line_height,
 8529                        scroll_pixel_position,
 8530                        target_display_point,
 8531                        editor_width,
 8532                        window,
 8533                        cx,
 8534                    )
 8535                }
 8536            }
 8537            EditPrediction::Edit {
 8538                display_mode: EditDisplayMode::Inline,
 8539                ..
 8540            } => None,
 8541            EditPrediction::Edit {
 8542                display_mode: EditDisplayMode::TabAccept,
 8543                edits,
 8544                ..
 8545            } => {
 8546                let range = &edits.first()?.0;
 8547                let target_display_point = range.end.to_display_point(editor_snapshot);
 8548
 8549                self.render_edit_prediction_end_of_line_popover(
 8550                    "Accept",
 8551                    editor_snapshot,
 8552                    visible_row_range,
 8553                    target_display_point,
 8554                    line_height,
 8555                    scroll_pixel_position,
 8556                    content_origin,
 8557                    editor_width,
 8558                    window,
 8559                    cx,
 8560                )
 8561            }
 8562            EditPrediction::Edit {
 8563                edits,
 8564                edit_preview,
 8565                display_mode: EditDisplayMode::DiffPopover,
 8566                snapshot,
 8567            } => self.render_edit_prediction_diff_popover(
 8568                text_bounds,
 8569                content_origin,
 8570                right_margin,
 8571                editor_snapshot,
 8572                visible_row_range,
 8573                line_layouts,
 8574                line_height,
 8575                scroll_position,
 8576                scroll_pixel_position,
 8577                newest_selection_head,
 8578                editor_width,
 8579                style,
 8580                edits,
 8581                edit_preview,
 8582                snapshot,
 8583                window,
 8584                cx,
 8585            ),
 8586            EditPrediction::MoveOutside { snapshot, .. } => {
 8587                let file_name = snapshot
 8588                    .file()
 8589                    .map(|file| file.file_name(cx))
 8590                    .unwrap_or("untitled");
 8591                let mut element = self
 8592                    .render_edit_prediction_line_popover(
 8593                        format!("Jump to {file_name}"),
 8594                        Some(IconName::ZedPredict),
 8595                        window,
 8596                        cx,
 8597                    )
 8598                    .into_any();
 8599
 8600                let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8601                let origin_x = text_bounds.size.width / 2. - size.width / 2.;
 8602                let origin_y = text_bounds.size.height - size.height - px(30.);
 8603                let origin = text_bounds.origin + gpui::Point::new(origin_x, origin_y);
 8604                element.prepaint_at(origin, window, cx);
 8605
 8606                Some((element, origin))
 8607            }
 8608        }
 8609    }
 8610
 8611    fn render_edit_prediction_modifier_jump_popover(
 8612        &mut self,
 8613        text_bounds: &Bounds<Pixels>,
 8614        content_origin: gpui::Point<Pixels>,
 8615        visible_row_range: Range<DisplayRow>,
 8616        line_layouts: &[LineWithInvisibles],
 8617        line_height: Pixels,
 8618        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8619        newest_selection_head: Option<DisplayPoint>,
 8620        target_display_point: DisplayPoint,
 8621        window: &mut Window,
 8622        cx: &mut App,
 8623    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8624        let scrolled_content_origin =
 8625            content_origin - gpui::Point::new(scroll_pixel_position.x.into(), Pixels::ZERO);
 8626
 8627        const SCROLL_PADDING_Y: Pixels = px(12.);
 8628
 8629        if target_display_point.row() < visible_row_range.start {
 8630            return self.render_edit_prediction_scroll_popover(
 8631                |_| SCROLL_PADDING_Y,
 8632                IconName::ArrowUp,
 8633                visible_row_range,
 8634                line_layouts,
 8635                newest_selection_head,
 8636                scrolled_content_origin,
 8637                window,
 8638                cx,
 8639            );
 8640        } else if target_display_point.row() >= visible_row_range.end {
 8641            return self.render_edit_prediction_scroll_popover(
 8642                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8643                IconName::ArrowDown,
 8644                visible_row_range,
 8645                line_layouts,
 8646                newest_selection_head,
 8647                scrolled_content_origin,
 8648                window,
 8649                cx,
 8650            );
 8651        }
 8652
 8653        const POLE_WIDTH: Pixels = px(2.);
 8654
 8655        let line_layout =
 8656            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8657        let target_column = target_display_point.column() as usize;
 8658
 8659        let target_x = line_layout.x_for_index(target_column);
 8660        let target_y = (target_display_point.row().as_f64() * f64::from(line_height))
 8661            - scroll_pixel_position.y;
 8662
 8663        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8664
 8665        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8666        border_color.l += 0.001;
 8667
 8668        let mut element = v_flex()
 8669            .items_end()
 8670            .when(flag_on_right, |el| el.items_start())
 8671            .child(if flag_on_right {
 8672                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8673                    .rounded_bl(px(0.))
 8674                    .rounded_tl(px(0.))
 8675                    .border_l_2()
 8676                    .border_color(border_color)
 8677            } else {
 8678                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8679                    .rounded_br(px(0.))
 8680                    .rounded_tr(px(0.))
 8681                    .border_r_2()
 8682                    .border_color(border_color)
 8683            })
 8684            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8685            .into_any();
 8686
 8687        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8688
 8689        let mut origin = scrolled_content_origin + point(target_x, target_y.into())
 8690            - point(
 8691                if flag_on_right {
 8692                    POLE_WIDTH
 8693                } else {
 8694                    size.width - POLE_WIDTH
 8695                },
 8696                size.height - line_height,
 8697            );
 8698
 8699        origin.x = origin.x.max(content_origin.x);
 8700
 8701        element.prepaint_at(origin, window, cx);
 8702
 8703        Some((element, origin))
 8704    }
 8705
 8706    fn render_edit_prediction_scroll_popover(
 8707        &mut self,
 8708        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8709        scroll_icon: IconName,
 8710        visible_row_range: Range<DisplayRow>,
 8711        line_layouts: &[LineWithInvisibles],
 8712        newest_selection_head: Option<DisplayPoint>,
 8713        scrolled_content_origin: gpui::Point<Pixels>,
 8714        window: &mut Window,
 8715        cx: &mut App,
 8716    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8717        let mut element = self
 8718            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)
 8719            .into_any();
 8720
 8721        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8722
 8723        let cursor = newest_selection_head?;
 8724        let cursor_row_layout =
 8725            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8726        let cursor_column = cursor.column() as usize;
 8727
 8728        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8729
 8730        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8731
 8732        element.prepaint_at(origin, window, cx);
 8733        Some((element, origin))
 8734    }
 8735
 8736    fn render_edit_prediction_eager_jump_popover(
 8737        &mut self,
 8738        text_bounds: &Bounds<Pixels>,
 8739        content_origin: gpui::Point<Pixels>,
 8740        editor_snapshot: &EditorSnapshot,
 8741        visible_row_range: Range<DisplayRow>,
 8742        scroll_top: ScrollOffset,
 8743        scroll_bottom: ScrollOffset,
 8744        line_height: Pixels,
 8745        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8746        target_display_point: DisplayPoint,
 8747        editor_width: Pixels,
 8748        window: &mut Window,
 8749        cx: &mut App,
 8750    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8751        if target_display_point.row().as_f64() < scroll_top {
 8752            let mut element = self
 8753                .render_edit_prediction_line_popover(
 8754                    "Jump to Edit",
 8755                    Some(IconName::ArrowUp),
 8756                    window,
 8757                    cx,
 8758                )
 8759                .into_any();
 8760
 8761            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8762            let offset = point(
 8763                (text_bounds.size.width - size.width) / 2.,
 8764                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8765            );
 8766
 8767            let origin = text_bounds.origin + offset;
 8768            element.prepaint_at(origin, window, cx);
 8769            Some((element, origin))
 8770        } else if (target_display_point.row().as_f64() + 1.) > scroll_bottom {
 8771            let mut element = self
 8772                .render_edit_prediction_line_popover(
 8773                    "Jump to Edit",
 8774                    Some(IconName::ArrowDown),
 8775                    window,
 8776                    cx,
 8777                )
 8778                .into_any();
 8779
 8780            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8781            let offset = point(
 8782                (text_bounds.size.width - size.width) / 2.,
 8783                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8784            );
 8785
 8786            let origin = text_bounds.origin + offset;
 8787            element.prepaint_at(origin, window, cx);
 8788            Some((element, origin))
 8789        } else {
 8790            self.render_edit_prediction_end_of_line_popover(
 8791                "Jump to Edit",
 8792                editor_snapshot,
 8793                visible_row_range,
 8794                target_display_point,
 8795                line_height,
 8796                scroll_pixel_position,
 8797                content_origin,
 8798                editor_width,
 8799                window,
 8800                cx,
 8801            )
 8802        }
 8803    }
 8804
 8805    fn render_edit_prediction_end_of_line_popover(
 8806        self: &mut Editor,
 8807        label: &'static str,
 8808        editor_snapshot: &EditorSnapshot,
 8809        visible_row_range: Range<DisplayRow>,
 8810        target_display_point: DisplayPoint,
 8811        line_height: Pixels,
 8812        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8813        content_origin: gpui::Point<Pixels>,
 8814        editor_width: Pixels,
 8815        window: &mut Window,
 8816        cx: &mut App,
 8817    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8818        let target_line_end = DisplayPoint::new(
 8819            target_display_point.row(),
 8820            editor_snapshot.line_len(target_display_point.row()),
 8821        );
 8822
 8823        let mut element = self
 8824            .render_edit_prediction_line_popover(label, None, window, cx)
 8825            .into_any();
 8826
 8827        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8828
 8829        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8830
 8831        let start_point = content_origin - point(scroll_pixel_position.x.into(), Pixels::ZERO);
 8832        let mut origin = start_point
 8833            + line_origin
 8834            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8835        origin.x = origin.x.max(content_origin.x);
 8836
 8837        let max_x = content_origin.x + editor_width - size.width;
 8838
 8839        if origin.x > max_x {
 8840            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8841
 8842            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8843                origin.y += offset;
 8844                IconName::ArrowUp
 8845            } else {
 8846                origin.y -= offset;
 8847                IconName::ArrowDown
 8848            };
 8849
 8850            element = self
 8851                .render_edit_prediction_line_popover(label, Some(icon), window, cx)
 8852                .into_any();
 8853
 8854            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8855
 8856            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8857        }
 8858
 8859        element.prepaint_at(origin, window, cx);
 8860        Some((element, origin))
 8861    }
 8862
 8863    fn render_edit_prediction_diff_popover(
 8864        self: &Editor,
 8865        text_bounds: &Bounds<Pixels>,
 8866        content_origin: gpui::Point<Pixels>,
 8867        right_margin: Pixels,
 8868        editor_snapshot: &EditorSnapshot,
 8869        visible_row_range: Range<DisplayRow>,
 8870        line_layouts: &[LineWithInvisibles],
 8871        line_height: Pixels,
 8872        scroll_position: gpui::Point<ScrollOffset>,
 8873        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8874        newest_selection_head: Option<DisplayPoint>,
 8875        editor_width: Pixels,
 8876        style: &EditorStyle,
 8877        edits: &Vec<(Range<Anchor>, String)>,
 8878        edit_preview: &Option<language::EditPreview>,
 8879        snapshot: &language::BufferSnapshot,
 8880        window: &mut Window,
 8881        cx: &mut App,
 8882    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8883        let edit_start = edits
 8884            .first()
 8885            .unwrap()
 8886            .0
 8887            .start
 8888            .to_display_point(editor_snapshot);
 8889        let edit_end = edits
 8890            .last()
 8891            .unwrap()
 8892            .0
 8893            .end
 8894            .to_display_point(editor_snapshot);
 8895
 8896        let is_visible = visible_row_range.contains(&edit_start.row())
 8897            || visible_row_range.contains(&edit_end.row());
 8898        if !is_visible {
 8899            return None;
 8900        }
 8901
 8902        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 8903            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 8904        } else {
 8905            // Fallback for providers without edit_preview
 8906            crate::edit_prediction_fallback_text(edits, cx)
 8907        };
 8908
 8909        let styled_text = highlighted_edits.to_styled_text(&style.text);
 8910        let line_count = highlighted_edits.text.lines().count();
 8911
 8912        const BORDER_WIDTH: Pixels = px(1.);
 8913
 8914        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8915        let has_keybind = keybind.is_some();
 8916
 8917        let mut element = h_flex()
 8918            .items_start()
 8919            .child(
 8920                h_flex()
 8921                    .bg(cx.theme().colors().editor_background)
 8922                    .border(BORDER_WIDTH)
 8923                    .shadow_xs()
 8924                    .border_color(cx.theme().colors().border)
 8925                    .rounded_l_lg()
 8926                    .when(line_count > 1, |el| el.rounded_br_lg())
 8927                    .pr_1()
 8928                    .child(styled_text),
 8929            )
 8930            .child(
 8931                h_flex()
 8932                    .h(line_height + BORDER_WIDTH * 2.)
 8933                    .px_1p5()
 8934                    .gap_1()
 8935                    // Workaround: For some reason, there's a gap if we don't do this
 8936                    .ml(-BORDER_WIDTH)
 8937                    .shadow(vec![gpui::BoxShadow {
 8938                        color: gpui::black().opacity(0.05),
 8939                        offset: point(px(1.), px(1.)),
 8940                        blur_radius: px(2.),
 8941                        spread_radius: px(0.),
 8942                    }])
 8943                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 8944                    .border(BORDER_WIDTH)
 8945                    .border_color(cx.theme().colors().border)
 8946                    .rounded_r_lg()
 8947                    .id("edit_prediction_diff_popover_keybind")
 8948                    .when(!has_keybind, |el| {
 8949                        let status_colors = cx.theme().status();
 8950
 8951                        el.bg(status_colors.error_background)
 8952                            .border_color(status_colors.error.opacity(0.6))
 8953                            .child(Icon::new(IconName::Info).color(Color::Error))
 8954                            .cursor_default()
 8955                            .hoverable_tooltip(move |_window, cx| {
 8956                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8957                            })
 8958                    })
 8959                    .children(keybind),
 8960            )
 8961            .into_any();
 8962
 8963        let longest_row =
 8964            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 8965        let longest_line_width = if visible_row_range.contains(&longest_row) {
 8966            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 8967        } else {
 8968            layout_line(
 8969                longest_row,
 8970                editor_snapshot,
 8971                style,
 8972                editor_width,
 8973                |_| false,
 8974                window,
 8975                cx,
 8976            )
 8977            .width
 8978        };
 8979
 8980        let viewport_bounds =
 8981            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 8982                right: -right_margin,
 8983                ..Default::default()
 8984            });
 8985
 8986        let x_after_longest = Pixels::from(
 8987            ScrollPixelOffset::from(
 8988                text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X,
 8989            ) - scroll_pixel_position.x,
 8990        );
 8991
 8992        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8993
 8994        // Fully visible if it can be displayed within the window (allow overlapping other
 8995        // panes). However, this is only allowed if the popover starts within text_bounds.
 8996        let can_position_to_the_right = x_after_longest < text_bounds.right()
 8997            && x_after_longest + element_bounds.width < viewport_bounds.right();
 8998
 8999        let mut origin = if can_position_to_the_right {
 9000            point(
 9001                x_after_longest,
 9002                text_bounds.origin.y
 9003                    + Pixels::from(
 9004                        edit_start.row().as_f64() * ScrollPixelOffset::from(line_height)
 9005                            - scroll_pixel_position.y,
 9006                    ),
 9007            )
 9008        } else {
 9009            let cursor_row = newest_selection_head.map(|head| head.row());
 9010            let above_edit = edit_start
 9011                .row()
 9012                .0
 9013                .checked_sub(line_count as u32)
 9014                .map(DisplayRow);
 9015            let below_edit = Some(edit_end.row() + 1);
 9016            let above_cursor =
 9017                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 9018            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 9019
 9020            // Place the edit popover adjacent to the edit if there is a location
 9021            // available that is onscreen and does not obscure the cursor. Otherwise,
 9022            // place it adjacent to the cursor.
 9023            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 9024                .into_iter()
 9025                .flatten()
 9026                .find(|&start_row| {
 9027                    let end_row = start_row + line_count as u32;
 9028                    visible_row_range.contains(&start_row)
 9029                        && visible_row_range.contains(&end_row)
 9030                        && cursor_row
 9031                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9032                })?;
 9033
 9034            content_origin
 9035                + point(
 9036                    Pixels::from(-scroll_pixel_position.x),
 9037                    Pixels::from(
 9038                        (row_target.as_f64() - scroll_position.y) * f64::from(line_height),
 9039                    ),
 9040                )
 9041        };
 9042
 9043        origin.x -= BORDER_WIDTH;
 9044
 9045        window.defer_draw(element, origin, 1);
 9046
 9047        // Do not return an element, since it will already be drawn due to defer_draw.
 9048        None
 9049    }
 9050
 9051    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9052        px(30.)
 9053    }
 9054
 9055    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9056        if self.read_only(cx) {
 9057            cx.theme().players().read_only()
 9058        } else {
 9059            self.style.as_ref().unwrap().local_player
 9060        }
 9061    }
 9062
 9063    fn render_edit_prediction_accept_keybind(
 9064        &self,
 9065        window: &mut Window,
 9066        cx: &mut App,
 9067    ) -> Option<AnyElement> {
 9068        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 9069        let accept_keystroke = accept_binding.keystroke()?;
 9070
 9071        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9072
 9073        let modifiers_color = if *accept_keystroke.modifiers() == window.modifiers() {
 9074            Color::Accent
 9075        } else {
 9076            Color::Muted
 9077        };
 9078
 9079        h_flex()
 9080            .px_0p5()
 9081            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9082            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9083            .text_size(TextSize::XSmall.rems(cx))
 9084            .child(h_flex().children(ui::render_modifiers(
 9085                accept_keystroke.modifiers(),
 9086                PlatformStyle::platform(),
 9087                Some(modifiers_color),
 9088                Some(IconSize::XSmall.rems().into()),
 9089                true,
 9090            )))
 9091            .when(is_platform_style_mac, |parent| {
 9092                parent.child(accept_keystroke.key().to_string())
 9093            })
 9094            .when(!is_platform_style_mac, |parent| {
 9095                parent.child(
 9096                    Key::new(
 9097                        util::capitalize(accept_keystroke.key()),
 9098                        Some(Color::Default),
 9099                    )
 9100                    .size(Some(IconSize::XSmall.rems().into())),
 9101                )
 9102            })
 9103            .into_any()
 9104            .into()
 9105    }
 9106
 9107    fn render_edit_prediction_line_popover(
 9108        &self,
 9109        label: impl Into<SharedString>,
 9110        icon: Option<IconName>,
 9111        window: &mut Window,
 9112        cx: &mut App,
 9113    ) -> Stateful<Div> {
 9114        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9115
 9116        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9117        let has_keybind = keybind.is_some();
 9118
 9119        h_flex()
 9120            .id("ep-line-popover")
 9121            .py_0p5()
 9122            .pl_1()
 9123            .pr(padding_right)
 9124            .gap_1()
 9125            .rounded_md()
 9126            .border_1()
 9127            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9128            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9129            .shadow_xs()
 9130            .when(!has_keybind, |el| {
 9131                let status_colors = cx.theme().status();
 9132
 9133                el.bg(status_colors.error_background)
 9134                    .border_color(status_colors.error.opacity(0.6))
 9135                    .pl_2()
 9136                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9137                    .cursor_default()
 9138                    .hoverable_tooltip(move |_window, cx| {
 9139                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9140                    })
 9141            })
 9142            .children(keybind)
 9143            .child(
 9144                Label::new(label)
 9145                    .size(LabelSize::Small)
 9146                    .when(!has_keybind, |el| {
 9147                        el.color(cx.theme().status().error.into()).strikethrough()
 9148                    }),
 9149            )
 9150            .when(!has_keybind, |el| {
 9151                el.child(
 9152                    h_flex().ml_1().child(
 9153                        Icon::new(IconName::Info)
 9154                            .size(IconSize::Small)
 9155                            .color(cx.theme().status().error.into()),
 9156                    ),
 9157                )
 9158            })
 9159            .when_some(icon, |element, icon| {
 9160                element.child(
 9161                    div()
 9162                        .mt(px(1.5))
 9163                        .child(Icon::new(icon).size(IconSize::Small)),
 9164                )
 9165            })
 9166    }
 9167
 9168    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9169        let accent_color = cx.theme().colors().text_accent;
 9170        let editor_bg_color = cx.theme().colors().editor_background;
 9171        editor_bg_color.blend(accent_color.opacity(0.1))
 9172    }
 9173
 9174    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9175        let accent_color = cx.theme().colors().text_accent;
 9176        let editor_bg_color = cx.theme().colors().editor_background;
 9177        editor_bg_color.blend(accent_color.opacity(0.6))
 9178    }
 9179    fn get_prediction_provider_icon_name(
 9180        provider: &Option<RegisteredEditPredictionProvider>,
 9181    ) -> IconName {
 9182        match provider {
 9183            Some(provider) => match provider.provider.name() {
 9184                "copilot" => IconName::Copilot,
 9185                "supermaven" => IconName::Supermaven,
 9186                _ => IconName::ZedPredict,
 9187            },
 9188            None => IconName::ZedPredict,
 9189        }
 9190    }
 9191
 9192    fn render_edit_prediction_cursor_popover(
 9193        &self,
 9194        min_width: Pixels,
 9195        max_width: Pixels,
 9196        cursor_point: Point,
 9197        style: &EditorStyle,
 9198        accept_keystroke: Option<&gpui::KeybindingKeystroke>,
 9199        _window: &Window,
 9200        cx: &mut Context<Editor>,
 9201    ) -> Option<AnyElement> {
 9202        let provider = self.edit_prediction_provider.as_ref()?;
 9203        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9204
 9205        let is_refreshing = provider.provider.is_refreshing(cx);
 9206
 9207        fn pending_completion_container(icon: IconName) -> Div {
 9208            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9209        }
 9210
 9211        let completion = match &self.active_edit_prediction {
 9212            Some(prediction) => {
 9213                if !self.has_visible_completions_menu() {
 9214                    const RADIUS: Pixels = px(6.);
 9215                    const BORDER_WIDTH: Pixels = px(1.);
 9216
 9217                    return Some(
 9218                        h_flex()
 9219                            .elevation_2(cx)
 9220                            .border(BORDER_WIDTH)
 9221                            .border_color(cx.theme().colors().border)
 9222                            .when(accept_keystroke.is_none(), |el| {
 9223                                el.border_color(cx.theme().status().error)
 9224                            })
 9225                            .rounded(RADIUS)
 9226                            .rounded_tl(px(0.))
 9227                            .overflow_hidden()
 9228                            .child(div().px_1p5().child(match &prediction.completion {
 9229                                EditPrediction::MoveWithin { target, snapshot } => {
 9230                                    use text::ToPoint as _;
 9231                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9232                                    {
 9233                                        Icon::new(IconName::ZedPredictDown)
 9234                                    } else {
 9235                                        Icon::new(IconName::ZedPredictUp)
 9236                                    }
 9237                                }
 9238                                EditPrediction::MoveOutside { .. } => {
 9239                                    // TODO [zeta2] custom icon for external jump?
 9240                                    Icon::new(provider_icon)
 9241                                }
 9242                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9243                            }))
 9244                            .child(
 9245                                h_flex()
 9246                                    .gap_1()
 9247                                    .py_1()
 9248                                    .px_2()
 9249                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9250                                    .border_l_1()
 9251                                    .border_color(cx.theme().colors().border)
 9252                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9253                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9254                                        el.child(
 9255                                            Label::new("Hold")
 9256                                                .size(LabelSize::Small)
 9257                                                .when(accept_keystroke.is_none(), |el| {
 9258                                                    el.strikethrough()
 9259                                                })
 9260                                                .line_height_style(LineHeightStyle::UiLabel),
 9261                                        )
 9262                                    })
 9263                                    .id("edit_prediction_cursor_popover_keybind")
 9264                                    .when(accept_keystroke.is_none(), |el| {
 9265                                        let status_colors = cx.theme().status();
 9266
 9267                                        el.bg(status_colors.error_background)
 9268                                            .border_color(status_colors.error.opacity(0.6))
 9269                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9270                                            .cursor_default()
 9271                                            .hoverable_tooltip(move |_window, cx| {
 9272                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9273                                                    .into()
 9274                                            })
 9275                                    })
 9276                                    .when_some(
 9277                                        accept_keystroke.as_ref(),
 9278                                        |el, accept_keystroke| {
 9279                                            el.child(h_flex().children(ui::render_modifiers(
 9280                                                accept_keystroke.modifiers(),
 9281                                                PlatformStyle::platform(),
 9282                                                Some(Color::Default),
 9283                                                Some(IconSize::XSmall.rems().into()),
 9284                                                false,
 9285                                            )))
 9286                                        },
 9287                                    ),
 9288                            )
 9289                            .into_any(),
 9290                    );
 9291                }
 9292
 9293                self.render_edit_prediction_cursor_popover_preview(
 9294                    prediction,
 9295                    cursor_point,
 9296                    style,
 9297                    cx,
 9298                )?
 9299            }
 9300
 9301            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9302                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9303                    stale_completion,
 9304                    cursor_point,
 9305                    style,
 9306                    cx,
 9307                )?,
 9308
 9309                None => pending_completion_container(provider_icon)
 9310                    .child(Label::new("...").size(LabelSize::Small)),
 9311            },
 9312
 9313            None => pending_completion_container(provider_icon)
 9314                .child(Label::new("...").size(LabelSize::Small)),
 9315        };
 9316
 9317        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9318            completion
 9319                .with_animation(
 9320                    "loading-completion",
 9321                    Animation::new(Duration::from_secs(2))
 9322                        .repeat()
 9323                        .with_easing(pulsating_between(0.4, 0.8)),
 9324                    |label, delta| label.opacity(delta),
 9325                )
 9326                .into_any_element()
 9327        } else {
 9328            completion.into_any_element()
 9329        };
 9330
 9331        let has_completion = self.active_edit_prediction.is_some();
 9332
 9333        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9334        Some(
 9335            h_flex()
 9336                .min_w(min_width)
 9337                .max_w(max_width)
 9338                .flex_1()
 9339                .elevation_2(cx)
 9340                .border_color(cx.theme().colors().border)
 9341                .child(
 9342                    div()
 9343                        .flex_1()
 9344                        .py_1()
 9345                        .px_2()
 9346                        .overflow_hidden()
 9347                        .child(completion),
 9348                )
 9349                .when_some(accept_keystroke, |el, accept_keystroke| {
 9350                    if !accept_keystroke.modifiers().modified() {
 9351                        return el;
 9352                    }
 9353
 9354                    el.child(
 9355                        h_flex()
 9356                            .h_full()
 9357                            .border_l_1()
 9358                            .rounded_r_lg()
 9359                            .border_color(cx.theme().colors().border)
 9360                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9361                            .gap_1()
 9362                            .py_1()
 9363                            .px_2()
 9364                            .child(
 9365                                h_flex()
 9366                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9367                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9368                                    .child(h_flex().children(ui::render_modifiers(
 9369                                        accept_keystroke.modifiers(),
 9370                                        PlatformStyle::platform(),
 9371                                        Some(if !has_completion {
 9372                                            Color::Muted
 9373                                        } else {
 9374                                            Color::Default
 9375                                        }),
 9376                                        None,
 9377                                        false,
 9378                                    ))),
 9379                            )
 9380                            .child(Label::new("Preview").into_any_element())
 9381                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9382                    )
 9383                })
 9384                .into_any(),
 9385        )
 9386    }
 9387
 9388    fn render_edit_prediction_cursor_popover_preview(
 9389        &self,
 9390        completion: &EditPredictionState,
 9391        cursor_point: Point,
 9392        style: &EditorStyle,
 9393        cx: &mut Context<Editor>,
 9394    ) -> Option<Div> {
 9395        use text::ToPoint as _;
 9396
 9397        fn render_relative_row_jump(
 9398            prefix: impl Into<String>,
 9399            current_row: u32,
 9400            target_row: u32,
 9401        ) -> Div {
 9402            let (row_diff, arrow) = if target_row < current_row {
 9403                (current_row - target_row, IconName::ArrowUp)
 9404            } else {
 9405                (target_row - current_row, IconName::ArrowDown)
 9406            };
 9407
 9408            h_flex()
 9409                .child(
 9410                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9411                        .color(Color::Muted)
 9412                        .size(LabelSize::Small),
 9413                )
 9414                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9415        }
 9416
 9417        let supports_jump = self
 9418            .edit_prediction_provider
 9419            .as_ref()
 9420            .map(|provider| provider.provider.supports_jump_to_edit())
 9421            .unwrap_or(true);
 9422
 9423        match &completion.completion {
 9424            EditPrediction::MoveWithin {
 9425                target, snapshot, ..
 9426            } => {
 9427                if !supports_jump {
 9428                    return None;
 9429                }
 9430
 9431                Some(
 9432                    h_flex()
 9433                        .px_2()
 9434                        .gap_2()
 9435                        .flex_1()
 9436                        .child(
 9437                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
 9438                                Icon::new(IconName::ZedPredictDown)
 9439                            } else {
 9440                                Icon::new(IconName::ZedPredictUp)
 9441                            },
 9442                        )
 9443                        .child(Label::new("Jump to Edit")),
 9444                )
 9445            }
 9446            EditPrediction::MoveOutside { snapshot, .. } => {
 9447                let file_name = snapshot
 9448                    .file()
 9449                    .map(|file| file.file_name(cx))
 9450                    .unwrap_or("untitled");
 9451                Some(
 9452                    h_flex()
 9453                        .px_2()
 9454                        .gap_2()
 9455                        .flex_1()
 9456                        .child(Icon::new(IconName::ZedPredict))
 9457                        .child(Label::new(format!("Jump to {file_name}"))),
 9458                )
 9459            }
 9460            EditPrediction::Edit {
 9461                edits,
 9462                edit_preview,
 9463                snapshot,
 9464                display_mode: _,
 9465            } => {
 9466                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
 9467
 9468                let (highlighted_edits, has_more_lines) =
 9469                    if let Some(edit_preview) = edit_preview.as_ref() {
 9470                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
 9471                            .first_line_preview()
 9472                    } else {
 9473                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
 9474                    };
 9475
 9476                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9477                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9478
 9479                let preview = h_flex()
 9480                    .gap_1()
 9481                    .min_w_16()
 9482                    .child(styled_text)
 9483                    .when(has_more_lines, |parent| parent.child(""));
 9484
 9485                let left = if supports_jump && first_edit_row != cursor_point.row {
 9486                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9487                        .into_any_element()
 9488                } else {
 9489                    let icon_name =
 9490                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9491                    Icon::new(icon_name).into_any_element()
 9492                };
 9493
 9494                Some(
 9495                    h_flex()
 9496                        .h_full()
 9497                        .flex_1()
 9498                        .gap_2()
 9499                        .pr_1()
 9500                        .overflow_x_hidden()
 9501                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9502                        .child(left)
 9503                        .child(preview),
 9504                )
 9505            }
 9506        }
 9507    }
 9508
 9509    pub fn render_context_menu(
 9510        &self,
 9511        style: &EditorStyle,
 9512        max_height_in_lines: u32,
 9513        window: &mut Window,
 9514        cx: &mut Context<Editor>,
 9515    ) -> Option<AnyElement> {
 9516        let menu = self.context_menu.borrow();
 9517        let menu = menu.as_ref()?;
 9518        if !menu.visible() {
 9519            return None;
 9520        };
 9521        Some(menu.render(style, max_height_in_lines, window, cx))
 9522    }
 9523
 9524    fn render_context_menu_aside(
 9525        &mut self,
 9526        max_size: Size<Pixels>,
 9527        window: &mut Window,
 9528        cx: &mut Context<Editor>,
 9529    ) -> Option<AnyElement> {
 9530        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9531            if menu.visible() {
 9532                menu.render_aside(max_size, window, cx)
 9533            } else {
 9534                None
 9535            }
 9536        })
 9537    }
 9538
 9539    fn hide_context_menu(
 9540        &mut self,
 9541        window: &mut Window,
 9542        cx: &mut Context<Self>,
 9543    ) -> Option<CodeContextMenu> {
 9544        cx.notify();
 9545        self.completion_tasks.clear();
 9546        let context_menu = self.context_menu.borrow_mut().take();
 9547        self.stale_edit_prediction_in_menu.take();
 9548        self.update_visible_edit_prediction(window, cx);
 9549        if let Some(CodeContextMenu::Completions(_)) = &context_menu
 9550            && let Some(completion_provider) = &self.completion_provider
 9551        {
 9552            completion_provider.selection_changed(None, window, cx);
 9553        }
 9554        context_menu
 9555    }
 9556
 9557    fn show_snippet_choices(
 9558        &mut self,
 9559        choices: &Vec<String>,
 9560        selection: Range<Anchor>,
 9561        cx: &mut Context<Self>,
 9562    ) {
 9563        let Some((_, buffer, _)) = self
 9564            .buffer()
 9565            .read(cx)
 9566            .excerpt_containing(selection.start, cx)
 9567        else {
 9568            return;
 9569        };
 9570        let Some((_, end_buffer, _)) = self.buffer().read(cx).excerpt_containing(selection.end, cx)
 9571        else {
 9572            return;
 9573        };
 9574        if buffer != end_buffer {
 9575            log::error!("expected anchor range to have matching buffer IDs");
 9576            return;
 9577        }
 9578
 9579        let id = post_inc(&mut self.next_completion_id);
 9580        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9581        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9582            CompletionsMenu::new_snippet_choices(
 9583                id,
 9584                true,
 9585                choices,
 9586                selection,
 9587                buffer,
 9588                snippet_sort_order,
 9589            ),
 9590        ));
 9591    }
 9592
 9593    pub fn insert_snippet(
 9594        &mut self,
 9595        insertion_ranges: &[Range<usize>],
 9596        snippet: Snippet,
 9597        window: &mut Window,
 9598        cx: &mut Context<Self>,
 9599    ) -> Result<()> {
 9600        struct Tabstop<T> {
 9601            is_end_tabstop: bool,
 9602            ranges: Vec<Range<T>>,
 9603            choices: Option<Vec<String>>,
 9604        }
 9605
 9606        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9607            let snippet_text: Arc<str> = snippet.text.clone().into();
 9608            let edits = insertion_ranges
 9609                .iter()
 9610                .cloned()
 9611                .map(|range| (range, snippet_text.clone()));
 9612            let autoindent_mode = AutoindentMode::Block {
 9613                original_indent_columns: Vec::new(),
 9614            };
 9615            buffer.edit(edits, Some(autoindent_mode), cx);
 9616
 9617            let snapshot = &*buffer.read(cx);
 9618            let snippet = &snippet;
 9619            snippet
 9620                .tabstops
 9621                .iter()
 9622                .map(|tabstop| {
 9623                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
 9624                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9625                    });
 9626                    let mut tabstop_ranges = tabstop
 9627                        .ranges
 9628                        .iter()
 9629                        .flat_map(|tabstop_range| {
 9630                            let mut delta = 0_isize;
 9631                            insertion_ranges.iter().map(move |insertion_range| {
 9632                                let insertion_start = insertion_range.start as isize + delta;
 9633                                delta +=
 9634                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9635
 9636                                let start = ((insertion_start + tabstop_range.start) as usize)
 9637                                    .min(snapshot.len());
 9638                                let end = ((insertion_start + tabstop_range.end) as usize)
 9639                                    .min(snapshot.len());
 9640                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9641                            })
 9642                        })
 9643                        .collect::<Vec<_>>();
 9644                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9645
 9646                    Tabstop {
 9647                        is_end_tabstop,
 9648                        ranges: tabstop_ranges,
 9649                        choices: tabstop.choices.clone(),
 9650                    }
 9651                })
 9652                .collect::<Vec<_>>()
 9653        });
 9654        if let Some(tabstop) = tabstops.first() {
 9655            self.change_selections(Default::default(), window, cx, |s| {
 9656                // Reverse order so that the first range is the newest created selection.
 9657                // Completions will use it and autoscroll will prioritize it.
 9658                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9659            });
 9660
 9661            if let Some(choices) = &tabstop.choices
 9662                && let Some(selection) = tabstop.ranges.first()
 9663            {
 9664                self.show_snippet_choices(choices, selection.clone(), cx)
 9665            }
 9666
 9667            // If we're already at the last tabstop and it's at the end of the snippet,
 9668            // we're done, we don't need to keep the state around.
 9669            if !tabstop.is_end_tabstop {
 9670                let choices = tabstops
 9671                    .iter()
 9672                    .map(|tabstop| tabstop.choices.clone())
 9673                    .collect();
 9674
 9675                let ranges = tabstops
 9676                    .into_iter()
 9677                    .map(|tabstop| tabstop.ranges)
 9678                    .collect::<Vec<_>>();
 9679
 9680                self.snippet_stack.push(SnippetState {
 9681                    active_index: 0,
 9682                    ranges,
 9683                    choices,
 9684                });
 9685            }
 9686
 9687            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9688            if self.autoclose_regions.is_empty() {
 9689                let snapshot = self.buffer.read(cx).snapshot(cx);
 9690                for selection in &mut self.selections.all::<Point>(&self.display_snapshot(cx)) {
 9691                    let selection_head = selection.head();
 9692                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9693                        continue;
 9694                    };
 9695
 9696                    let mut bracket_pair = None;
 9697                    let max_lookup_length = scope
 9698                        .brackets()
 9699                        .map(|(pair, _)| {
 9700                            pair.start
 9701                                .as_str()
 9702                                .chars()
 9703                                .count()
 9704                                .max(pair.end.as_str().chars().count())
 9705                        })
 9706                        .max();
 9707                    if let Some(max_lookup_length) = max_lookup_length {
 9708                        let next_text = snapshot
 9709                            .chars_at(selection_head)
 9710                            .take(max_lookup_length)
 9711                            .collect::<String>();
 9712                        let prev_text = snapshot
 9713                            .reversed_chars_at(selection_head)
 9714                            .take(max_lookup_length)
 9715                            .collect::<String>();
 9716
 9717                        for (pair, enabled) in scope.brackets() {
 9718                            if enabled
 9719                                && pair.close
 9720                                && prev_text.starts_with(pair.start.as_str())
 9721                                && next_text.starts_with(pair.end.as_str())
 9722                            {
 9723                                bracket_pair = Some(pair.clone());
 9724                                break;
 9725                            }
 9726                        }
 9727                    }
 9728
 9729                    if let Some(pair) = bracket_pair {
 9730                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9731                        let autoclose_enabled =
 9732                            self.use_autoclose && snapshot_settings.use_autoclose;
 9733                        if autoclose_enabled {
 9734                            let start = snapshot.anchor_after(selection_head);
 9735                            let end = snapshot.anchor_after(selection_head);
 9736                            self.autoclose_regions.push(AutocloseRegion {
 9737                                selection_id: selection.id,
 9738                                range: start..end,
 9739                                pair,
 9740                            });
 9741                        }
 9742                    }
 9743                }
 9744            }
 9745        }
 9746        Ok(())
 9747    }
 9748
 9749    pub fn move_to_next_snippet_tabstop(
 9750        &mut self,
 9751        window: &mut Window,
 9752        cx: &mut Context<Self>,
 9753    ) -> bool {
 9754        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9755    }
 9756
 9757    pub fn move_to_prev_snippet_tabstop(
 9758        &mut self,
 9759        window: &mut Window,
 9760        cx: &mut Context<Self>,
 9761    ) -> bool {
 9762        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9763    }
 9764
 9765    pub fn move_to_snippet_tabstop(
 9766        &mut self,
 9767        bias: Bias,
 9768        window: &mut Window,
 9769        cx: &mut Context<Self>,
 9770    ) -> bool {
 9771        if let Some(mut snippet) = self.snippet_stack.pop() {
 9772            match bias {
 9773                Bias::Left => {
 9774                    if snippet.active_index > 0 {
 9775                        snippet.active_index -= 1;
 9776                    } else {
 9777                        self.snippet_stack.push(snippet);
 9778                        return false;
 9779                    }
 9780                }
 9781                Bias::Right => {
 9782                    if snippet.active_index + 1 < snippet.ranges.len() {
 9783                        snippet.active_index += 1;
 9784                    } else {
 9785                        self.snippet_stack.push(snippet);
 9786                        return false;
 9787                    }
 9788                }
 9789            }
 9790            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9791                self.change_selections(Default::default(), window, cx, |s| {
 9792                    // Reverse order so that the first range is the newest created selection.
 9793                    // Completions will use it and autoscroll will prioritize it.
 9794                    s.select_ranges(current_ranges.iter().rev().cloned())
 9795                });
 9796
 9797                if let Some(choices) = &snippet.choices[snippet.active_index]
 9798                    && let Some(selection) = current_ranges.first()
 9799                {
 9800                    self.show_snippet_choices(choices, selection.clone(), cx);
 9801                }
 9802
 9803                // If snippet state is not at the last tabstop, push it back on the stack
 9804                if snippet.active_index + 1 < snippet.ranges.len() {
 9805                    self.snippet_stack.push(snippet);
 9806                }
 9807                return true;
 9808            }
 9809        }
 9810
 9811        false
 9812    }
 9813
 9814    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9815        self.transact(window, cx, |this, window, cx| {
 9816            this.select_all(&SelectAll, window, cx);
 9817            this.insert("", window, cx);
 9818        });
 9819    }
 9820
 9821    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9822        if self.read_only(cx) {
 9823            return;
 9824        }
 9825        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9826        self.transact(window, cx, |this, window, cx| {
 9827            this.select_autoclose_pair(window, cx);
 9828
 9829            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9830
 9831            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9832            if !this.linked_edit_ranges.is_empty() {
 9833                let selections = this.selections.all::<MultiBufferPoint>(&display_map);
 9834                let snapshot = this.buffer.read(cx).snapshot(cx);
 9835
 9836                for selection in selections.iter() {
 9837                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9838                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9839                    if selection_start.buffer_id != selection_end.buffer_id {
 9840                        continue;
 9841                    }
 9842                    if let Some(ranges) =
 9843                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9844                    {
 9845                        for (buffer, entries) in ranges {
 9846                            linked_ranges.entry(buffer).or_default().extend(entries);
 9847                        }
 9848                    }
 9849                }
 9850            }
 9851
 9852            let mut selections = this.selections.all::<MultiBufferPoint>(&display_map);
 9853            for selection in &mut selections {
 9854                if selection.is_empty() {
 9855                    let old_head = selection.head();
 9856                    let mut new_head =
 9857                        movement::left(&display_map, old_head.to_display_point(&display_map))
 9858                            .to_point(&display_map);
 9859                    if let Some((buffer, line_buffer_range)) = display_map
 9860                        .buffer_snapshot()
 9861                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 9862                    {
 9863                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 9864                        let indent_len = match indent_size.kind {
 9865                            IndentKind::Space => {
 9866                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 9867                            }
 9868                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 9869                        };
 9870                        if old_head.column <= indent_size.len && old_head.column > 0 {
 9871                            let indent_len = indent_len.get();
 9872                            new_head = cmp::min(
 9873                                new_head,
 9874                                MultiBufferPoint::new(
 9875                                    old_head.row,
 9876                                    ((old_head.column - 1) / indent_len) * indent_len,
 9877                                ),
 9878                            );
 9879                        }
 9880                    }
 9881
 9882                    selection.set_head(new_head, SelectionGoal::None);
 9883                }
 9884            }
 9885
 9886            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9887            this.insert("", window, cx);
 9888            let empty_str: Arc<str> = Arc::from("");
 9889            for (buffer, edits) in linked_ranges {
 9890                let snapshot = buffer.read(cx).snapshot();
 9891                use text::ToPoint as TP;
 9892
 9893                let edits = edits
 9894                    .into_iter()
 9895                    .map(|range| {
 9896                        let end_point = TP::to_point(&range.end, &snapshot);
 9897                        let mut start_point = TP::to_point(&range.start, &snapshot);
 9898
 9899                        if end_point == start_point {
 9900                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 9901                                .saturating_sub(1);
 9902                            start_point =
 9903                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 9904                        };
 9905
 9906                        (start_point..end_point, empty_str.clone())
 9907                    })
 9908                    .sorted_by_key(|(range, _)| range.start)
 9909                    .collect::<Vec<_>>();
 9910                buffer.update(cx, |this, cx| {
 9911                    this.edit(edits, None, cx);
 9912                })
 9913            }
 9914            this.refresh_edit_prediction(true, false, window, cx);
 9915            refresh_linked_ranges(this, window, cx);
 9916        });
 9917    }
 9918
 9919    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 9920        if self.read_only(cx) {
 9921            return;
 9922        }
 9923        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9924        self.transact(window, cx, |this, window, cx| {
 9925            this.change_selections(Default::default(), window, cx, |s| {
 9926                s.move_with(|map, selection| {
 9927                    if selection.is_empty() {
 9928                        let cursor = movement::right(map, selection.head());
 9929                        selection.end = cursor;
 9930                        selection.reversed = true;
 9931                        selection.goal = SelectionGoal::None;
 9932                    }
 9933                })
 9934            });
 9935            this.insert("", window, cx);
 9936            this.refresh_edit_prediction(true, false, window, cx);
 9937        });
 9938    }
 9939
 9940    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 9941        if self.mode.is_single_line() {
 9942            cx.propagate();
 9943            return;
 9944        }
 9945
 9946        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9947        if self.move_to_prev_snippet_tabstop(window, cx) {
 9948            return;
 9949        }
 9950        self.outdent(&Outdent, window, cx);
 9951    }
 9952
 9953    pub fn next_snippet_tabstop(
 9954        &mut self,
 9955        _: &NextSnippetTabstop,
 9956        window: &mut Window,
 9957        cx: &mut Context<Self>,
 9958    ) {
 9959        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
 9960            return;
 9961        }
 9962
 9963        if self.move_to_next_snippet_tabstop(window, cx) {
 9964            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9965            return;
 9966        }
 9967    }
 9968
 9969    pub fn previous_snippet_tabstop(
 9970        &mut self,
 9971        _: &PreviousSnippetTabstop,
 9972        window: &mut Window,
 9973        cx: &mut Context<Self>,
 9974    ) {
 9975        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
 9976            return;
 9977        }
 9978
 9979        if self.move_to_prev_snippet_tabstop(window, cx) {
 9980            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9981            return;
 9982        }
 9983    }
 9984
 9985    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 9986        if self.mode.is_single_line() {
 9987            cx.propagate();
 9988            return;
 9989        }
 9990
 9991        if self.move_to_next_snippet_tabstop(window, cx) {
 9992            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9993            return;
 9994        }
 9995        if self.read_only(cx) {
 9996            return;
 9997        }
 9998        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9999        let mut selections = self.selections.all_adjusted(&self.display_snapshot(cx));
10000        let buffer = self.buffer.read(cx);
10001        let snapshot = buffer.snapshot(cx);
10002        let rows_iter = selections.iter().map(|s| s.head().row);
10003        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
10004
10005        let has_some_cursor_in_whitespace = selections
10006            .iter()
10007            .filter(|selection| selection.is_empty())
10008            .any(|selection| {
10009                let cursor = selection.head();
10010                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10011                cursor.column < current_indent.len
10012            });
10013
10014        let mut edits = Vec::new();
10015        let mut prev_edited_row = 0;
10016        let mut row_delta = 0;
10017        for selection in &mut selections {
10018            if selection.start.row != prev_edited_row {
10019                row_delta = 0;
10020            }
10021            prev_edited_row = selection.end.row;
10022
10023            // If the selection is non-empty, then increase the indentation of the selected lines.
10024            if !selection.is_empty() {
10025                row_delta =
10026                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10027                continue;
10028            }
10029
10030            let cursor = selection.head();
10031            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10032            if let Some(suggested_indent) =
10033                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
10034            {
10035                // Don't do anything if already at suggested indent
10036                // and there is any other cursor which is not
10037                if has_some_cursor_in_whitespace
10038                    && cursor.column == current_indent.len
10039                    && current_indent.len == suggested_indent.len
10040                {
10041                    continue;
10042                }
10043
10044                // Adjust line and move cursor to suggested indent
10045                // if cursor is not at suggested indent
10046                if cursor.column < suggested_indent.len
10047                    && cursor.column <= current_indent.len
10048                    && current_indent.len <= suggested_indent.len
10049                {
10050                    selection.start = Point::new(cursor.row, suggested_indent.len);
10051                    selection.end = selection.start;
10052                    if row_delta == 0 {
10053                        edits.extend(Buffer::edit_for_indent_size_adjustment(
10054                            cursor.row,
10055                            current_indent,
10056                            suggested_indent,
10057                        ));
10058                        row_delta = suggested_indent.len - current_indent.len;
10059                    }
10060                    continue;
10061                }
10062
10063                // If current indent is more than suggested indent
10064                // only move cursor to current indent and skip indent
10065                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
10066                    selection.start = Point::new(cursor.row, current_indent.len);
10067                    selection.end = selection.start;
10068                    continue;
10069                }
10070            }
10071
10072            // Otherwise, insert a hard or soft tab.
10073            let settings = buffer.language_settings_at(cursor, cx);
10074            let tab_size = if settings.hard_tabs {
10075                IndentSize::tab()
10076            } else {
10077                let tab_size = settings.tab_size.get();
10078                let indent_remainder = snapshot
10079                    .text_for_range(Point::new(cursor.row, 0)..cursor)
10080                    .flat_map(str::chars)
10081                    .fold(row_delta % tab_size, |counter: u32, c| {
10082                        if c == '\t' {
10083                            0
10084                        } else {
10085                            (counter + 1) % tab_size
10086                        }
10087                    });
10088
10089                let chars_to_next_tab_stop = tab_size - indent_remainder;
10090                IndentSize::spaces(chars_to_next_tab_stop)
10091            };
10092            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
10093            selection.end = selection.start;
10094            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
10095            row_delta += tab_size.len;
10096        }
10097
10098        self.transact(window, cx, |this, window, cx| {
10099            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10100            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10101            this.refresh_edit_prediction(true, false, window, cx);
10102        });
10103    }
10104
10105    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10106        if self.read_only(cx) {
10107            return;
10108        }
10109        if self.mode.is_single_line() {
10110            cx.propagate();
10111            return;
10112        }
10113
10114        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10115        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
10116        let mut prev_edited_row = 0;
10117        let mut row_delta = 0;
10118        let mut edits = Vec::new();
10119        let buffer = self.buffer.read(cx);
10120        let snapshot = buffer.snapshot(cx);
10121        for selection in &mut selections {
10122            if selection.start.row != prev_edited_row {
10123                row_delta = 0;
10124            }
10125            prev_edited_row = selection.end.row;
10126
10127            row_delta =
10128                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10129        }
10130
10131        self.transact(window, cx, |this, window, cx| {
10132            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10133            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10134        });
10135    }
10136
10137    fn indent_selection(
10138        buffer: &MultiBuffer,
10139        snapshot: &MultiBufferSnapshot,
10140        selection: &mut Selection<Point>,
10141        edits: &mut Vec<(Range<Point>, String)>,
10142        delta_for_start_row: u32,
10143        cx: &App,
10144    ) -> u32 {
10145        let settings = buffer.language_settings_at(selection.start, cx);
10146        let tab_size = settings.tab_size.get();
10147        let indent_kind = if settings.hard_tabs {
10148            IndentKind::Tab
10149        } else {
10150            IndentKind::Space
10151        };
10152        let mut start_row = selection.start.row;
10153        let mut end_row = selection.end.row + 1;
10154
10155        // If a selection ends at the beginning of a line, don't indent
10156        // that last line.
10157        if selection.end.column == 0 && selection.end.row > selection.start.row {
10158            end_row -= 1;
10159        }
10160
10161        // Avoid re-indenting a row that has already been indented by a
10162        // previous selection, but still update this selection's column
10163        // to reflect that indentation.
10164        if delta_for_start_row > 0 {
10165            start_row += 1;
10166            selection.start.column += delta_for_start_row;
10167            if selection.end.row == selection.start.row {
10168                selection.end.column += delta_for_start_row;
10169            }
10170        }
10171
10172        let mut delta_for_end_row = 0;
10173        let has_multiple_rows = start_row + 1 != end_row;
10174        for row in start_row..end_row {
10175            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10176            let indent_delta = match (current_indent.kind, indent_kind) {
10177                (IndentKind::Space, IndentKind::Space) => {
10178                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10179                    IndentSize::spaces(columns_to_next_tab_stop)
10180                }
10181                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10182                (_, IndentKind::Tab) => IndentSize::tab(),
10183            };
10184
10185            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10186                0
10187            } else {
10188                selection.start.column
10189            };
10190            let row_start = Point::new(row, start);
10191            edits.push((
10192                row_start..row_start,
10193                indent_delta.chars().collect::<String>(),
10194            ));
10195
10196            // Update this selection's endpoints to reflect the indentation.
10197            if row == selection.start.row {
10198                selection.start.column += indent_delta.len;
10199            }
10200            if row == selection.end.row {
10201                selection.end.column += indent_delta.len;
10202                delta_for_end_row = indent_delta.len;
10203            }
10204        }
10205
10206        if selection.start.row == selection.end.row {
10207            delta_for_start_row + delta_for_end_row
10208        } else {
10209            delta_for_end_row
10210        }
10211    }
10212
10213    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10214        if self.read_only(cx) {
10215            return;
10216        }
10217        if self.mode.is_single_line() {
10218            cx.propagate();
10219            return;
10220        }
10221
10222        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10223        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10224        let selections = self.selections.all::<Point>(&display_map);
10225        let mut deletion_ranges = Vec::new();
10226        let mut last_outdent = None;
10227        {
10228            let buffer = self.buffer.read(cx);
10229            let snapshot = buffer.snapshot(cx);
10230            for selection in &selections {
10231                let settings = buffer.language_settings_at(selection.start, cx);
10232                let tab_size = settings.tab_size.get();
10233                let mut rows = selection.spanned_rows(false, &display_map);
10234
10235                // Avoid re-outdenting a row that has already been outdented by a
10236                // previous selection.
10237                if let Some(last_row) = last_outdent
10238                    && last_row == rows.start
10239                {
10240                    rows.start = rows.start.next_row();
10241                }
10242                let has_multiple_rows = rows.len() > 1;
10243                for row in rows.iter_rows() {
10244                    let indent_size = snapshot.indent_size_for_line(row);
10245                    if indent_size.len > 0 {
10246                        let deletion_len = match indent_size.kind {
10247                            IndentKind::Space => {
10248                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10249                                if columns_to_prev_tab_stop == 0 {
10250                                    tab_size
10251                                } else {
10252                                    columns_to_prev_tab_stop
10253                                }
10254                            }
10255                            IndentKind::Tab => 1,
10256                        };
10257                        let start = if has_multiple_rows
10258                            || deletion_len > selection.start.column
10259                            || indent_size.len < selection.start.column
10260                        {
10261                            0
10262                        } else {
10263                            selection.start.column - deletion_len
10264                        };
10265                        deletion_ranges.push(
10266                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10267                        );
10268                        last_outdent = Some(row);
10269                    }
10270                }
10271            }
10272        }
10273
10274        self.transact(window, cx, |this, window, cx| {
10275            this.buffer.update(cx, |buffer, cx| {
10276                let empty_str: Arc<str> = Arc::default();
10277                buffer.edit(
10278                    deletion_ranges
10279                        .into_iter()
10280                        .map(|range| (range, empty_str.clone())),
10281                    None,
10282                    cx,
10283                );
10284            });
10285            let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
10286            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10287        });
10288    }
10289
10290    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10291        if self.read_only(cx) {
10292            return;
10293        }
10294        if self.mode.is_single_line() {
10295            cx.propagate();
10296            return;
10297        }
10298
10299        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10300        let selections = self
10301            .selections
10302            .all::<usize>(&self.display_snapshot(cx))
10303            .into_iter()
10304            .map(|s| s.range());
10305
10306        self.transact(window, cx, |this, window, cx| {
10307            this.buffer.update(cx, |buffer, cx| {
10308                buffer.autoindent_ranges(selections, cx);
10309            });
10310            let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
10311            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10312        });
10313    }
10314
10315    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10316        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10317        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10318        let selections = self.selections.all::<Point>(&display_map);
10319
10320        let mut new_cursors = Vec::new();
10321        let mut edit_ranges = Vec::new();
10322        let mut selections = selections.iter().peekable();
10323        while let Some(selection) = selections.next() {
10324            let mut rows = selection.spanned_rows(false, &display_map);
10325
10326            // Accumulate contiguous regions of rows that we want to delete.
10327            while let Some(next_selection) = selections.peek() {
10328                let next_rows = next_selection.spanned_rows(false, &display_map);
10329                if next_rows.start <= rows.end {
10330                    rows.end = next_rows.end;
10331                    selections.next().unwrap();
10332                } else {
10333                    break;
10334                }
10335            }
10336
10337            let buffer = display_map.buffer_snapshot();
10338            let mut edit_start = ToOffset::to_offset(&Point::new(rows.start.0, 0), buffer);
10339            let (edit_end, target_row) = if buffer.max_point().row >= rows.end.0 {
10340                // If there's a line after the range, delete the \n from the end of the row range
10341                (
10342                    ToOffset::to_offset(&Point::new(rows.end.0, 0), buffer),
10343                    rows.end,
10344                )
10345            } else {
10346                // If there isn't a line after the range, delete the \n from the line before the
10347                // start of the row range
10348                edit_start = edit_start.saturating_sub(1);
10349                (buffer.len(), rows.start.previous_row())
10350            };
10351
10352            let text_layout_details = self.text_layout_details(window);
10353            let x = display_map.x_for_display_point(
10354                selection.head().to_display_point(&display_map),
10355                &text_layout_details,
10356            );
10357            let row = Point::new(target_row.0, 0)
10358                .to_display_point(&display_map)
10359                .row();
10360            let column = display_map.display_column_for_x(row, x, &text_layout_details);
10361
10362            new_cursors.push((
10363                selection.id,
10364                buffer.anchor_after(DisplayPoint::new(row, column).to_point(&display_map)),
10365                SelectionGoal::None,
10366            ));
10367            edit_ranges.push(edit_start..edit_end);
10368        }
10369
10370        self.transact(window, cx, |this, window, cx| {
10371            let buffer = this.buffer.update(cx, |buffer, cx| {
10372                let empty_str: Arc<str> = Arc::default();
10373                buffer.edit(
10374                    edit_ranges
10375                        .into_iter()
10376                        .map(|range| (range, empty_str.clone())),
10377                    None,
10378                    cx,
10379                );
10380                buffer.snapshot(cx)
10381            });
10382            let new_selections = new_cursors
10383                .into_iter()
10384                .map(|(id, cursor, goal)| {
10385                    let cursor = cursor.to_point(&buffer);
10386                    Selection {
10387                        id,
10388                        start: cursor,
10389                        end: cursor,
10390                        reversed: false,
10391                        goal,
10392                    }
10393                })
10394                .collect();
10395
10396            this.change_selections(Default::default(), window, cx, |s| {
10397                s.select(new_selections);
10398            });
10399        });
10400    }
10401
10402    pub fn join_lines_impl(
10403        &mut self,
10404        insert_whitespace: bool,
10405        window: &mut Window,
10406        cx: &mut Context<Self>,
10407    ) {
10408        if self.read_only(cx) {
10409            return;
10410        }
10411        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10412        for selection in self.selections.all::<Point>(&self.display_snapshot(cx)) {
10413            let start = MultiBufferRow(selection.start.row);
10414            // Treat single line selections as if they include the next line. Otherwise this action
10415            // would do nothing for single line selections individual cursors.
10416            let end = if selection.start.row == selection.end.row {
10417                MultiBufferRow(selection.start.row + 1)
10418            } else {
10419                MultiBufferRow(selection.end.row)
10420            };
10421
10422            if let Some(last_row_range) = row_ranges.last_mut()
10423                && start <= last_row_range.end
10424            {
10425                last_row_range.end = end;
10426                continue;
10427            }
10428            row_ranges.push(start..end);
10429        }
10430
10431        let snapshot = self.buffer.read(cx).snapshot(cx);
10432        let mut cursor_positions = Vec::new();
10433        for row_range in &row_ranges {
10434            let anchor = snapshot.anchor_before(Point::new(
10435                row_range.end.previous_row().0,
10436                snapshot.line_len(row_range.end.previous_row()),
10437            ));
10438            cursor_positions.push(anchor..anchor);
10439        }
10440
10441        self.transact(window, cx, |this, window, cx| {
10442            for row_range in row_ranges.into_iter().rev() {
10443                for row in row_range.iter_rows().rev() {
10444                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10445                    let next_line_row = row.next_row();
10446                    let indent = snapshot.indent_size_for_line(next_line_row);
10447                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10448
10449                    let replace =
10450                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10451                            " "
10452                        } else {
10453                            ""
10454                        };
10455
10456                    this.buffer.update(cx, |buffer, cx| {
10457                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10458                    });
10459                }
10460            }
10461
10462            this.change_selections(Default::default(), window, cx, |s| {
10463                s.select_anchor_ranges(cursor_positions)
10464            });
10465        });
10466    }
10467
10468    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10469        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10470        self.join_lines_impl(true, window, cx);
10471    }
10472
10473    pub fn sort_lines_case_sensitive(
10474        &mut self,
10475        _: &SortLinesCaseSensitive,
10476        window: &mut Window,
10477        cx: &mut Context<Self>,
10478    ) {
10479        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10480    }
10481
10482    pub fn sort_lines_by_length(
10483        &mut self,
10484        _: &SortLinesByLength,
10485        window: &mut Window,
10486        cx: &mut Context<Self>,
10487    ) {
10488        self.manipulate_immutable_lines(window, cx, |lines| {
10489            lines.sort_by_key(|&line| line.chars().count())
10490        })
10491    }
10492
10493    pub fn sort_lines_case_insensitive(
10494        &mut self,
10495        _: &SortLinesCaseInsensitive,
10496        window: &mut Window,
10497        cx: &mut Context<Self>,
10498    ) {
10499        self.manipulate_immutable_lines(window, cx, |lines| {
10500            lines.sort_by_key(|line| line.to_lowercase())
10501        })
10502    }
10503
10504    pub fn unique_lines_case_insensitive(
10505        &mut self,
10506        _: &UniqueLinesCaseInsensitive,
10507        window: &mut Window,
10508        cx: &mut Context<Self>,
10509    ) {
10510        self.manipulate_immutable_lines(window, cx, |lines| {
10511            let mut seen = HashSet::default();
10512            lines.retain(|line| seen.insert(line.to_lowercase()));
10513        })
10514    }
10515
10516    pub fn unique_lines_case_sensitive(
10517        &mut self,
10518        _: &UniqueLinesCaseSensitive,
10519        window: &mut Window,
10520        cx: &mut Context<Self>,
10521    ) {
10522        self.manipulate_immutable_lines(window, cx, |lines| {
10523            let mut seen = HashSet::default();
10524            lines.retain(|line| seen.insert(*line));
10525        })
10526    }
10527
10528    fn enable_wrap_selections_in_tag(&self, cx: &App) -> bool {
10529        let snapshot = self.buffer.read(cx).snapshot(cx);
10530        for selection in self.selections.disjoint_anchors_arc().iter() {
10531            if snapshot
10532                .language_at(selection.start)
10533                .and_then(|lang| lang.config().wrap_characters.as_ref())
10534                .is_some()
10535            {
10536                return true;
10537            }
10538        }
10539        false
10540    }
10541
10542    fn wrap_selections_in_tag(
10543        &mut self,
10544        _: &WrapSelectionsInTag,
10545        window: &mut Window,
10546        cx: &mut Context<Self>,
10547    ) {
10548        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10549
10550        let snapshot = self.buffer.read(cx).snapshot(cx);
10551
10552        let mut edits = Vec::new();
10553        let mut boundaries = Vec::new();
10554
10555        for selection in self
10556            .selections
10557            .all_adjusted(&self.display_snapshot(cx))
10558            .iter()
10559        {
10560            let Some(wrap_config) = snapshot
10561                .language_at(selection.start)
10562                .and_then(|lang| lang.config().wrap_characters.clone())
10563            else {
10564                continue;
10565            };
10566
10567            let open_tag = format!("{}{}", wrap_config.start_prefix, wrap_config.start_suffix);
10568            let close_tag = format!("{}{}", wrap_config.end_prefix, wrap_config.end_suffix);
10569
10570            let start_before = snapshot.anchor_before(selection.start);
10571            let end_after = snapshot.anchor_after(selection.end);
10572
10573            edits.push((start_before..start_before, open_tag));
10574            edits.push((end_after..end_after, close_tag));
10575
10576            boundaries.push((
10577                start_before,
10578                end_after,
10579                wrap_config.start_prefix.len(),
10580                wrap_config.end_suffix.len(),
10581            ));
10582        }
10583
10584        if edits.is_empty() {
10585            return;
10586        }
10587
10588        self.transact(window, cx, |this, window, cx| {
10589            let buffer = this.buffer.update(cx, |buffer, cx| {
10590                buffer.edit(edits, None, cx);
10591                buffer.snapshot(cx)
10592            });
10593
10594            let mut new_selections = Vec::with_capacity(boundaries.len() * 2);
10595            for (start_before, end_after, start_prefix_len, end_suffix_len) in
10596                boundaries.into_iter()
10597            {
10598                let open_offset = start_before.to_offset(&buffer) + start_prefix_len;
10599                let close_offset = end_after.to_offset(&buffer).saturating_sub(end_suffix_len);
10600                new_selections.push(open_offset..open_offset);
10601                new_selections.push(close_offset..close_offset);
10602            }
10603
10604            this.change_selections(Default::default(), window, cx, |s| {
10605                s.select_ranges(new_selections);
10606            });
10607
10608            this.request_autoscroll(Autoscroll::fit(), cx);
10609        });
10610    }
10611
10612    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10613        let Some(project) = self.project.clone() else {
10614            return;
10615        };
10616        self.reload(project, window, cx)
10617            .detach_and_notify_err(window, cx);
10618    }
10619
10620    pub fn restore_file(
10621        &mut self,
10622        _: &::git::RestoreFile,
10623        window: &mut Window,
10624        cx: &mut Context<Self>,
10625    ) {
10626        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10627        let mut buffer_ids = HashSet::default();
10628        let snapshot = self.buffer().read(cx).snapshot(cx);
10629        for selection in self.selections.all::<usize>(&self.display_snapshot(cx)) {
10630            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10631        }
10632
10633        let buffer = self.buffer().read(cx);
10634        let ranges = buffer_ids
10635            .into_iter()
10636            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10637            .collect::<Vec<_>>();
10638
10639        self.restore_hunks_in_ranges(ranges, window, cx);
10640    }
10641
10642    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10643        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10644        let selections = self
10645            .selections
10646            .all(&self.display_snapshot(cx))
10647            .into_iter()
10648            .map(|s| s.range())
10649            .collect();
10650        self.restore_hunks_in_ranges(selections, window, cx);
10651    }
10652
10653    pub fn restore_hunks_in_ranges(
10654        &mut self,
10655        ranges: Vec<Range<Point>>,
10656        window: &mut Window,
10657        cx: &mut Context<Editor>,
10658    ) {
10659        let mut revert_changes = HashMap::default();
10660        let chunk_by = self
10661            .snapshot(window, cx)
10662            .hunks_for_ranges(ranges)
10663            .into_iter()
10664            .chunk_by(|hunk| hunk.buffer_id);
10665        for (buffer_id, hunks) in &chunk_by {
10666            let hunks = hunks.collect::<Vec<_>>();
10667            for hunk in &hunks {
10668                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10669            }
10670            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10671        }
10672        drop(chunk_by);
10673        if !revert_changes.is_empty() {
10674            self.transact(window, cx, |editor, window, cx| {
10675                editor.restore(revert_changes, window, cx);
10676            });
10677        }
10678    }
10679
10680    pub fn status_for_buffer_id(&self, buffer_id: BufferId, cx: &App) -> Option<FileStatus> {
10681        if let Some(status) = self
10682            .addons
10683            .iter()
10684            .find_map(|(_, addon)| addon.override_status_for_buffer_id(buffer_id, cx))
10685        {
10686            return Some(status);
10687        }
10688        self.project
10689            .as_ref()?
10690            .read(cx)
10691            .status_for_buffer_id(buffer_id, cx)
10692    }
10693
10694    pub fn open_active_item_in_terminal(
10695        &mut self,
10696        _: &OpenInTerminal,
10697        window: &mut Window,
10698        cx: &mut Context<Self>,
10699    ) {
10700        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10701            let project_path = buffer.read(cx).project_path(cx)?;
10702            let project = self.project()?.read(cx);
10703            let entry = project.entry_for_path(&project_path, cx)?;
10704            let parent = match &entry.canonical_path {
10705                Some(canonical_path) => canonical_path.to_path_buf(),
10706                None => project.absolute_path(&project_path, cx)?,
10707            }
10708            .parent()?
10709            .to_path_buf();
10710            Some(parent)
10711        }) {
10712            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10713        }
10714    }
10715
10716    fn set_breakpoint_context_menu(
10717        &mut self,
10718        display_row: DisplayRow,
10719        position: Option<Anchor>,
10720        clicked_point: gpui::Point<Pixels>,
10721        window: &mut Window,
10722        cx: &mut Context<Self>,
10723    ) {
10724        let source = self
10725            .buffer
10726            .read(cx)
10727            .snapshot(cx)
10728            .anchor_before(Point::new(display_row.0, 0u32));
10729
10730        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10731
10732        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10733            self,
10734            source,
10735            clicked_point,
10736            context_menu,
10737            window,
10738            cx,
10739        );
10740    }
10741
10742    fn add_edit_breakpoint_block(
10743        &mut self,
10744        anchor: Anchor,
10745        breakpoint: &Breakpoint,
10746        edit_action: BreakpointPromptEditAction,
10747        window: &mut Window,
10748        cx: &mut Context<Self>,
10749    ) {
10750        let weak_editor = cx.weak_entity();
10751        let bp_prompt = cx.new(|cx| {
10752            BreakpointPromptEditor::new(
10753                weak_editor,
10754                anchor,
10755                breakpoint.clone(),
10756                edit_action,
10757                window,
10758                cx,
10759            )
10760        });
10761
10762        let height = bp_prompt.update(cx, |this, cx| {
10763            this.prompt
10764                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10765        });
10766        let cloned_prompt = bp_prompt.clone();
10767        let blocks = vec![BlockProperties {
10768            style: BlockStyle::Sticky,
10769            placement: BlockPlacement::Above(anchor),
10770            height: Some(height),
10771            render: Arc::new(move |cx| {
10772                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10773                cloned_prompt.clone().into_any_element()
10774            }),
10775            priority: 0,
10776        }];
10777
10778        let focus_handle = bp_prompt.focus_handle(cx);
10779        window.focus(&focus_handle);
10780
10781        let block_ids = self.insert_blocks(blocks, None, cx);
10782        bp_prompt.update(cx, |prompt, _| {
10783            prompt.add_block_ids(block_ids);
10784        });
10785    }
10786
10787    pub(crate) fn breakpoint_at_row(
10788        &self,
10789        row: u32,
10790        window: &mut Window,
10791        cx: &mut Context<Self>,
10792    ) -> Option<(Anchor, Breakpoint)> {
10793        let snapshot = self.snapshot(window, cx);
10794        let breakpoint_position = snapshot.buffer_snapshot().anchor_before(Point::new(row, 0));
10795
10796        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10797    }
10798
10799    pub(crate) fn breakpoint_at_anchor(
10800        &self,
10801        breakpoint_position: Anchor,
10802        snapshot: &EditorSnapshot,
10803        cx: &mut Context<Self>,
10804    ) -> Option<(Anchor, Breakpoint)> {
10805        let buffer = self
10806            .buffer
10807            .read(cx)
10808            .buffer_for_anchor(breakpoint_position, cx)?;
10809
10810        let enclosing_excerpt = breakpoint_position.excerpt_id;
10811        let buffer_snapshot = buffer.read(cx).snapshot();
10812
10813        let row = buffer_snapshot
10814            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10815            .row;
10816
10817        let line_len = snapshot.buffer_snapshot().line_len(MultiBufferRow(row));
10818        let anchor_end = snapshot
10819            .buffer_snapshot()
10820            .anchor_after(Point::new(row, line_len));
10821
10822        self.breakpoint_store
10823            .as_ref()?
10824            .read_with(cx, |breakpoint_store, cx| {
10825                breakpoint_store
10826                    .breakpoints(
10827                        &buffer,
10828                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10829                        &buffer_snapshot,
10830                        cx,
10831                    )
10832                    .next()
10833                    .and_then(|(bp, _)| {
10834                        let breakpoint_row = buffer_snapshot
10835                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10836                            .row;
10837
10838                        if breakpoint_row == row {
10839                            snapshot
10840                                .buffer_snapshot()
10841                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10842                                .map(|position| (position, bp.bp.clone()))
10843                        } else {
10844                            None
10845                        }
10846                    })
10847            })
10848    }
10849
10850    pub fn edit_log_breakpoint(
10851        &mut self,
10852        _: &EditLogBreakpoint,
10853        window: &mut Window,
10854        cx: &mut Context<Self>,
10855    ) {
10856        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10857            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10858                message: None,
10859                state: BreakpointState::Enabled,
10860                condition: None,
10861                hit_condition: None,
10862            });
10863
10864            self.add_edit_breakpoint_block(
10865                anchor,
10866                &breakpoint,
10867                BreakpointPromptEditAction::Log,
10868                window,
10869                cx,
10870            );
10871        }
10872    }
10873
10874    fn breakpoints_at_cursors(
10875        &self,
10876        window: &mut Window,
10877        cx: &mut Context<Self>,
10878    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10879        let snapshot = self.snapshot(window, cx);
10880        let cursors = self
10881            .selections
10882            .disjoint_anchors_arc()
10883            .iter()
10884            .map(|selection| {
10885                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot());
10886
10887                let breakpoint_position = self
10888                    .breakpoint_at_row(cursor_position.row, window, cx)
10889                    .map(|bp| bp.0)
10890                    .unwrap_or_else(|| {
10891                        snapshot
10892                            .display_snapshot
10893                            .buffer_snapshot()
10894                            .anchor_after(Point::new(cursor_position.row, 0))
10895                    });
10896
10897                let breakpoint = self
10898                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10899                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
10900
10901                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
10902            })
10903            // 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.
10904            .collect::<HashMap<Anchor, _>>();
10905
10906        cursors.into_iter().collect()
10907    }
10908
10909    pub fn enable_breakpoint(
10910        &mut self,
10911        _: &crate::actions::EnableBreakpoint,
10912        window: &mut Window,
10913        cx: &mut Context<Self>,
10914    ) {
10915        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10916            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
10917                continue;
10918            };
10919            self.edit_breakpoint_at_anchor(
10920                anchor,
10921                breakpoint,
10922                BreakpointEditAction::InvertState,
10923                cx,
10924            );
10925        }
10926    }
10927
10928    pub fn disable_breakpoint(
10929        &mut self,
10930        _: &crate::actions::DisableBreakpoint,
10931        window: &mut Window,
10932        cx: &mut Context<Self>,
10933    ) {
10934        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10935            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
10936                continue;
10937            };
10938            self.edit_breakpoint_at_anchor(
10939                anchor,
10940                breakpoint,
10941                BreakpointEditAction::InvertState,
10942                cx,
10943            );
10944        }
10945    }
10946
10947    pub fn toggle_breakpoint(
10948        &mut self,
10949        _: &crate::actions::ToggleBreakpoint,
10950        window: &mut Window,
10951        cx: &mut Context<Self>,
10952    ) {
10953        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10954            if let Some(breakpoint) = breakpoint {
10955                self.edit_breakpoint_at_anchor(
10956                    anchor,
10957                    breakpoint,
10958                    BreakpointEditAction::Toggle,
10959                    cx,
10960                );
10961            } else {
10962                self.edit_breakpoint_at_anchor(
10963                    anchor,
10964                    Breakpoint::new_standard(),
10965                    BreakpointEditAction::Toggle,
10966                    cx,
10967                );
10968            }
10969        }
10970    }
10971
10972    pub fn edit_breakpoint_at_anchor(
10973        &mut self,
10974        breakpoint_position: Anchor,
10975        breakpoint: Breakpoint,
10976        edit_action: BreakpointEditAction,
10977        cx: &mut Context<Self>,
10978    ) {
10979        let Some(breakpoint_store) = &self.breakpoint_store else {
10980            return;
10981        };
10982
10983        let Some(buffer) = self
10984            .buffer
10985            .read(cx)
10986            .buffer_for_anchor(breakpoint_position, cx)
10987        else {
10988            return;
10989        };
10990
10991        breakpoint_store.update(cx, |breakpoint_store, cx| {
10992            breakpoint_store.toggle_breakpoint(
10993                buffer,
10994                BreakpointWithPosition {
10995                    position: breakpoint_position.text_anchor,
10996                    bp: breakpoint,
10997                },
10998                edit_action,
10999                cx,
11000            );
11001        });
11002
11003        cx.notify();
11004    }
11005
11006    #[cfg(any(test, feature = "test-support"))]
11007    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
11008        self.breakpoint_store.clone()
11009    }
11010
11011    pub fn prepare_restore_change(
11012        &self,
11013        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
11014        hunk: &MultiBufferDiffHunk,
11015        cx: &mut App,
11016    ) -> Option<()> {
11017        if hunk.is_created_file() {
11018            return None;
11019        }
11020        let buffer = self.buffer.read(cx);
11021        let diff = buffer.diff_for(hunk.buffer_id)?;
11022        let buffer = buffer.buffer(hunk.buffer_id)?;
11023        let buffer = buffer.read(cx);
11024        let original_text = diff
11025            .read(cx)
11026            .base_text()
11027            .as_rope()
11028            .slice(hunk.diff_base_byte_range.clone());
11029        let buffer_snapshot = buffer.snapshot();
11030        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
11031        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
11032            probe
11033                .0
11034                .start
11035                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
11036                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
11037        }) {
11038            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
11039            Some(())
11040        } else {
11041            None
11042        }
11043    }
11044
11045    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
11046        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
11047    }
11048
11049    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
11050        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut rand::rng()))
11051    }
11052
11053    fn manipulate_lines<M>(
11054        &mut self,
11055        window: &mut Window,
11056        cx: &mut Context<Self>,
11057        mut manipulate: M,
11058    ) where
11059        M: FnMut(&str) -> LineManipulationResult,
11060    {
11061        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11062
11063        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11064        let buffer = self.buffer.read(cx).snapshot(cx);
11065
11066        let mut edits = Vec::new();
11067
11068        let selections = self.selections.all::<Point>(&display_map);
11069        let mut selections = selections.iter().peekable();
11070        let mut contiguous_row_selections = Vec::new();
11071        let mut new_selections = Vec::new();
11072        let mut added_lines = 0;
11073        let mut removed_lines = 0;
11074
11075        while let Some(selection) = selections.next() {
11076            let (start_row, end_row) = consume_contiguous_rows(
11077                &mut contiguous_row_selections,
11078                selection,
11079                &display_map,
11080                &mut selections,
11081            );
11082
11083            let start_point = Point::new(start_row.0, 0);
11084            let end_point = Point::new(
11085                end_row.previous_row().0,
11086                buffer.line_len(end_row.previous_row()),
11087            );
11088            let text = buffer
11089                .text_for_range(start_point..end_point)
11090                .collect::<String>();
11091
11092            let LineManipulationResult {
11093                new_text,
11094                line_count_before,
11095                line_count_after,
11096            } = manipulate(&text);
11097
11098            edits.push((start_point..end_point, new_text));
11099
11100            // Selections must change based on added and removed line count
11101            let start_row =
11102                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
11103            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
11104            new_selections.push(Selection {
11105                id: selection.id,
11106                start: start_row,
11107                end: end_row,
11108                goal: SelectionGoal::None,
11109                reversed: selection.reversed,
11110            });
11111
11112            if line_count_after > line_count_before {
11113                added_lines += line_count_after - line_count_before;
11114            } else if line_count_before > line_count_after {
11115                removed_lines += line_count_before - line_count_after;
11116            }
11117        }
11118
11119        self.transact(window, cx, |this, window, cx| {
11120            let buffer = this.buffer.update(cx, |buffer, cx| {
11121                buffer.edit(edits, None, cx);
11122                buffer.snapshot(cx)
11123            });
11124
11125            // Recalculate offsets on newly edited buffer
11126            let new_selections = new_selections
11127                .iter()
11128                .map(|s| {
11129                    let start_point = Point::new(s.start.0, 0);
11130                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
11131                    Selection {
11132                        id: s.id,
11133                        start: buffer.point_to_offset(start_point),
11134                        end: buffer.point_to_offset(end_point),
11135                        goal: s.goal,
11136                        reversed: s.reversed,
11137                    }
11138                })
11139                .collect();
11140
11141            this.change_selections(Default::default(), window, cx, |s| {
11142                s.select(new_selections);
11143            });
11144
11145            this.request_autoscroll(Autoscroll::fit(), cx);
11146        });
11147    }
11148
11149    fn manipulate_immutable_lines<Fn>(
11150        &mut self,
11151        window: &mut Window,
11152        cx: &mut Context<Self>,
11153        mut callback: Fn,
11154    ) where
11155        Fn: FnMut(&mut Vec<&str>),
11156    {
11157        self.manipulate_lines(window, cx, |text| {
11158            let mut lines: Vec<&str> = text.split('\n').collect();
11159            let line_count_before = lines.len();
11160
11161            callback(&mut lines);
11162
11163            LineManipulationResult {
11164                new_text: lines.join("\n"),
11165                line_count_before,
11166                line_count_after: lines.len(),
11167            }
11168        });
11169    }
11170
11171    fn manipulate_mutable_lines<Fn>(
11172        &mut self,
11173        window: &mut Window,
11174        cx: &mut Context<Self>,
11175        mut callback: Fn,
11176    ) where
11177        Fn: FnMut(&mut Vec<Cow<'_, str>>),
11178    {
11179        self.manipulate_lines(window, cx, |text| {
11180            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
11181            let line_count_before = lines.len();
11182
11183            callback(&mut lines);
11184
11185            LineManipulationResult {
11186                new_text: lines.join("\n"),
11187                line_count_before,
11188                line_count_after: lines.len(),
11189            }
11190        });
11191    }
11192
11193    pub fn convert_indentation_to_spaces(
11194        &mut self,
11195        _: &ConvertIndentationToSpaces,
11196        window: &mut Window,
11197        cx: &mut Context<Self>,
11198    ) {
11199        let settings = self.buffer.read(cx).language_settings(cx);
11200        let tab_size = settings.tab_size.get() as usize;
11201
11202        self.manipulate_mutable_lines(window, cx, |lines| {
11203            // Allocates a reasonably sized scratch buffer once for the whole loop
11204            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11205            // Avoids recomputing spaces that could be inserted many times
11206            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11207                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11208                .collect();
11209
11210            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11211                let mut chars = line.as_ref().chars();
11212                let mut col = 0;
11213                let mut changed = false;
11214
11215                for ch in chars.by_ref() {
11216                    match ch {
11217                        ' ' => {
11218                            reindented_line.push(' ');
11219                            col += 1;
11220                        }
11221                        '\t' => {
11222                            // \t are converted to spaces depending on the current column
11223                            let spaces_len = tab_size - (col % tab_size);
11224                            reindented_line.extend(&space_cache[spaces_len - 1]);
11225                            col += spaces_len;
11226                            changed = true;
11227                        }
11228                        _ => {
11229                            // If we dont append before break, the character is consumed
11230                            reindented_line.push(ch);
11231                            break;
11232                        }
11233                    }
11234                }
11235
11236                if !changed {
11237                    reindented_line.clear();
11238                    continue;
11239                }
11240                // Append the rest of the line and replace old reference with new one
11241                reindented_line.extend(chars);
11242                *line = Cow::Owned(reindented_line.clone());
11243                reindented_line.clear();
11244            }
11245        });
11246    }
11247
11248    pub fn convert_indentation_to_tabs(
11249        &mut self,
11250        _: &ConvertIndentationToTabs,
11251        window: &mut Window,
11252        cx: &mut Context<Self>,
11253    ) {
11254        let settings = self.buffer.read(cx).language_settings(cx);
11255        let tab_size = settings.tab_size.get() as usize;
11256
11257        self.manipulate_mutable_lines(window, cx, |lines| {
11258            // Allocates a reasonably sized buffer once for the whole loop
11259            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11260            // Avoids recomputing spaces that could be inserted many times
11261            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11262                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11263                .collect();
11264
11265            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11266                let mut chars = line.chars();
11267                let mut spaces_count = 0;
11268                let mut first_non_indent_char = None;
11269                let mut changed = false;
11270
11271                for ch in chars.by_ref() {
11272                    match ch {
11273                        ' ' => {
11274                            // Keep track of spaces. Append \t when we reach tab_size
11275                            spaces_count += 1;
11276                            changed = true;
11277                            if spaces_count == tab_size {
11278                                reindented_line.push('\t');
11279                                spaces_count = 0;
11280                            }
11281                        }
11282                        '\t' => {
11283                            reindented_line.push('\t');
11284                            spaces_count = 0;
11285                        }
11286                        _ => {
11287                            // Dont append it yet, we might have remaining spaces
11288                            first_non_indent_char = Some(ch);
11289                            break;
11290                        }
11291                    }
11292                }
11293
11294                if !changed {
11295                    reindented_line.clear();
11296                    continue;
11297                }
11298                // Remaining spaces that didn't make a full tab stop
11299                if spaces_count > 0 {
11300                    reindented_line.extend(&space_cache[spaces_count - 1]);
11301                }
11302                // If we consume an extra character that was not indentation, add it back
11303                if let Some(extra_char) = first_non_indent_char {
11304                    reindented_line.push(extra_char);
11305                }
11306                // Append the rest of the line and replace old reference with new one
11307                reindented_line.extend(chars);
11308                *line = Cow::Owned(reindented_line.clone());
11309                reindented_line.clear();
11310            }
11311        });
11312    }
11313
11314    pub fn convert_to_upper_case(
11315        &mut self,
11316        _: &ConvertToUpperCase,
11317        window: &mut Window,
11318        cx: &mut Context<Self>,
11319    ) {
11320        self.manipulate_text(window, cx, |text| text.to_uppercase())
11321    }
11322
11323    pub fn convert_to_lower_case(
11324        &mut self,
11325        _: &ConvertToLowerCase,
11326        window: &mut Window,
11327        cx: &mut Context<Self>,
11328    ) {
11329        self.manipulate_text(window, cx, |text| text.to_lowercase())
11330    }
11331
11332    pub fn convert_to_title_case(
11333        &mut self,
11334        _: &ConvertToTitleCase,
11335        window: &mut Window,
11336        cx: &mut Context<Self>,
11337    ) {
11338        self.manipulate_text(window, cx, |text| {
11339            text.split('\n')
11340                .map(|line| line.to_case(Case::Title))
11341                .join("\n")
11342        })
11343    }
11344
11345    pub fn convert_to_snake_case(
11346        &mut self,
11347        _: &ConvertToSnakeCase,
11348        window: &mut Window,
11349        cx: &mut Context<Self>,
11350    ) {
11351        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11352    }
11353
11354    pub fn convert_to_kebab_case(
11355        &mut self,
11356        _: &ConvertToKebabCase,
11357        window: &mut Window,
11358        cx: &mut Context<Self>,
11359    ) {
11360        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11361    }
11362
11363    pub fn convert_to_upper_camel_case(
11364        &mut self,
11365        _: &ConvertToUpperCamelCase,
11366        window: &mut Window,
11367        cx: &mut Context<Self>,
11368    ) {
11369        self.manipulate_text(window, cx, |text| {
11370            text.split('\n')
11371                .map(|line| line.to_case(Case::UpperCamel))
11372                .join("\n")
11373        })
11374    }
11375
11376    pub fn convert_to_lower_camel_case(
11377        &mut self,
11378        _: &ConvertToLowerCamelCase,
11379        window: &mut Window,
11380        cx: &mut Context<Self>,
11381    ) {
11382        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11383    }
11384
11385    pub fn convert_to_opposite_case(
11386        &mut self,
11387        _: &ConvertToOppositeCase,
11388        window: &mut Window,
11389        cx: &mut Context<Self>,
11390    ) {
11391        self.manipulate_text(window, cx, |text| {
11392            text.chars()
11393                .fold(String::with_capacity(text.len()), |mut t, c| {
11394                    if c.is_uppercase() {
11395                        t.extend(c.to_lowercase());
11396                    } else {
11397                        t.extend(c.to_uppercase());
11398                    }
11399                    t
11400                })
11401        })
11402    }
11403
11404    pub fn convert_to_sentence_case(
11405        &mut self,
11406        _: &ConvertToSentenceCase,
11407        window: &mut Window,
11408        cx: &mut Context<Self>,
11409    ) {
11410        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
11411    }
11412
11413    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
11414        self.manipulate_text(window, cx, |text| {
11415            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
11416            if has_upper_case_characters {
11417                text.to_lowercase()
11418            } else {
11419                text.to_uppercase()
11420            }
11421        })
11422    }
11423
11424    pub fn convert_to_rot13(
11425        &mut self,
11426        _: &ConvertToRot13,
11427        window: &mut Window,
11428        cx: &mut Context<Self>,
11429    ) {
11430        self.manipulate_text(window, cx, |text| {
11431            text.chars()
11432                .map(|c| match c {
11433                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11434                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11435                    _ => c,
11436                })
11437                .collect()
11438        })
11439    }
11440
11441    pub fn convert_to_rot47(
11442        &mut self,
11443        _: &ConvertToRot47,
11444        window: &mut Window,
11445        cx: &mut Context<Self>,
11446    ) {
11447        self.manipulate_text(window, cx, |text| {
11448            text.chars()
11449                .map(|c| {
11450                    let code_point = c as u32;
11451                    if code_point >= 33 && code_point <= 126 {
11452                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11453                    }
11454                    c
11455                })
11456                .collect()
11457        })
11458    }
11459
11460    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11461    where
11462        Fn: FnMut(&str) -> String,
11463    {
11464        let buffer = self.buffer.read(cx).snapshot(cx);
11465
11466        let mut new_selections = Vec::new();
11467        let mut edits = Vec::new();
11468        let mut selection_adjustment = 0i32;
11469
11470        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
11471            let selection_is_empty = selection.is_empty();
11472
11473            let (start, end) = if selection_is_empty {
11474                let (word_range, _) = buffer.surrounding_word(selection.start, None);
11475                (word_range.start, word_range.end)
11476            } else {
11477                (
11478                    buffer.point_to_offset(selection.start),
11479                    buffer.point_to_offset(selection.end),
11480                )
11481            };
11482
11483            let text = buffer.text_for_range(start..end).collect::<String>();
11484            let old_length = text.len() as i32;
11485            let text = callback(&text);
11486
11487            new_selections.push(Selection {
11488                start: (start as i32 - selection_adjustment) as usize,
11489                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
11490                goal: SelectionGoal::None,
11491                id: selection.id,
11492                reversed: selection.reversed,
11493            });
11494
11495            selection_adjustment += old_length - text.len() as i32;
11496
11497            edits.push((start..end, text));
11498        }
11499
11500        self.transact(window, cx, |this, window, cx| {
11501            this.buffer.update(cx, |buffer, cx| {
11502                buffer.edit(edits, None, cx);
11503            });
11504
11505            this.change_selections(Default::default(), window, cx, |s| {
11506                s.select(new_selections);
11507            });
11508
11509            this.request_autoscroll(Autoscroll::fit(), cx);
11510        });
11511    }
11512
11513    pub fn move_selection_on_drop(
11514        &mut self,
11515        selection: &Selection<Anchor>,
11516        target: DisplayPoint,
11517        is_cut: bool,
11518        window: &mut Window,
11519        cx: &mut Context<Self>,
11520    ) {
11521        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11522        let buffer = display_map.buffer_snapshot();
11523        let mut edits = Vec::new();
11524        let insert_point = display_map
11525            .clip_point(target, Bias::Left)
11526            .to_point(&display_map);
11527        let text = buffer
11528            .text_for_range(selection.start..selection.end)
11529            .collect::<String>();
11530        if is_cut {
11531            edits.push(((selection.start..selection.end), String::new()));
11532        }
11533        let insert_anchor = buffer.anchor_before(insert_point);
11534        edits.push(((insert_anchor..insert_anchor), text));
11535        let last_edit_start = insert_anchor.bias_left(buffer);
11536        let last_edit_end = insert_anchor.bias_right(buffer);
11537        self.transact(window, cx, |this, window, cx| {
11538            this.buffer.update(cx, |buffer, cx| {
11539                buffer.edit(edits, None, cx);
11540            });
11541            this.change_selections(Default::default(), window, cx, |s| {
11542                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11543            });
11544        });
11545    }
11546
11547    pub fn clear_selection_drag_state(&mut self) {
11548        self.selection_drag_state = SelectionDragState::None;
11549    }
11550
11551    pub fn duplicate(
11552        &mut self,
11553        upwards: bool,
11554        whole_lines: bool,
11555        window: &mut Window,
11556        cx: &mut Context<Self>,
11557    ) {
11558        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11559
11560        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11561        let buffer = display_map.buffer_snapshot();
11562        let selections = self.selections.all::<Point>(&display_map);
11563
11564        let mut edits = Vec::new();
11565        let mut selections_iter = selections.iter().peekable();
11566        while let Some(selection) = selections_iter.next() {
11567            let mut rows = selection.spanned_rows(false, &display_map);
11568            // duplicate line-wise
11569            if whole_lines || selection.start == selection.end {
11570                // Avoid duplicating the same lines twice.
11571                while let Some(next_selection) = selections_iter.peek() {
11572                    let next_rows = next_selection.spanned_rows(false, &display_map);
11573                    if next_rows.start < rows.end {
11574                        rows.end = next_rows.end;
11575                        selections_iter.next().unwrap();
11576                    } else {
11577                        break;
11578                    }
11579                }
11580
11581                // Copy the text from the selected row region and splice it either at the start
11582                // or end of the region.
11583                let start = Point::new(rows.start.0, 0);
11584                let end = Point::new(
11585                    rows.end.previous_row().0,
11586                    buffer.line_len(rows.end.previous_row()),
11587                );
11588
11589                let mut text = buffer.text_for_range(start..end).collect::<String>();
11590
11591                let insert_location = if upwards {
11592                    // When duplicating upward, we need to insert before the current line.
11593                    // If we're on the last line and it doesn't end with a newline,
11594                    // we need to add a newline before the duplicated content.
11595                    let needs_leading_newline = rows.end.0 >= buffer.max_point().row
11596                        && buffer.max_point().column > 0
11597                        && !text.ends_with('\n');
11598
11599                    if needs_leading_newline {
11600                        text.insert(0, '\n');
11601                        end
11602                    } else {
11603                        text.push('\n');
11604                        Point::new(rows.start.0, 0)
11605                    }
11606                } else {
11607                    text.push('\n');
11608                    start
11609                };
11610                edits.push((insert_location..insert_location, text));
11611            } else {
11612                // duplicate character-wise
11613                let start = selection.start;
11614                let end = selection.end;
11615                let text = buffer.text_for_range(start..end).collect::<String>();
11616                edits.push((selection.end..selection.end, text));
11617            }
11618        }
11619
11620        self.transact(window, cx, |this, window, cx| {
11621            this.buffer.update(cx, |buffer, cx| {
11622                buffer.edit(edits, None, cx);
11623            });
11624
11625            // When duplicating upward with whole lines, move the cursor to the duplicated line
11626            if upwards && whole_lines {
11627                let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
11628
11629                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
11630                    let mut new_ranges = Vec::new();
11631                    let selections = s.all::<Point>(&display_map);
11632                    let mut selections_iter = selections.iter().peekable();
11633
11634                    while let Some(first_selection) = selections_iter.next() {
11635                        // Group contiguous selections together to find the total row span
11636                        let mut group_selections = vec![first_selection];
11637                        let mut rows = first_selection.spanned_rows(false, &display_map);
11638
11639                        while let Some(next_selection) = selections_iter.peek() {
11640                            let next_rows = next_selection.spanned_rows(false, &display_map);
11641                            if next_rows.start < rows.end {
11642                                rows.end = next_rows.end;
11643                                group_selections.push(selections_iter.next().unwrap());
11644                            } else {
11645                                break;
11646                            }
11647                        }
11648
11649                        let row_count = rows.end.0 - rows.start.0;
11650
11651                        // Move all selections in this group up by the total number of duplicated rows
11652                        for selection in group_selections {
11653                            let new_start = Point::new(
11654                                selection.start.row.saturating_sub(row_count),
11655                                selection.start.column,
11656                            );
11657
11658                            let new_end = Point::new(
11659                                selection.end.row.saturating_sub(row_count),
11660                                selection.end.column,
11661                            );
11662
11663                            new_ranges.push(new_start..new_end);
11664                        }
11665                    }
11666
11667                    s.select_ranges(new_ranges);
11668                });
11669            }
11670
11671            this.request_autoscroll(Autoscroll::fit(), cx);
11672        });
11673    }
11674
11675    pub fn duplicate_line_up(
11676        &mut self,
11677        _: &DuplicateLineUp,
11678        window: &mut Window,
11679        cx: &mut Context<Self>,
11680    ) {
11681        self.duplicate(true, true, window, cx);
11682    }
11683
11684    pub fn duplicate_line_down(
11685        &mut self,
11686        _: &DuplicateLineDown,
11687        window: &mut Window,
11688        cx: &mut Context<Self>,
11689    ) {
11690        self.duplicate(false, true, window, cx);
11691    }
11692
11693    pub fn duplicate_selection(
11694        &mut self,
11695        _: &DuplicateSelection,
11696        window: &mut Window,
11697        cx: &mut Context<Self>,
11698    ) {
11699        self.duplicate(false, false, window, cx);
11700    }
11701
11702    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11703        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11704        if self.mode.is_single_line() {
11705            cx.propagate();
11706            return;
11707        }
11708
11709        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11710        let buffer = self.buffer.read(cx).snapshot(cx);
11711
11712        let mut edits = Vec::new();
11713        let mut unfold_ranges = Vec::new();
11714        let mut refold_creases = Vec::new();
11715
11716        let selections = self.selections.all::<Point>(&display_map);
11717        let mut selections = selections.iter().peekable();
11718        let mut contiguous_row_selections = Vec::new();
11719        let mut new_selections = Vec::new();
11720
11721        while let Some(selection) = selections.next() {
11722            // Find all the selections that span a contiguous row range
11723            let (start_row, end_row) = consume_contiguous_rows(
11724                &mut contiguous_row_selections,
11725                selection,
11726                &display_map,
11727                &mut selections,
11728            );
11729
11730            // Move the text spanned by the row range to be before the line preceding the row range
11731            if start_row.0 > 0 {
11732                let range_to_move = Point::new(
11733                    start_row.previous_row().0,
11734                    buffer.line_len(start_row.previous_row()),
11735                )
11736                    ..Point::new(
11737                        end_row.previous_row().0,
11738                        buffer.line_len(end_row.previous_row()),
11739                    );
11740                let insertion_point = display_map
11741                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11742                    .0;
11743
11744                // Don't move lines across excerpts
11745                if buffer
11746                    .excerpt_containing(insertion_point..range_to_move.end)
11747                    .is_some()
11748                {
11749                    let text = buffer
11750                        .text_for_range(range_to_move.clone())
11751                        .flat_map(|s| s.chars())
11752                        .skip(1)
11753                        .chain(['\n'])
11754                        .collect::<String>();
11755
11756                    edits.push((
11757                        buffer.anchor_after(range_to_move.start)
11758                            ..buffer.anchor_before(range_to_move.end),
11759                        String::new(),
11760                    ));
11761                    let insertion_anchor = buffer.anchor_after(insertion_point);
11762                    edits.push((insertion_anchor..insertion_anchor, text));
11763
11764                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11765
11766                    // Move selections up
11767                    new_selections.extend(contiguous_row_selections.drain(..).map(
11768                        |mut selection| {
11769                            selection.start.row -= row_delta;
11770                            selection.end.row -= row_delta;
11771                            selection
11772                        },
11773                    ));
11774
11775                    // Move folds up
11776                    unfold_ranges.push(range_to_move.clone());
11777                    for fold in display_map.folds_in_range(
11778                        buffer.anchor_before(range_to_move.start)
11779                            ..buffer.anchor_after(range_to_move.end),
11780                    ) {
11781                        let mut start = fold.range.start.to_point(&buffer);
11782                        let mut end = fold.range.end.to_point(&buffer);
11783                        start.row -= row_delta;
11784                        end.row -= row_delta;
11785                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11786                    }
11787                }
11788            }
11789
11790            // If we didn't move line(s), preserve the existing selections
11791            new_selections.append(&mut contiguous_row_selections);
11792        }
11793
11794        self.transact(window, cx, |this, window, cx| {
11795            this.unfold_ranges(&unfold_ranges, true, true, cx);
11796            this.buffer.update(cx, |buffer, cx| {
11797                for (range, text) in edits {
11798                    buffer.edit([(range, text)], None, cx);
11799                }
11800            });
11801            this.fold_creases(refold_creases, true, window, cx);
11802            this.change_selections(Default::default(), window, cx, |s| {
11803                s.select(new_selections);
11804            })
11805        });
11806    }
11807
11808    pub fn move_line_down(
11809        &mut self,
11810        _: &MoveLineDown,
11811        window: &mut Window,
11812        cx: &mut Context<Self>,
11813    ) {
11814        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11815        if self.mode.is_single_line() {
11816            cx.propagate();
11817            return;
11818        }
11819
11820        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11821        let buffer = self.buffer.read(cx).snapshot(cx);
11822
11823        let mut edits = Vec::new();
11824        let mut unfold_ranges = Vec::new();
11825        let mut refold_creases = Vec::new();
11826
11827        let selections = self.selections.all::<Point>(&display_map);
11828        let mut selections = selections.iter().peekable();
11829        let mut contiguous_row_selections = Vec::new();
11830        let mut new_selections = Vec::new();
11831
11832        while let Some(selection) = selections.next() {
11833            // Find all the selections that span a contiguous row range
11834            let (start_row, end_row) = consume_contiguous_rows(
11835                &mut contiguous_row_selections,
11836                selection,
11837                &display_map,
11838                &mut selections,
11839            );
11840
11841            // Move the text spanned by the row range to be after the last line of the row range
11842            if end_row.0 <= buffer.max_point().row {
11843                let range_to_move =
11844                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11845                let insertion_point = display_map
11846                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11847                    .0;
11848
11849                // Don't move lines across excerpt boundaries
11850                if buffer
11851                    .excerpt_containing(range_to_move.start..insertion_point)
11852                    .is_some()
11853                {
11854                    let mut text = String::from("\n");
11855                    text.extend(buffer.text_for_range(range_to_move.clone()));
11856                    text.pop(); // Drop trailing newline
11857                    edits.push((
11858                        buffer.anchor_after(range_to_move.start)
11859                            ..buffer.anchor_before(range_to_move.end),
11860                        String::new(),
11861                    ));
11862                    let insertion_anchor = buffer.anchor_after(insertion_point);
11863                    edits.push((insertion_anchor..insertion_anchor, text));
11864
11865                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
11866
11867                    // Move selections down
11868                    new_selections.extend(contiguous_row_selections.drain(..).map(
11869                        |mut selection| {
11870                            selection.start.row += row_delta;
11871                            selection.end.row += row_delta;
11872                            selection
11873                        },
11874                    ));
11875
11876                    // Move folds down
11877                    unfold_ranges.push(range_to_move.clone());
11878                    for fold in display_map.folds_in_range(
11879                        buffer.anchor_before(range_to_move.start)
11880                            ..buffer.anchor_after(range_to_move.end),
11881                    ) {
11882                        let mut start = fold.range.start.to_point(&buffer);
11883                        let mut end = fold.range.end.to_point(&buffer);
11884                        start.row += row_delta;
11885                        end.row += row_delta;
11886                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11887                    }
11888                }
11889            }
11890
11891            // If we didn't move line(s), preserve the existing selections
11892            new_selections.append(&mut contiguous_row_selections);
11893        }
11894
11895        self.transact(window, cx, |this, window, cx| {
11896            this.unfold_ranges(&unfold_ranges, true, true, cx);
11897            this.buffer.update(cx, |buffer, cx| {
11898                for (range, text) in edits {
11899                    buffer.edit([(range, text)], None, cx);
11900                }
11901            });
11902            this.fold_creases(refold_creases, true, window, cx);
11903            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
11904        });
11905    }
11906
11907    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
11908        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11909        let text_layout_details = &self.text_layout_details(window);
11910        self.transact(window, cx, |this, window, cx| {
11911            let edits = this.change_selections(Default::default(), window, cx, |s| {
11912                let mut edits: Vec<(Range<usize>, String)> = Default::default();
11913                s.move_with(|display_map, selection| {
11914                    if !selection.is_empty() {
11915                        return;
11916                    }
11917
11918                    let mut head = selection.head();
11919                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
11920                    if head.column() == display_map.line_len(head.row()) {
11921                        transpose_offset = display_map
11922                            .buffer_snapshot()
11923                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11924                    }
11925
11926                    if transpose_offset == 0 {
11927                        return;
11928                    }
11929
11930                    *head.column_mut() += 1;
11931                    head = display_map.clip_point(head, Bias::Right);
11932                    let goal = SelectionGoal::HorizontalPosition(
11933                        display_map
11934                            .x_for_display_point(head, text_layout_details)
11935                            .into(),
11936                    );
11937                    selection.collapse_to(head, goal);
11938
11939                    let transpose_start = display_map
11940                        .buffer_snapshot()
11941                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11942                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
11943                        let transpose_end = display_map
11944                            .buffer_snapshot()
11945                            .clip_offset(transpose_offset + 1, Bias::Right);
11946                        if let Some(ch) = display_map
11947                            .buffer_snapshot()
11948                            .chars_at(transpose_start)
11949                            .next()
11950                        {
11951                            edits.push((transpose_start..transpose_offset, String::new()));
11952                            edits.push((transpose_end..transpose_end, ch.to_string()));
11953                        }
11954                    }
11955                });
11956                edits
11957            });
11958            this.buffer
11959                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11960            let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
11961            this.change_selections(Default::default(), window, cx, |s| {
11962                s.select(selections);
11963            });
11964        });
11965    }
11966
11967    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
11968        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11969        if self.mode.is_single_line() {
11970            cx.propagate();
11971            return;
11972        }
11973
11974        self.rewrap_impl(RewrapOptions::default(), cx)
11975    }
11976
11977    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
11978        let buffer = self.buffer.read(cx).snapshot(cx);
11979        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
11980
11981        #[derive(Clone, Debug, PartialEq)]
11982        enum CommentFormat {
11983            /// single line comment, with prefix for line
11984            Line(String),
11985            /// single line within a block comment, with prefix for line
11986            BlockLine(String),
11987            /// a single line of a block comment that includes the initial delimiter
11988            BlockCommentWithStart(BlockCommentConfig),
11989            /// a single line of a block comment that includes the ending delimiter
11990            BlockCommentWithEnd(BlockCommentConfig),
11991        }
11992
11993        // Split selections to respect paragraph, indent, and comment prefix boundaries.
11994        let wrap_ranges = selections.into_iter().flat_map(|selection| {
11995            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
11996                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11997                .peekable();
11998
11999            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
12000                row
12001            } else {
12002                return Vec::new();
12003            };
12004
12005            let language_settings = buffer.language_settings_at(selection.head(), cx);
12006            let language_scope = buffer.language_scope_at(selection.head());
12007
12008            let indent_and_prefix_for_row =
12009                |row: u32| -> (IndentSize, Option<CommentFormat>, Option<String>) {
12010                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
12011                    let (comment_prefix, rewrap_prefix) = if let Some(language_scope) =
12012                        &language_scope
12013                    {
12014                        let indent_end = Point::new(row, indent.len);
12015                        let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12016                        let line_text_after_indent = buffer
12017                            .text_for_range(indent_end..line_end)
12018                            .collect::<String>();
12019
12020                        let is_within_comment_override = buffer
12021                            .language_scope_at(indent_end)
12022                            .is_some_and(|scope| scope.override_name() == Some("comment"));
12023                        let comment_delimiters = if is_within_comment_override {
12024                            // we are within a comment syntax node, but we don't
12025                            // yet know what kind of comment: block, doc or line
12026                            match (
12027                                language_scope.documentation_comment(),
12028                                language_scope.block_comment(),
12029                            ) {
12030                                (Some(config), _) | (_, Some(config))
12031                                    if buffer.contains_str_at(indent_end, &config.start) =>
12032                                {
12033                                    Some(CommentFormat::BlockCommentWithStart(config.clone()))
12034                                }
12035                                (Some(config), _) | (_, Some(config))
12036                                    if line_text_after_indent.ends_with(config.end.as_ref()) =>
12037                                {
12038                                    Some(CommentFormat::BlockCommentWithEnd(config.clone()))
12039                                }
12040                                (Some(config), _) | (_, Some(config))
12041                                    if buffer.contains_str_at(indent_end, &config.prefix) =>
12042                                {
12043                                    Some(CommentFormat::BlockLine(config.prefix.to_string()))
12044                                }
12045                                (_, _) => language_scope
12046                                    .line_comment_prefixes()
12047                                    .iter()
12048                                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12049                                    .map(|prefix| CommentFormat::Line(prefix.to_string())),
12050                            }
12051                        } else {
12052                            // we not in an overridden comment node, but we may
12053                            // be within a non-overridden line comment node
12054                            language_scope
12055                                .line_comment_prefixes()
12056                                .iter()
12057                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12058                                .map(|prefix| CommentFormat::Line(prefix.to_string()))
12059                        };
12060
12061                        let rewrap_prefix = language_scope
12062                            .rewrap_prefixes()
12063                            .iter()
12064                            .find_map(|prefix_regex| {
12065                                prefix_regex.find(&line_text_after_indent).map(|mat| {
12066                                    if mat.start() == 0 {
12067                                        Some(mat.as_str().to_string())
12068                                    } else {
12069                                        None
12070                                    }
12071                                })
12072                            })
12073                            .flatten();
12074                        (comment_delimiters, rewrap_prefix)
12075                    } else {
12076                        (None, None)
12077                    };
12078                    (indent, comment_prefix, rewrap_prefix)
12079                };
12080
12081            let mut ranges = Vec::new();
12082            let from_empty_selection = selection.is_empty();
12083
12084            let mut current_range_start = first_row;
12085            let mut prev_row = first_row;
12086            let (
12087                mut current_range_indent,
12088                mut current_range_comment_delimiters,
12089                mut current_range_rewrap_prefix,
12090            ) = indent_and_prefix_for_row(first_row);
12091
12092            for row in non_blank_rows_iter.skip(1) {
12093                let has_paragraph_break = row > prev_row + 1;
12094
12095                let (row_indent, row_comment_delimiters, row_rewrap_prefix) =
12096                    indent_and_prefix_for_row(row);
12097
12098                let has_indent_change = row_indent != current_range_indent;
12099                let has_comment_change = row_comment_delimiters != current_range_comment_delimiters;
12100
12101                let has_boundary_change = has_comment_change
12102                    || row_rewrap_prefix.is_some()
12103                    || (has_indent_change && current_range_comment_delimiters.is_some());
12104
12105                if has_paragraph_break || has_boundary_change {
12106                    ranges.push((
12107                        language_settings.clone(),
12108                        Point::new(current_range_start, 0)
12109                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12110                        current_range_indent,
12111                        current_range_comment_delimiters.clone(),
12112                        current_range_rewrap_prefix.clone(),
12113                        from_empty_selection,
12114                    ));
12115                    current_range_start = row;
12116                    current_range_indent = row_indent;
12117                    current_range_comment_delimiters = row_comment_delimiters;
12118                    current_range_rewrap_prefix = row_rewrap_prefix;
12119                }
12120                prev_row = row;
12121            }
12122
12123            ranges.push((
12124                language_settings.clone(),
12125                Point::new(current_range_start, 0)
12126                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12127                current_range_indent,
12128                current_range_comment_delimiters,
12129                current_range_rewrap_prefix,
12130                from_empty_selection,
12131            ));
12132
12133            ranges
12134        });
12135
12136        let mut edits = Vec::new();
12137        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
12138
12139        for (
12140            language_settings,
12141            wrap_range,
12142            mut indent_size,
12143            comment_prefix,
12144            rewrap_prefix,
12145            from_empty_selection,
12146        ) in wrap_ranges
12147        {
12148            let mut start_row = wrap_range.start.row;
12149            let mut end_row = wrap_range.end.row;
12150
12151            // Skip selections that overlap with a range that has already been rewrapped.
12152            let selection_range = start_row..end_row;
12153            if rewrapped_row_ranges
12154                .iter()
12155                .any(|range| range.overlaps(&selection_range))
12156            {
12157                continue;
12158            }
12159
12160            let tab_size = language_settings.tab_size;
12161
12162            let (line_prefix, inside_comment) = match &comment_prefix {
12163                Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
12164                    (Some(prefix.as_str()), true)
12165                }
12166                Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig { prefix, .. })) => {
12167                    (Some(prefix.as_ref()), true)
12168                }
12169                Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12170                    start: _,
12171                    end: _,
12172                    prefix,
12173                    tab_size,
12174                })) => {
12175                    indent_size.len += tab_size;
12176                    (Some(prefix.as_ref()), true)
12177                }
12178                None => (None, false),
12179            };
12180            let indent_prefix = indent_size.chars().collect::<String>();
12181            let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
12182
12183            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
12184                RewrapBehavior::InComments => inside_comment,
12185                RewrapBehavior::InSelections => !wrap_range.is_empty(),
12186                RewrapBehavior::Anywhere => true,
12187            };
12188
12189            let should_rewrap = options.override_language_settings
12190                || allow_rewrap_based_on_language
12191                || self.hard_wrap.is_some();
12192            if !should_rewrap {
12193                continue;
12194            }
12195
12196            if from_empty_selection {
12197                'expand_upwards: while start_row > 0 {
12198                    let prev_row = start_row - 1;
12199                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
12200                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
12201                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
12202                    {
12203                        start_row = prev_row;
12204                    } else {
12205                        break 'expand_upwards;
12206                    }
12207                }
12208
12209                'expand_downwards: while end_row < buffer.max_point().row {
12210                    let next_row = end_row + 1;
12211                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
12212                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
12213                        && !buffer.is_line_blank(MultiBufferRow(next_row))
12214                    {
12215                        end_row = next_row;
12216                    } else {
12217                        break 'expand_downwards;
12218                    }
12219                }
12220            }
12221
12222            let start = Point::new(start_row, 0);
12223            let start_offset = ToOffset::to_offset(&start, &buffer);
12224            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
12225            let selection_text = buffer.text_for_range(start..end).collect::<String>();
12226            let mut first_line_delimiter = None;
12227            let mut last_line_delimiter = None;
12228            let Some(lines_without_prefixes) = selection_text
12229                .lines()
12230                .enumerate()
12231                .map(|(ix, line)| {
12232                    let line_trimmed = line.trim_start();
12233                    if rewrap_prefix.is_some() && ix > 0 {
12234                        Ok(line_trimmed)
12235                    } else if let Some(
12236                        CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12237                            start,
12238                            prefix,
12239                            end,
12240                            tab_size,
12241                        })
12242                        | CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
12243                            start,
12244                            prefix,
12245                            end,
12246                            tab_size,
12247                        }),
12248                    ) = &comment_prefix
12249                    {
12250                        let line_trimmed = line_trimmed
12251                            .strip_prefix(start.as_ref())
12252                            .map(|s| {
12253                                let mut indent_size = indent_size;
12254                                indent_size.len -= tab_size;
12255                                let indent_prefix: String = indent_size.chars().collect();
12256                                first_line_delimiter = Some((indent_prefix, start));
12257                                s.trim_start()
12258                            })
12259                            .unwrap_or(line_trimmed);
12260                        let line_trimmed = line_trimmed
12261                            .strip_suffix(end.as_ref())
12262                            .map(|s| {
12263                                last_line_delimiter = Some(end);
12264                                s.trim_end()
12265                            })
12266                            .unwrap_or(line_trimmed);
12267                        let line_trimmed = line_trimmed
12268                            .strip_prefix(prefix.as_ref())
12269                            .unwrap_or(line_trimmed);
12270                        Ok(line_trimmed)
12271                    } else if let Some(CommentFormat::BlockLine(prefix)) = &comment_prefix {
12272                        line_trimmed.strip_prefix(prefix).with_context(|| {
12273                            format!("line did not start with prefix {prefix:?}: {line:?}")
12274                        })
12275                    } else {
12276                        line_trimmed
12277                            .strip_prefix(&line_prefix.trim_start())
12278                            .with_context(|| {
12279                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
12280                            })
12281                    }
12282                })
12283                .collect::<Result<Vec<_>, _>>()
12284                .log_err()
12285            else {
12286                continue;
12287            };
12288
12289            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
12290                buffer
12291                    .language_settings_at(Point::new(start_row, 0), cx)
12292                    .preferred_line_length as usize
12293            });
12294
12295            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
12296                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
12297            } else {
12298                line_prefix.clone()
12299            };
12300
12301            let wrapped_text = {
12302                let mut wrapped_text = wrap_with_prefix(
12303                    line_prefix,
12304                    subsequent_lines_prefix,
12305                    lines_without_prefixes.join("\n"),
12306                    wrap_column,
12307                    tab_size,
12308                    options.preserve_existing_whitespace,
12309                );
12310
12311                if let Some((indent, delimiter)) = first_line_delimiter {
12312                    wrapped_text = format!("{indent}{delimiter}\n{wrapped_text}");
12313                }
12314                if let Some(last_line) = last_line_delimiter {
12315                    wrapped_text = format!("{wrapped_text}\n{indent_prefix}{last_line}");
12316                }
12317
12318                wrapped_text
12319            };
12320
12321            // TODO: should always use char-based diff while still supporting cursor behavior that
12322            // matches vim.
12323            let mut diff_options = DiffOptions::default();
12324            if options.override_language_settings {
12325                diff_options.max_word_diff_len = 0;
12326                diff_options.max_word_diff_line_count = 0;
12327            } else {
12328                diff_options.max_word_diff_len = usize::MAX;
12329                diff_options.max_word_diff_line_count = usize::MAX;
12330            }
12331
12332            for (old_range, new_text) in
12333                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
12334            {
12335                let edit_start = buffer.anchor_after(start_offset + old_range.start);
12336                let edit_end = buffer.anchor_after(start_offset + old_range.end);
12337                edits.push((edit_start..edit_end, new_text));
12338            }
12339
12340            rewrapped_row_ranges.push(start_row..=end_row);
12341        }
12342
12343        self.buffer
12344            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12345    }
12346
12347    pub fn cut_common(
12348        &mut self,
12349        cut_no_selection_line: bool,
12350        window: &mut Window,
12351        cx: &mut Context<Self>,
12352    ) -> ClipboardItem {
12353        let mut text = String::new();
12354        let buffer = self.buffer.read(cx).snapshot(cx);
12355        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12356        let mut clipboard_selections = Vec::with_capacity(selections.len());
12357        {
12358            let max_point = buffer.max_point();
12359            let mut is_first = true;
12360            for selection in &mut selections {
12361                let is_entire_line =
12362                    (selection.is_empty() && cut_no_selection_line) || self.selections.line_mode();
12363                if is_entire_line {
12364                    selection.start = Point::new(selection.start.row, 0);
12365                    if !selection.is_empty() && selection.end.column == 0 {
12366                        selection.end = cmp::min(max_point, selection.end);
12367                    } else {
12368                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
12369                    }
12370                    selection.goal = SelectionGoal::None;
12371                }
12372                if is_first {
12373                    is_first = false;
12374                } else {
12375                    text += "\n";
12376                }
12377                let mut len = 0;
12378                for chunk in buffer.text_for_range(selection.start..selection.end) {
12379                    text.push_str(chunk);
12380                    len += chunk.len();
12381                }
12382                clipboard_selections.push(ClipboardSelection {
12383                    len,
12384                    is_entire_line,
12385                    first_line_indent: buffer
12386                        .indent_size_for_line(MultiBufferRow(selection.start.row))
12387                        .len,
12388                });
12389            }
12390        }
12391
12392        self.transact(window, cx, |this, window, cx| {
12393            this.change_selections(Default::default(), window, cx, |s| {
12394                s.select(selections);
12395            });
12396            this.insert("", window, cx);
12397        });
12398        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
12399    }
12400
12401    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
12402        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12403        let item = self.cut_common(true, window, cx);
12404        cx.write_to_clipboard(item);
12405    }
12406
12407    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
12408        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12409        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12410            s.move_with(|snapshot, sel| {
12411                if sel.is_empty() {
12412                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()));
12413                }
12414                if sel.is_empty() {
12415                    sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
12416                }
12417            });
12418        });
12419        let item = self.cut_common(false, window, cx);
12420        cx.set_global(KillRing(item))
12421    }
12422
12423    pub fn kill_ring_yank(
12424        &mut self,
12425        _: &KillRingYank,
12426        window: &mut Window,
12427        cx: &mut Context<Self>,
12428    ) {
12429        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12430        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
12431            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
12432                (kill_ring.text().to_string(), kill_ring.metadata_json())
12433            } else {
12434                return;
12435            }
12436        } else {
12437            return;
12438        };
12439        self.do_paste(&text, metadata, false, window, cx);
12440    }
12441
12442    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
12443        self.do_copy(true, cx);
12444    }
12445
12446    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
12447        self.do_copy(false, cx);
12448    }
12449
12450    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
12451        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12452        let buffer = self.buffer.read(cx).read(cx);
12453        let mut text = String::new();
12454
12455        let mut clipboard_selections = Vec::with_capacity(selections.len());
12456        {
12457            let max_point = buffer.max_point();
12458            let mut is_first = true;
12459            for selection in &selections {
12460                let mut start = selection.start;
12461                let mut end = selection.end;
12462                let is_entire_line = selection.is_empty() || self.selections.line_mode();
12463                let mut add_trailing_newline = false;
12464                if is_entire_line {
12465                    start = Point::new(start.row, 0);
12466                    let next_line_start = Point::new(end.row + 1, 0);
12467                    if next_line_start <= max_point {
12468                        end = next_line_start;
12469                    } else {
12470                        // We're on the last line without a trailing newline.
12471                        // Copy to the end of the line and add a newline afterwards.
12472                        end = Point::new(end.row, buffer.line_len(MultiBufferRow(end.row)));
12473                        add_trailing_newline = true;
12474                    }
12475                }
12476
12477                let mut trimmed_selections = Vec::new();
12478                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
12479                    let row = MultiBufferRow(start.row);
12480                    let first_indent = buffer.indent_size_for_line(row);
12481                    if first_indent.len == 0 || start.column > first_indent.len {
12482                        trimmed_selections.push(start..end);
12483                    } else {
12484                        trimmed_selections.push(
12485                            Point::new(row.0, first_indent.len)
12486                                ..Point::new(row.0, buffer.line_len(row)),
12487                        );
12488                        for row in start.row + 1..=end.row {
12489                            let mut line_len = buffer.line_len(MultiBufferRow(row));
12490                            if row == end.row {
12491                                line_len = end.column;
12492                            }
12493                            if line_len == 0 {
12494                                trimmed_selections
12495                                    .push(Point::new(row, 0)..Point::new(row, line_len));
12496                                continue;
12497                            }
12498                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
12499                            if row_indent_size.len >= first_indent.len {
12500                                trimmed_selections.push(
12501                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
12502                                );
12503                            } else {
12504                                trimmed_selections.clear();
12505                                trimmed_selections.push(start..end);
12506                                break;
12507                            }
12508                        }
12509                    }
12510                } else {
12511                    trimmed_selections.push(start..end);
12512                }
12513
12514                for trimmed_range in trimmed_selections {
12515                    if is_first {
12516                        is_first = false;
12517                    } else {
12518                        text += "\n";
12519                    }
12520                    let mut len = 0;
12521                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12522                        text.push_str(chunk);
12523                        len += chunk.len();
12524                    }
12525                    if add_trailing_newline {
12526                        text.push('\n');
12527                        len += 1;
12528                    }
12529                    clipboard_selections.push(ClipboardSelection {
12530                        len,
12531                        is_entire_line,
12532                        first_line_indent: buffer
12533                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12534                            .len,
12535                    });
12536                }
12537            }
12538        }
12539
12540        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12541            text,
12542            clipboard_selections,
12543        ));
12544    }
12545
12546    pub fn do_paste(
12547        &mut self,
12548        text: &String,
12549        clipboard_selections: Option<Vec<ClipboardSelection>>,
12550        handle_entire_lines: bool,
12551        window: &mut Window,
12552        cx: &mut Context<Self>,
12553    ) {
12554        if self.read_only(cx) {
12555            return;
12556        }
12557
12558        let clipboard_text = Cow::Borrowed(text.as_str());
12559
12560        self.transact(window, cx, |this, window, cx| {
12561            let had_active_edit_prediction = this.has_active_edit_prediction();
12562            let display_map = this.display_snapshot(cx);
12563            let old_selections = this.selections.all::<usize>(&display_map);
12564            let cursor_offset = this.selections.last::<usize>(&display_map).head();
12565
12566            if let Some(mut clipboard_selections) = clipboard_selections {
12567                let all_selections_were_entire_line =
12568                    clipboard_selections.iter().all(|s| s.is_entire_line);
12569                let first_selection_indent_column =
12570                    clipboard_selections.first().map(|s| s.first_line_indent);
12571                if clipboard_selections.len() != old_selections.len() {
12572                    clipboard_selections.drain(..);
12573                }
12574                let mut auto_indent_on_paste = true;
12575
12576                this.buffer.update(cx, |buffer, cx| {
12577                    let snapshot = buffer.read(cx);
12578                    auto_indent_on_paste = snapshot
12579                        .language_settings_at(cursor_offset, cx)
12580                        .auto_indent_on_paste;
12581
12582                    let mut start_offset = 0;
12583                    let mut edits = Vec::new();
12584                    let mut original_indent_columns = Vec::new();
12585                    for (ix, selection) in old_selections.iter().enumerate() {
12586                        let to_insert;
12587                        let entire_line;
12588                        let original_indent_column;
12589                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12590                            let end_offset = start_offset + clipboard_selection.len;
12591                            to_insert = &clipboard_text[start_offset..end_offset];
12592                            entire_line = clipboard_selection.is_entire_line;
12593                            start_offset = end_offset + 1;
12594                            original_indent_column = Some(clipboard_selection.first_line_indent);
12595                        } else {
12596                            to_insert = &*clipboard_text;
12597                            entire_line = all_selections_were_entire_line;
12598                            original_indent_column = first_selection_indent_column
12599                        }
12600
12601                        let (range, to_insert) =
12602                            if selection.is_empty() && handle_entire_lines && entire_line {
12603                                // If the corresponding selection was empty when this slice of the
12604                                // clipboard text was written, then the entire line containing the
12605                                // selection was copied. If this selection is also currently empty,
12606                                // then paste the line before the current line of the buffer.
12607                                let column = selection.start.to_point(&snapshot).column as usize;
12608                                let line_start = selection.start - column;
12609                                (line_start..line_start, Cow::Borrowed(to_insert))
12610                            } else {
12611                                let language = snapshot.language_at(selection.head());
12612                                let range = selection.range();
12613                                if let Some(language) = language
12614                                    && language.name() == "Markdown".into()
12615                                {
12616                                    edit_for_markdown_paste(
12617                                        &snapshot,
12618                                        range,
12619                                        to_insert,
12620                                        url::Url::parse(to_insert).ok(),
12621                                    )
12622                                } else {
12623                                    (range, Cow::Borrowed(to_insert))
12624                                }
12625                            };
12626
12627                        edits.push((range, to_insert));
12628                        original_indent_columns.push(original_indent_column);
12629                    }
12630                    drop(snapshot);
12631
12632                    buffer.edit(
12633                        edits,
12634                        if auto_indent_on_paste {
12635                            Some(AutoindentMode::Block {
12636                                original_indent_columns,
12637                            })
12638                        } else {
12639                            None
12640                        },
12641                        cx,
12642                    );
12643                });
12644
12645                let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
12646                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12647            } else {
12648                let url = url::Url::parse(&clipboard_text).ok();
12649
12650                let auto_indent_mode = if !clipboard_text.is_empty() {
12651                    Some(AutoindentMode::Block {
12652                        original_indent_columns: Vec::new(),
12653                    })
12654                } else {
12655                    None
12656                };
12657
12658                let selection_anchors = this.buffer.update(cx, |buffer, cx| {
12659                    let snapshot = buffer.snapshot(cx);
12660
12661                    let anchors = old_selections
12662                        .iter()
12663                        .map(|s| {
12664                            let anchor = snapshot.anchor_after(s.head());
12665                            s.map(|_| anchor)
12666                        })
12667                        .collect::<Vec<_>>();
12668
12669                    let mut edits = Vec::new();
12670
12671                    for selection in old_selections.iter() {
12672                        let language = snapshot.language_at(selection.head());
12673                        let range = selection.range();
12674
12675                        let (edit_range, edit_text) = if let Some(language) = language
12676                            && language.name() == "Markdown".into()
12677                        {
12678                            edit_for_markdown_paste(&snapshot, range, &clipboard_text, url.clone())
12679                        } else {
12680                            (range, clipboard_text.clone())
12681                        };
12682
12683                        edits.push((edit_range, edit_text));
12684                    }
12685
12686                    drop(snapshot);
12687                    buffer.edit(edits, auto_indent_mode, cx);
12688
12689                    anchors
12690                });
12691
12692                this.change_selections(Default::default(), window, cx, |s| {
12693                    s.select_anchors(selection_anchors);
12694                });
12695            }
12696
12697            let trigger_in_words =
12698                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
12699
12700            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
12701        });
12702    }
12703
12704    pub fn diff_clipboard_with_selection(
12705        &mut self,
12706        _: &DiffClipboardWithSelection,
12707        window: &mut Window,
12708        cx: &mut Context<Self>,
12709    ) {
12710        let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
12711
12712        if selections.is_empty() {
12713            log::warn!("There should always be at least one selection in Zed. This is a bug.");
12714            return;
12715        };
12716
12717        let clipboard_text = match cx.read_from_clipboard() {
12718            Some(item) => match item.entries().first() {
12719                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
12720                _ => None,
12721            },
12722            None => None,
12723        };
12724
12725        let Some(clipboard_text) = clipboard_text else {
12726            log::warn!("Clipboard doesn't contain text.");
12727            return;
12728        };
12729
12730        window.dispatch_action(
12731            Box::new(DiffClipboardWithSelectionData {
12732                clipboard_text,
12733                editor: cx.entity(),
12734            }),
12735            cx,
12736        );
12737    }
12738
12739    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
12740        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12741        if let Some(item) = cx.read_from_clipboard() {
12742            let entries = item.entries();
12743
12744            match entries.first() {
12745                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
12746                // of all the pasted entries.
12747                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
12748                    .do_paste(
12749                        clipboard_string.text(),
12750                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
12751                        true,
12752                        window,
12753                        cx,
12754                    ),
12755                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
12756            }
12757        }
12758    }
12759
12760    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
12761        if self.read_only(cx) {
12762            return;
12763        }
12764
12765        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12766
12767        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
12768            if let Some((selections, _)) =
12769                self.selection_history.transaction(transaction_id).cloned()
12770            {
12771                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12772                    s.select_anchors(selections.to_vec());
12773                });
12774            } else {
12775                log::error!(
12776                    "No entry in selection_history found for undo. \
12777                     This may correspond to a bug where undo does not update the selection. \
12778                     If this is occurring, please add details to \
12779                     https://github.com/zed-industries/zed/issues/22692"
12780                );
12781            }
12782            self.request_autoscroll(Autoscroll::fit(), cx);
12783            self.unmark_text(window, cx);
12784            self.refresh_edit_prediction(true, false, window, cx);
12785            cx.emit(EditorEvent::Edited { transaction_id });
12786            cx.emit(EditorEvent::TransactionUndone { transaction_id });
12787        }
12788    }
12789
12790    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
12791        if self.read_only(cx) {
12792            return;
12793        }
12794
12795        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12796
12797        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
12798            if let Some((_, Some(selections))) =
12799                self.selection_history.transaction(transaction_id).cloned()
12800            {
12801                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12802                    s.select_anchors(selections.to_vec());
12803                });
12804            } else {
12805                log::error!(
12806                    "No entry in selection_history found for redo. \
12807                     This may correspond to a bug where undo does not update the selection. \
12808                     If this is occurring, please add details to \
12809                     https://github.com/zed-industries/zed/issues/22692"
12810                );
12811            }
12812            self.request_autoscroll(Autoscroll::fit(), cx);
12813            self.unmark_text(window, cx);
12814            self.refresh_edit_prediction(true, false, window, cx);
12815            cx.emit(EditorEvent::Edited { transaction_id });
12816        }
12817    }
12818
12819    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
12820        self.buffer
12821            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
12822    }
12823
12824    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
12825        self.buffer
12826            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
12827    }
12828
12829    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
12830        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12831        self.change_selections(Default::default(), window, cx, |s| {
12832            s.move_with(|map, selection| {
12833                let cursor = if selection.is_empty() {
12834                    movement::left(map, selection.start)
12835                } else {
12836                    selection.start
12837                };
12838                selection.collapse_to(cursor, SelectionGoal::None);
12839            });
12840        })
12841    }
12842
12843    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
12844        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12845        self.change_selections(Default::default(), window, cx, |s| {
12846            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
12847        })
12848    }
12849
12850    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
12851        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12852        self.change_selections(Default::default(), window, cx, |s| {
12853            s.move_with(|map, selection| {
12854                let cursor = if selection.is_empty() {
12855                    movement::right(map, selection.end)
12856                } else {
12857                    selection.end
12858                };
12859                selection.collapse_to(cursor, SelectionGoal::None)
12860            });
12861        })
12862    }
12863
12864    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
12865        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12866        self.change_selections(Default::default(), window, cx, |s| {
12867            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
12868        });
12869    }
12870
12871    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
12872        if self.take_rename(true, window, cx).is_some() {
12873            return;
12874        }
12875
12876        if self.mode.is_single_line() {
12877            cx.propagate();
12878            return;
12879        }
12880
12881        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12882
12883        let text_layout_details = &self.text_layout_details(window);
12884        let selection_count = self.selections.count();
12885        let first_selection = self.selections.first_anchor();
12886
12887        self.change_selections(Default::default(), window, cx, |s| {
12888            s.move_with(|map, selection| {
12889                if !selection.is_empty() {
12890                    selection.goal = SelectionGoal::None;
12891                }
12892                let (cursor, goal) = movement::up(
12893                    map,
12894                    selection.start,
12895                    selection.goal,
12896                    false,
12897                    text_layout_details,
12898                );
12899                selection.collapse_to(cursor, goal);
12900            });
12901        });
12902
12903        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12904        {
12905            cx.propagate();
12906        }
12907    }
12908
12909    pub fn move_up_by_lines(
12910        &mut self,
12911        action: &MoveUpByLines,
12912        window: &mut Window,
12913        cx: &mut Context<Self>,
12914    ) {
12915        if self.take_rename(true, window, cx).is_some() {
12916            return;
12917        }
12918
12919        if self.mode.is_single_line() {
12920            cx.propagate();
12921            return;
12922        }
12923
12924        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12925
12926        let text_layout_details = &self.text_layout_details(window);
12927
12928        self.change_selections(Default::default(), window, cx, |s| {
12929            s.move_with(|map, selection| {
12930                if !selection.is_empty() {
12931                    selection.goal = SelectionGoal::None;
12932                }
12933                let (cursor, goal) = movement::up_by_rows(
12934                    map,
12935                    selection.start,
12936                    action.lines,
12937                    selection.goal,
12938                    false,
12939                    text_layout_details,
12940                );
12941                selection.collapse_to(cursor, goal);
12942            });
12943        })
12944    }
12945
12946    pub fn move_down_by_lines(
12947        &mut self,
12948        action: &MoveDownByLines,
12949        window: &mut Window,
12950        cx: &mut Context<Self>,
12951    ) {
12952        if self.take_rename(true, window, cx).is_some() {
12953            return;
12954        }
12955
12956        if self.mode.is_single_line() {
12957            cx.propagate();
12958            return;
12959        }
12960
12961        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12962
12963        let text_layout_details = &self.text_layout_details(window);
12964
12965        self.change_selections(Default::default(), window, cx, |s| {
12966            s.move_with(|map, selection| {
12967                if !selection.is_empty() {
12968                    selection.goal = SelectionGoal::None;
12969                }
12970                let (cursor, goal) = movement::down_by_rows(
12971                    map,
12972                    selection.start,
12973                    action.lines,
12974                    selection.goal,
12975                    false,
12976                    text_layout_details,
12977                );
12978                selection.collapse_to(cursor, goal);
12979            });
12980        })
12981    }
12982
12983    pub fn select_down_by_lines(
12984        &mut self,
12985        action: &SelectDownByLines,
12986        window: &mut Window,
12987        cx: &mut Context<Self>,
12988    ) {
12989        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12990        let text_layout_details = &self.text_layout_details(window);
12991        self.change_selections(Default::default(), window, cx, |s| {
12992            s.move_heads_with(|map, head, goal| {
12993                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
12994            })
12995        })
12996    }
12997
12998    pub fn select_up_by_lines(
12999        &mut self,
13000        action: &SelectUpByLines,
13001        window: &mut Window,
13002        cx: &mut Context<Self>,
13003    ) {
13004        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13005        let text_layout_details = &self.text_layout_details(window);
13006        self.change_selections(Default::default(), window, cx, |s| {
13007            s.move_heads_with(|map, head, goal| {
13008                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
13009            })
13010        })
13011    }
13012
13013    pub fn select_page_up(
13014        &mut self,
13015        _: &SelectPageUp,
13016        window: &mut Window,
13017        cx: &mut Context<Self>,
13018    ) {
13019        let Some(row_count) = self.visible_row_count() else {
13020            return;
13021        };
13022
13023        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13024
13025        let text_layout_details = &self.text_layout_details(window);
13026
13027        self.change_selections(Default::default(), window, cx, |s| {
13028            s.move_heads_with(|map, head, goal| {
13029                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
13030            })
13031        })
13032    }
13033
13034    pub fn move_page_up(
13035        &mut self,
13036        action: &MovePageUp,
13037        window: &mut Window,
13038        cx: &mut Context<Self>,
13039    ) {
13040        if self.take_rename(true, window, cx).is_some() {
13041            return;
13042        }
13043
13044        if self
13045            .context_menu
13046            .borrow_mut()
13047            .as_mut()
13048            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
13049            .unwrap_or(false)
13050        {
13051            return;
13052        }
13053
13054        if matches!(self.mode, EditorMode::SingleLine) {
13055            cx.propagate();
13056            return;
13057        }
13058
13059        let Some(row_count) = self.visible_row_count() else {
13060            return;
13061        };
13062
13063        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13064
13065        let effects = if action.center_cursor {
13066            SelectionEffects::scroll(Autoscroll::center())
13067        } else {
13068            SelectionEffects::default()
13069        };
13070
13071        let text_layout_details = &self.text_layout_details(window);
13072
13073        self.change_selections(effects, window, cx, |s| {
13074            s.move_with(|map, selection| {
13075                if !selection.is_empty() {
13076                    selection.goal = SelectionGoal::None;
13077                }
13078                let (cursor, goal) = movement::up_by_rows(
13079                    map,
13080                    selection.end,
13081                    row_count,
13082                    selection.goal,
13083                    false,
13084                    text_layout_details,
13085                );
13086                selection.collapse_to(cursor, goal);
13087            });
13088        });
13089    }
13090
13091    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
13092        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13093        let text_layout_details = &self.text_layout_details(window);
13094        self.change_selections(Default::default(), window, cx, |s| {
13095            s.move_heads_with(|map, head, goal| {
13096                movement::up(map, head, goal, false, text_layout_details)
13097            })
13098        })
13099    }
13100
13101    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
13102        self.take_rename(true, window, cx);
13103
13104        if self.mode.is_single_line() {
13105            cx.propagate();
13106            return;
13107        }
13108
13109        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13110
13111        let text_layout_details = &self.text_layout_details(window);
13112        let selection_count = self.selections.count();
13113        let first_selection = self.selections.first_anchor();
13114
13115        self.change_selections(Default::default(), window, cx, |s| {
13116            s.move_with(|map, selection| {
13117                if !selection.is_empty() {
13118                    selection.goal = SelectionGoal::None;
13119                }
13120                let (cursor, goal) = movement::down(
13121                    map,
13122                    selection.end,
13123                    selection.goal,
13124                    false,
13125                    text_layout_details,
13126                );
13127                selection.collapse_to(cursor, goal);
13128            });
13129        });
13130
13131        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13132        {
13133            cx.propagate();
13134        }
13135    }
13136
13137    pub fn select_page_down(
13138        &mut self,
13139        _: &SelectPageDown,
13140        window: &mut Window,
13141        cx: &mut Context<Self>,
13142    ) {
13143        let Some(row_count) = self.visible_row_count() else {
13144            return;
13145        };
13146
13147        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13148
13149        let text_layout_details = &self.text_layout_details(window);
13150
13151        self.change_selections(Default::default(), window, cx, |s| {
13152            s.move_heads_with(|map, head, goal| {
13153                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
13154            })
13155        })
13156    }
13157
13158    pub fn move_page_down(
13159        &mut self,
13160        action: &MovePageDown,
13161        window: &mut Window,
13162        cx: &mut Context<Self>,
13163    ) {
13164        if self.take_rename(true, window, cx).is_some() {
13165            return;
13166        }
13167
13168        if self
13169            .context_menu
13170            .borrow_mut()
13171            .as_mut()
13172            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
13173            .unwrap_or(false)
13174        {
13175            return;
13176        }
13177
13178        if matches!(self.mode, EditorMode::SingleLine) {
13179            cx.propagate();
13180            return;
13181        }
13182
13183        let Some(row_count) = self.visible_row_count() else {
13184            return;
13185        };
13186
13187        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13188
13189        let effects = if action.center_cursor {
13190            SelectionEffects::scroll(Autoscroll::center())
13191        } else {
13192            SelectionEffects::default()
13193        };
13194
13195        let text_layout_details = &self.text_layout_details(window);
13196        self.change_selections(effects, window, cx, |s| {
13197            s.move_with(|map, selection| {
13198                if !selection.is_empty() {
13199                    selection.goal = SelectionGoal::None;
13200                }
13201                let (cursor, goal) = movement::down_by_rows(
13202                    map,
13203                    selection.end,
13204                    row_count,
13205                    selection.goal,
13206                    false,
13207                    text_layout_details,
13208                );
13209                selection.collapse_to(cursor, goal);
13210            });
13211        });
13212    }
13213
13214    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
13215        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13216        let text_layout_details = &self.text_layout_details(window);
13217        self.change_selections(Default::default(), window, cx, |s| {
13218            s.move_heads_with(|map, head, goal| {
13219                movement::down(map, head, goal, false, text_layout_details)
13220            })
13221        });
13222    }
13223
13224    pub fn context_menu_first(
13225        &mut self,
13226        _: &ContextMenuFirst,
13227        window: &mut Window,
13228        cx: &mut Context<Self>,
13229    ) {
13230        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13231            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
13232        }
13233    }
13234
13235    pub fn context_menu_prev(
13236        &mut self,
13237        _: &ContextMenuPrevious,
13238        window: &mut Window,
13239        cx: &mut Context<Self>,
13240    ) {
13241        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13242            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
13243        }
13244    }
13245
13246    pub fn context_menu_next(
13247        &mut self,
13248        _: &ContextMenuNext,
13249        window: &mut Window,
13250        cx: &mut Context<Self>,
13251    ) {
13252        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13253            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
13254        }
13255    }
13256
13257    pub fn context_menu_last(
13258        &mut self,
13259        _: &ContextMenuLast,
13260        window: &mut Window,
13261        cx: &mut Context<Self>,
13262    ) {
13263        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13264            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
13265        }
13266    }
13267
13268    pub fn signature_help_prev(
13269        &mut self,
13270        _: &SignatureHelpPrevious,
13271        _: &mut Window,
13272        cx: &mut Context<Self>,
13273    ) {
13274        if let Some(popover) = self.signature_help_state.popover_mut() {
13275            if popover.current_signature == 0 {
13276                popover.current_signature = popover.signatures.len() - 1;
13277            } else {
13278                popover.current_signature -= 1;
13279            }
13280            cx.notify();
13281        }
13282    }
13283
13284    pub fn signature_help_next(
13285        &mut self,
13286        _: &SignatureHelpNext,
13287        _: &mut Window,
13288        cx: &mut Context<Self>,
13289    ) {
13290        if let Some(popover) = self.signature_help_state.popover_mut() {
13291            if popover.current_signature + 1 == popover.signatures.len() {
13292                popover.current_signature = 0;
13293            } else {
13294                popover.current_signature += 1;
13295            }
13296            cx.notify();
13297        }
13298    }
13299
13300    pub fn move_to_previous_word_start(
13301        &mut self,
13302        _: &MoveToPreviousWordStart,
13303        window: &mut Window,
13304        cx: &mut Context<Self>,
13305    ) {
13306        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13307        self.change_selections(Default::default(), window, cx, |s| {
13308            s.move_cursors_with(|map, head, _| {
13309                (
13310                    movement::previous_word_start(map, head),
13311                    SelectionGoal::None,
13312                )
13313            });
13314        })
13315    }
13316
13317    pub fn move_to_previous_subword_start(
13318        &mut self,
13319        _: &MoveToPreviousSubwordStart,
13320        window: &mut Window,
13321        cx: &mut Context<Self>,
13322    ) {
13323        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13324        self.change_selections(Default::default(), window, cx, |s| {
13325            s.move_cursors_with(|map, head, _| {
13326                (
13327                    movement::previous_subword_start(map, head),
13328                    SelectionGoal::None,
13329                )
13330            });
13331        })
13332    }
13333
13334    pub fn select_to_previous_word_start(
13335        &mut self,
13336        _: &SelectToPreviousWordStart,
13337        window: &mut Window,
13338        cx: &mut Context<Self>,
13339    ) {
13340        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13341        self.change_selections(Default::default(), window, cx, |s| {
13342            s.move_heads_with(|map, head, _| {
13343                (
13344                    movement::previous_word_start(map, head),
13345                    SelectionGoal::None,
13346                )
13347            });
13348        })
13349    }
13350
13351    pub fn select_to_previous_subword_start(
13352        &mut self,
13353        _: &SelectToPreviousSubwordStart,
13354        window: &mut Window,
13355        cx: &mut Context<Self>,
13356    ) {
13357        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13358        self.change_selections(Default::default(), window, cx, |s| {
13359            s.move_heads_with(|map, head, _| {
13360                (
13361                    movement::previous_subword_start(map, head),
13362                    SelectionGoal::None,
13363                )
13364            });
13365        })
13366    }
13367
13368    pub fn delete_to_previous_word_start(
13369        &mut self,
13370        action: &DeleteToPreviousWordStart,
13371        window: &mut Window,
13372        cx: &mut Context<Self>,
13373    ) {
13374        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13375        self.transact(window, cx, |this, window, cx| {
13376            this.select_autoclose_pair(window, cx);
13377            this.change_selections(Default::default(), window, cx, |s| {
13378                s.move_with(|map, selection| {
13379                    if selection.is_empty() {
13380                        let mut cursor = if action.ignore_newlines {
13381                            movement::previous_word_start(map, selection.head())
13382                        } else {
13383                            movement::previous_word_start_or_newline(map, selection.head())
13384                        };
13385                        cursor = movement::adjust_greedy_deletion(
13386                            map,
13387                            selection.head(),
13388                            cursor,
13389                            action.ignore_brackets,
13390                        );
13391                        selection.set_head(cursor, SelectionGoal::None);
13392                    }
13393                });
13394            });
13395            this.insert("", window, cx);
13396        });
13397    }
13398
13399    pub fn delete_to_previous_subword_start(
13400        &mut self,
13401        _: &DeleteToPreviousSubwordStart,
13402        window: &mut Window,
13403        cx: &mut Context<Self>,
13404    ) {
13405        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13406        self.transact(window, cx, |this, window, cx| {
13407            this.select_autoclose_pair(window, cx);
13408            this.change_selections(Default::default(), window, cx, |s| {
13409                s.move_with(|map, selection| {
13410                    if selection.is_empty() {
13411                        let mut cursor = movement::previous_subword_start(map, selection.head());
13412                        cursor =
13413                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13414                        selection.set_head(cursor, SelectionGoal::None);
13415                    }
13416                });
13417            });
13418            this.insert("", window, cx);
13419        });
13420    }
13421
13422    pub fn move_to_next_word_end(
13423        &mut self,
13424        _: &MoveToNextWordEnd,
13425        window: &mut Window,
13426        cx: &mut Context<Self>,
13427    ) {
13428        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13429        self.change_selections(Default::default(), window, cx, |s| {
13430            s.move_cursors_with(|map, head, _| {
13431                (movement::next_word_end(map, head), SelectionGoal::None)
13432            });
13433        })
13434    }
13435
13436    pub fn move_to_next_subword_end(
13437        &mut self,
13438        _: &MoveToNextSubwordEnd,
13439        window: &mut Window,
13440        cx: &mut Context<Self>,
13441    ) {
13442        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13443        self.change_selections(Default::default(), window, cx, |s| {
13444            s.move_cursors_with(|map, head, _| {
13445                (movement::next_subword_end(map, head), SelectionGoal::None)
13446            });
13447        })
13448    }
13449
13450    pub fn select_to_next_word_end(
13451        &mut self,
13452        _: &SelectToNextWordEnd,
13453        window: &mut Window,
13454        cx: &mut Context<Self>,
13455    ) {
13456        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13457        self.change_selections(Default::default(), window, cx, |s| {
13458            s.move_heads_with(|map, head, _| {
13459                (movement::next_word_end(map, head), SelectionGoal::None)
13460            });
13461        })
13462    }
13463
13464    pub fn select_to_next_subword_end(
13465        &mut self,
13466        _: &SelectToNextSubwordEnd,
13467        window: &mut Window,
13468        cx: &mut Context<Self>,
13469    ) {
13470        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13471        self.change_selections(Default::default(), window, cx, |s| {
13472            s.move_heads_with(|map, head, _| {
13473                (movement::next_subword_end(map, head), SelectionGoal::None)
13474            });
13475        })
13476    }
13477
13478    pub fn delete_to_next_word_end(
13479        &mut self,
13480        action: &DeleteToNextWordEnd,
13481        window: &mut Window,
13482        cx: &mut Context<Self>,
13483    ) {
13484        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13485        self.transact(window, cx, |this, window, cx| {
13486            this.change_selections(Default::default(), window, cx, |s| {
13487                s.move_with(|map, selection| {
13488                    if selection.is_empty() {
13489                        let mut cursor = if action.ignore_newlines {
13490                            movement::next_word_end(map, selection.head())
13491                        } else {
13492                            movement::next_word_end_or_newline(map, selection.head())
13493                        };
13494                        cursor = movement::adjust_greedy_deletion(
13495                            map,
13496                            selection.head(),
13497                            cursor,
13498                            action.ignore_brackets,
13499                        );
13500                        selection.set_head(cursor, SelectionGoal::None);
13501                    }
13502                });
13503            });
13504            this.insert("", window, cx);
13505        });
13506    }
13507
13508    pub fn delete_to_next_subword_end(
13509        &mut self,
13510        _: &DeleteToNextSubwordEnd,
13511        window: &mut Window,
13512        cx: &mut Context<Self>,
13513    ) {
13514        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13515        self.transact(window, cx, |this, window, cx| {
13516            this.change_selections(Default::default(), window, cx, |s| {
13517                s.move_with(|map, selection| {
13518                    if selection.is_empty() {
13519                        let mut cursor = movement::next_subword_end(map, selection.head());
13520                        cursor =
13521                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13522                        selection.set_head(cursor, SelectionGoal::None);
13523                    }
13524                });
13525            });
13526            this.insert("", window, cx);
13527        });
13528    }
13529
13530    pub fn move_to_beginning_of_line(
13531        &mut self,
13532        action: &MoveToBeginningOfLine,
13533        window: &mut Window,
13534        cx: &mut Context<Self>,
13535    ) {
13536        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13537        self.change_selections(Default::default(), window, cx, |s| {
13538            s.move_cursors_with(|map, head, _| {
13539                (
13540                    movement::indented_line_beginning(
13541                        map,
13542                        head,
13543                        action.stop_at_soft_wraps,
13544                        action.stop_at_indent,
13545                    ),
13546                    SelectionGoal::None,
13547                )
13548            });
13549        })
13550    }
13551
13552    pub fn select_to_beginning_of_line(
13553        &mut self,
13554        action: &SelectToBeginningOfLine,
13555        window: &mut Window,
13556        cx: &mut Context<Self>,
13557    ) {
13558        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13559        self.change_selections(Default::default(), window, cx, |s| {
13560            s.move_heads_with(|map, head, _| {
13561                (
13562                    movement::indented_line_beginning(
13563                        map,
13564                        head,
13565                        action.stop_at_soft_wraps,
13566                        action.stop_at_indent,
13567                    ),
13568                    SelectionGoal::None,
13569                )
13570            });
13571        });
13572    }
13573
13574    pub fn delete_to_beginning_of_line(
13575        &mut self,
13576        action: &DeleteToBeginningOfLine,
13577        window: &mut Window,
13578        cx: &mut Context<Self>,
13579    ) {
13580        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13581        self.transact(window, cx, |this, window, cx| {
13582            this.change_selections(Default::default(), window, cx, |s| {
13583                s.move_with(|_, selection| {
13584                    selection.reversed = true;
13585                });
13586            });
13587
13588            this.select_to_beginning_of_line(
13589                &SelectToBeginningOfLine {
13590                    stop_at_soft_wraps: false,
13591                    stop_at_indent: action.stop_at_indent,
13592                },
13593                window,
13594                cx,
13595            );
13596            this.backspace(&Backspace, window, cx);
13597        });
13598    }
13599
13600    pub fn move_to_end_of_line(
13601        &mut self,
13602        action: &MoveToEndOfLine,
13603        window: &mut Window,
13604        cx: &mut Context<Self>,
13605    ) {
13606        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13607        self.change_selections(Default::default(), window, cx, |s| {
13608            s.move_cursors_with(|map, head, _| {
13609                (
13610                    movement::line_end(map, head, action.stop_at_soft_wraps),
13611                    SelectionGoal::None,
13612                )
13613            });
13614        })
13615    }
13616
13617    pub fn select_to_end_of_line(
13618        &mut self,
13619        action: &SelectToEndOfLine,
13620        window: &mut Window,
13621        cx: &mut Context<Self>,
13622    ) {
13623        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13624        self.change_selections(Default::default(), window, cx, |s| {
13625            s.move_heads_with(|map, head, _| {
13626                (
13627                    movement::line_end(map, head, action.stop_at_soft_wraps),
13628                    SelectionGoal::None,
13629                )
13630            });
13631        })
13632    }
13633
13634    pub fn delete_to_end_of_line(
13635        &mut self,
13636        _: &DeleteToEndOfLine,
13637        window: &mut Window,
13638        cx: &mut Context<Self>,
13639    ) {
13640        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13641        self.transact(window, cx, |this, window, cx| {
13642            this.select_to_end_of_line(
13643                &SelectToEndOfLine {
13644                    stop_at_soft_wraps: false,
13645                },
13646                window,
13647                cx,
13648            );
13649            this.delete(&Delete, window, cx);
13650        });
13651    }
13652
13653    pub fn cut_to_end_of_line(
13654        &mut self,
13655        action: &CutToEndOfLine,
13656        window: &mut Window,
13657        cx: &mut Context<Self>,
13658    ) {
13659        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13660        self.transact(window, cx, |this, window, cx| {
13661            this.select_to_end_of_line(
13662                &SelectToEndOfLine {
13663                    stop_at_soft_wraps: false,
13664                },
13665                window,
13666                cx,
13667            );
13668            if !action.stop_at_newlines {
13669                this.change_selections(Default::default(), window, cx, |s| {
13670                    s.move_with(|_, sel| {
13671                        if sel.is_empty() {
13672                            sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
13673                        }
13674                    });
13675                });
13676            }
13677            this.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13678            let item = this.cut_common(false, window, cx);
13679            cx.write_to_clipboard(item);
13680        });
13681    }
13682
13683    pub fn move_to_start_of_paragraph(
13684        &mut self,
13685        _: &MoveToStartOfParagraph,
13686        window: &mut Window,
13687        cx: &mut Context<Self>,
13688    ) {
13689        if matches!(self.mode, EditorMode::SingleLine) {
13690            cx.propagate();
13691            return;
13692        }
13693        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13694        self.change_selections(Default::default(), window, cx, |s| {
13695            s.move_with(|map, selection| {
13696                selection.collapse_to(
13697                    movement::start_of_paragraph(map, selection.head(), 1),
13698                    SelectionGoal::None,
13699                )
13700            });
13701        })
13702    }
13703
13704    pub fn move_to_end_of_paragraph(
13705        &mut self,
13706        _: &MoveToEndOfParagraph,
13707        window: &mut Window,
13708        cx: &mut Context<Self>,
13709    ) {
13710        if matches!(self.mode, EditorMode::SingleLine) {
13711            cx.propagate();
13712            return;
13713        }
13714        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13715        self.change_selections(Default::default(), window, cx, |s| {
13716            s.move_with(|map, selection| {
13717                selection.collapse_to(
13718                    movement::end_of_paragraph(map, selection.head(), 1),
13719                    SelectionGoal::None,
13720                )
13721            });
13722        })
13723    }
13724
13725    pub fn select_to_start_of_paragraph(
13726        &mut self,
13727        _: &SelectToStartOfParagraph,
13728        window: &mut Window,
13729        cx: &mut Context<Self>,
13730    ) {
13731        if matches!(self.mode, EditorMode::SingleLine) {
13732            cx.propagate();
13733            return;
13734        }
13735        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13736        self.change_selections(Default::default(), window, cx, |s| {
13737            s.move_heads_with(|map, head, _| {
13738                (
13739                    movement::start_of_paragraph(map, head, 1),
13740                    SelectionGoal::None,
13741                )
13742            });
13743        })
13744    }
13745
13746    pub fn select_to_end_of_paragraph(
13747        &mut self,
13748        _: &SelectToEndOfParagraph,
13749        window: &mut Window,
13750        cx: &mut Context<Self>,
13751    ) {
13752        if matches!(self.mode, EditorMode::SingleLine) {
13753            cx.propagate();
13754            return;
13755        }
13756        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13757        self.change_selections(Default::default(), window, cx, |s| {
13758            s.move_heads_with(|map, head, _| {
13759                (
13760                    movement::end_of_paragraph(map, head, 1),
13761                    SelectionGoal::None,
13762                )
13763            });
13764        })
13765    }
13766
13767    pub fn move_to_start_of_excerpt(
13768        &mut self,
13769        _: &MoveToStartOfExcerpt,
13770        window: &mut Window,
13771        cx: &mut Context<Self>,
13772    ) {
13773        if matches!(self.mode, EditorMode::SingleLine) {
13774            cx.propagate();
13775            return;
13776        }
13777        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13778        self.change_selections(Default::default(), window, cx, |s| {
13779            s.move_with(|map, selection| {
13780                selection.collapse_to(
13781                    movement::start_of_excerpt(
13782                        map,
13783                        selection.head(),
13784                        workspace::searchable::Direction::Prev,
13785                    ),
13786                    SelectionGoal::None,
13787                )
13788            });
13789        })
13790    }
13791
13792    pub fn move_to_start_of_next_excerpt(
13793        &mut self,
13794        _: &MoveToStartOfNextExcerpt,
13795        window: &mut Window,
13796        cx: &mut Context<Self>,
13797    ) {
13798        if matches!(self.mode, EditorMode::SingleLine) {
13799            cx.propagate();
13800            return;
13801        }
13802
13803        self.change_selections(Default::default(), window, cx, |s| {
13804            s.move_with(|map, selection| {
13805                selection.collapse_to(
13806                    movement::start_of_excerpt(
13807                        map,
13808                        selection.head(),
13809                        workspace::searchable::Direction::Next,
13810                    ),
13811                    SelectionGoal::None,
13812                )
13813            });
13814        })
13815    }
13816
13817    pub fn move_to_end_of_excerpt(
13818        &mut self,
13819        _: &MoveToEndOfExcerpt,
13820        window: &mut Window,
13821        cx: &mut Context<Self>,
13822    ) {
13823        if matches!(self.mode, EditorMode::SingleLine) {
13824            cx.propagate();
13825            return;
13826        }
13827        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13828        self.change_selections(Default::default(), window, cx, |s| {
13829            s.move_with(|map, selection| {
13830                selection.collapse_to(
13831                    movement::end_of_excerpt(
13832                        map,
13833                        selection.head(),
13834                        workspace::searchable::Direction::Next,
13835                    ),
13836                    SelectionGoal::None,
13837                )
13838            });
13839        })
13840    }
13841
13842    pub fn move_to_end_of_previous_excerpt(
13843        &mut self,
13844        _: &MoveToEndOfPreviousExcerpt,
13845        window: &mut Window,
13846        cx: &mut Context<Self>,
13847    ) {
13848        if matches!(self.mode, EditorMode::SingleLine) {
13849            cx.propagate();
13850            return;
13851        }
13852        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13853        self.change_selections(Default::default(), window, cx, |s| {
13854            s.move_with(|map, selection| {
13855                selection.collapse_to(
13856                    movement::end_of_excerpt(
13857                        map,
13858                        selection.head(),
13859                        workspace::searchable::Direction::Prev,
13860                    ),
13861                    SelectionGoal::None,
13862                )
13863            });
13864        })
13865    }
13866
13867    pub fn select_to_start_of_excerpt(
13868        &mut self,
13869        _: &SelectToStartOfExcerpt,
13870        window: &mut Window,
13871        cx: &mut Context<Self>,
13872    ) {
13873        if matches!(self.mode, EditorMode::SingleLine) {
13874            cx.propagate();
13875            return;
13876        }
13877        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13878        self.change_selections(Default::default(), window, cx, |s| {
13879            s.move_heads_with(|map, head, _| {
13880                (
13881                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13882                    SelectionGoal::None,
13883                )
13884            });
13885        })
13886    }
13887
13888    pub fn select_to_start_of_next_excerpt(
13889        &mut self,
13890        _: &SelectToStartOfNextExcerpt,
13891        window: &mut Window,
13892        cx: &mut Context<Self>,
13893    ) {
13894        if matches!(self.mode, EditorMode::SingleLine) {
13895            cx.propagate();
13896            return;
13897        }
13898        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13899        self.change_selections(Default::default(), window, cx, |s| {
13900            s.move_heads_with(|map, head, _| {
13901                (
13902                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
13903                    SelectionGoal::None,
13904                )
13905            });
13906        })
13907    }
13908
13909    pub fn select_to_end_of_excerpt(
13910        &mut self,
13911        _: &SelectToEndOfExcerpt,
13912        window: &mut Window,
13913        cx: &mut Context<Self>,
13914    ) {
13915        if matches!(self.mode, EditorMode::SingleLine) {
13916            cx.propagate();
13917            return;
13918        }
13919        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13920        self.change_selections(Default::default(), window, cx, |s| {
13921            s.move_heads_with(|map, head, _| {
13922                (
13923                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
13924                    SelectionGoal::None,
13925                )
13926            });
13927        })
13928    }
13929
13930    pub fn select_to_end_of_previous_excerpt(
13931        &mut self,
13932        _: &SelectToEndOfPreviousExcerpt,
13933        window: &mut Window,
13934        cx: &mut Context<Self>,
13935    ) {
13936        if matches!(self.mode, EditorMode::SingleLine) {
13937            cx.propagate();
13938            return;
13939        }
13940        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13941        self.change_selections(Default::default(), window, cx, |s| {
13942            s.move_heads_with(|map, head, _| {
13943                (
13944                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13945                    SelectionGoal::None,
13946                )
13947            });
13948        })
13949    }
13950
13951    pub fn move_to_beginning(
13952        &mut self,
13953        _: &MoveToBeginning,
13954        window: &mut Window,
13955        cx: &mut Context<Self>,
13956    ) {
13957        if matches!(self.mode, EditorMode::SingleLine) {
13958            cx.propagate();
13959            return;
13960        }
13961        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13962        self.change_selections(Default::default(), window, cx, |s| {
13963            s.select_ranges(vec![0..0]);
13964        });
13965    }
13966
13967    pub fn select_to_beginning(
13968        &mut self,
13969        _: &SelectToBeginning,
13970        window: &mut Window,
13971        cx: &mut Context<Self>,
13972    ) {
13973        let mut selection = self.selections.last::<Point>(&self.display_snapshot(cx));
13974        selection.set_head(Point::zero(), SelectionGoal::None);
13975        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13976        self.change_selections(Default::default(), window, cx, |s| {
13977            s.select(vec![selection]);
13978        });
13979    }
13980
13981    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
13982        if matches!(self.mode, EditorMode::SingleLine) {
13983            cx.propagate();
13984            return;
13985        }
13986        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13987        let cursor = self.buffer.read(cx).read(cx).len();
13988        self.change_selections(Default::default(), window, cx, |s| {
13989            s.select_ranges(vec![cursor..cursor])
13990        });
13991    }
13992
13993    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
13994        self.nav_history = nav_history;
13995    }
13996
13997    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
13998        self.nav_history.as_ref()
13999    }
14000
14001    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
14002        self.push_to_nav_history(
14003            self.selections.newest_anchor().head(),
14004            None,
14005            false,
14006            true,
14007            cx,
14008        );
14009    }
14010
14011    fn push_to_nav_history(
14012        &mut self,
14013        cursor_anchor: Anchor,
14014        new_position: Option<Point>,
14015        is_deactivate: bool,
14016        always: bool,
14017        cx: &mut Context<Self>,
14018    ) {
14019        if let Some(nav_history) = self.nav_history.as_mut() {
14020            let buffer = self.buffer.read(cx).read(cx);
14021            let cursor_position = cursor_anchor.to_point(&buffer);
14022            let scroll_state = self.scroll_manager.anchor();
14023            let scroll_top_row = scroll_state.top_row(&buffer);
14024            drop(buffer);
14025
14026            if let Some(new_position) = new_position {
14027                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
14028                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
14029                    return;
14030                }
14031            }
14032
14033            nav_history.push(
14034                Some(NavigationData {
14035                    cursor_anchor,
14036                    cursor_position,
14037                    scroll_anchor: scroll_state,
14038                    scroll_top_row,
14039                }),
14040                cx,
14041            );
14042            cx.emit(EditorEvent::PushedToNavHistory {
14043                anchor: cursor_anchor,
14044                is_deactivate,
14045            })
14046        }
14047    }
14048
14049    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
14050        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14051        let buffer = self.buffer.read(cx).snapshot(cx);
14052        let mut selection = self.selections.first::<usize>(&self.display_snapshot(cx));
14053        selection.set_head(buffer.len(), SelectionGoal::None);
14054        self.change_selections(Default::default(), window, cx, |s| {
14055            s.select(vec![selection]);
14056        });
14057    }
14058
14059    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
14060        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14061        let end = self.buffer.read(cx).read(cx).len();
14062        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14063            s.select_ranges(vec![0..end]);
14064        });
14065    }
14066
14067    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
14068        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14069        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14070        let mut selections = self.selections.all::<Point>(&display_map);
14071        let max_point = display_map.buffer_snapshot().max_point();
14072        for selection in &mut selections {
14073            let rows = selection.spanned_rows(true, &display_map);
14074            selection.start = Point::new(rows.start.0, 0);
14075            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
14076            selection.reversed = false;
14077        }
14078        self.change_selections(Default::default(), window, cx, |s| {
14079            s.select(selections);
14080        });
14081    }
14082
14083    pub fn split_selection_into_lines(
14084        &mut self,
14085        action: &SplitSelectionIntoLines,
14086        window: &mut Window,
14087        cx: &mut Context<Self>,
14088    ) {
14089        let selections = self
14090            .selections
14091            .all::<Point>(&self.display_snapshot(cx))
14092            .into_iter()
14093            .map(|selection| selection.start..selection.end)
14094            .collect::<Vec<_>>();
14095        self.unfold_ranges(&selections, true, true, cx);
14096
14097        let mut new_selection_ranges = Vec::new();
14098        {
14099            let buffer = self.buffer.read(cx).read(cx);
14100            for selection in selections {
14101                for row in selection.start.row..selection.end.row {
14102                    let line_start = Point::new(row, 0);
14103                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
14104
14105                    if action.keep_selections {
14106                        // Keep the selection range for each line
14107                        let selection_start = if row == selection.start.row {
14108                            selection.start
14109                        } else {
14110                            line_start
14111                        };
14112                        new_selection_ranges.push(selection_start..line_end);
14113                    } else {
14114                        // Collapse to cursor at end of line
14115                        new_selection_ranges.push(line_end..line_end);
14116                    }
14117                }
14118
14119                let is_multiline_selection = selection.start.row != selection.end.row;
14120                // Don't insert last one if it's a multi-line selection ending at the start of a line,
14121                // so this action feels more ergonomic when paired with other selection operations
14122                let should_skip_last = is_multiline_selection && selection.end.column == 0;
14123                if !should_skip_last {
14124                    if action.keep_selections {
14125                        if is_multiline_selection {
14126                            let line_start = Point::new(selection.end.row, 0);
14127                            new_selection_ranges.push(line_start..selection.end);
14128                        } else {
14129                            new_selection_ranges.push(selection.start..selection.end);
14130                        }
14131                    } else {
14132                        new_selection_ranges.push(selection.end..selection.end);
14133                    }
14134                }
14135            }
14136        }
14137        self.change_selections(Default::default(), window, cx, |s| {
14138            s.select_ranges(new_selection_ranges);
14139        });
14140    }
14141
14142    pub fn add_selection_above(
14143        &mut self,
14144        action: &AddSelectionAbove,
14145        window: &mut Window,
14146        cx: &mut Context<Self>,
14147    ) {
14148        self.add_selection(true, action.skip_soft_wrap, window, cx);
14149    }
14150
14151    pub fn add_selection_below(
14152        &mut self,
14153        action: &AddSelectionBelow,
14154        window: &mut Window,
14155        cx: &mut Context<Self>,
14156    ) {
14157        self.add_selection(false, action.skip_soft_wrap, window, cx);
14158    }
14159
14160    fn add_selection(
14161        &mut self,
14162        above: bool,
14163        skip_soft_wrap: bool,
14164        window: &mut Window,
14165        cx: &mut Context<Self>,
14166    ) {
14167        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14168
14169        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14170        let all_selections = self.selections.all::<Point>(&display_map);
14171        let text_layout_details = self.text_layout_details(window);
14172
14173        let (mut columnar_selections, new_selections_to_columnarize) = {
14174            if let Some(state) = self.add_selections_state.as_ref() {
14175                let columnar_selection_ids: HashSet<_> = state
14176                    .groups
14177                    .iter()
14178                    .flat_map(|group| group.stack.iter())
14179                    .copied()
14180                    .collect();
14181
14182                all_selections
14183                    .into_iter()
14184                    .partition(|s| columnar_selection_ids.contains(&s.id))
14185            } else {
14186                (Vec::new(), all_selections)
14187            }
14188        };
14189
14190        let mut state = self
14191            .add_selections_state
14192            .take()
14193            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
14194
14195        for selection in new_selections_to_columnarize {
14196            let range = selection.display_range(&display_map).sorted();
14197            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
14198            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
14199            let positions = start_x.min(end_x)..start_x.max(end_x);
14200            let mut stack = Vec::new();
14201            for row in range.start.row().0..=range.end.row().0 {
14202                if let Some(selection) = self.selections.build_columnar_selection(
14203                    &display_map,
14204                    DisplayRow(row),
14205                    &positions,
14206                    selection.reversed,
14207                    &text_layout_details,
14208                ) {
14209                    stack.push(selection.id);
14210                    columnar_selections.push(selection);
14211                }
14212            }
14213            if !stack.is_empty() {
14214                if above {
14215                    stack.reverse();
14216                }
14217                state.groups.push(AddSelectionsGroup { above, stack });
14218            }
14219        }
14220
14221        let mut final_selections = Vec::new();
14222        let end_row = if above {
14223            DisplayRow(0)
14224        } else {
14225            display_map.max_point().row()
14226        };
14227
14228        let mut last_added_item_per_group = HashMap::default();
14229        for group in state.groups.iter_mut() {
14230            if let Some(last_id) = group.stack.last() {
14231                last_added_item_per_group.insert(*last_id, group);
14232            }
14233        }
14234
14235        for selection in columnar_selections {
14236            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
14237                if above == group.above {
14238                    let range = selection.display_range(&display_map).sorted();
14239                    debug_assert_eq!(range.start.row(), range.end.row());
14240                    let mut row = range.start.row();
14241                    let positions =
14242                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
14243                            Pixels::from(start)..Pixels::from(end)
14244                        } else {
14245                            let start_x =
14246                                display_map.x_for_display_point(range.start, &text_layout_details);
14247                            let end_x =
14248                                display_map.x_for_display_point(range.end, &text_layout_details);
14249                            start_x.min(end_x)..start_x.max(end_x)
14250                        };
14251
14252                    let mut maybe_new_selection = None;
14253                    let direction = if above { -1 } else { 1 };
14254
14255                    while row != end_row {
14256                        if skip_soft_wrap {
14257                            row = display_map
14258                                .start_of_relative_buffer_row(DisplayPoint::new(row, 0), direction)
14259                                .row();
14260                        } else if above {
14261                            row.0 -= 1;
14262                        } else {
14263                            row.0 += 1;
14264                        }
14265
14266                        if let Some(new_selection) = self.selections.build_columnar_selection(
14267                            &display_map,
14268                            row,
14269                            &positions,
14270                            selection.reversed,
14271                            &text_layout_details,
14272                        ) {
14273                            maybe_new_selection = Some(new_selection);
14274                            break;
14275                        }
14276                    }
14277
14278                    if let Some(new_selection) = maybe_new_selection {
14279                        group.stack.push(new_selection.id);
14280                        if above {
14281                            final_selections.push(new_selection);
14282                            final_selections.push(selection);
14283                        } else {
14284                            final_selections.push(selection);
14285                            final_selections.push(new_selection);
14286                        }
14287                    } else {
14288                        final_selections.push(selection);
14289                    }
14290                } else {
14291                    group.stack.pop();
14292                }
14293            } else {
14294                final_selections.push(selection);
14295            }
14296        }
14297
14298        self.change_selections(Default::default(), window, cx, |s| {
14299            s.select(final_selections);
14300        });
14301
14302        let final_selection_ids: HashSet<_> = self
14303            .selections
14304            .all::<Point>(&display_map)
14305            .iter()
14306            .map(|s| s.id)
14307            .collect();
14308        state.groups.retain_mut(|group| {
14309            // selections might get merged above so we remove invalid items from stacks
14310            group.stack.retain(|id| final_selection_ids.contains(id));
14311
14312            // single selection in stack can be treated as initial state
14313            group.stack.len() > 1
14314        });
14315
14316        if !state.groups.is_empty() {
14317            self.add_selections_state = Some(state);
14318        }
14319    }
14320
14321    fn select_match_ranges(
14322        &mut self,
14323        range: Range<usize>,
14324        reversed: bool,
14325        replace_newest: bool,
14326        auto_scroll: Option<Autoscroll>,
14327        window: &mut Window,
14328        cx: &mut Context<Editor>,
14329    ) {
14330        self.unfold_ranges(
14331            std::slice::from_ref(&range),
14332            false,
14333            auto_scroll.is_some(),
14334            cx,
14335        );
14336        let effects = if let Some(scroll) = auto_scroll {
14337            SelectionEffects::scroll(scroll)
14338        } else {
14339            SelectionEffects::no_scroll()
14340        };
14341        self.change_selections(effects, window, cx, |s| {
14342            if replace_newest {
14343                s.delete(s.newest_anchor().id);
14344            }
14345            if reversed {
14346                s.insert_range(range.end..range.start);
14347            } else {
14348                s.insert_range(range);
14349            }
14350        });
14351    }
14352
14353    pub fn select_next_match_internal(
14354        &mut self,
14355        display_map: &DisplaySnapshot,
14356        replace_newest: bool,
14357        autoscroll: Option<Autoscroll>,
14358        window: &mut Window,
14359        cx: &mut Context<Self>,
14360    ) -> Result<()> {
14361        let buffer = display_map.buffer_snapshot();
14362        let mut selections = self.selections.all::<usize>(&display_map);
14363        if let Some(mut select_next_state) = self.select_next_state.take() {
14364            let query = &select_next_state.query;
14365            if !select_next_state.done {
14366                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14367                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14368                let mut next_selected_range = None;
14369
14370                let bytes_after_last_selection =
14371                    buffer.bytes_in_range(last_selection.end..buffer.len());
14372                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
14373                let query_matches = query
14374                    .stream_find_iter(bytes_after_last_selection)
14375                    .map(|result| (last_selection.end, result))
14376                    .chain(
14377                        query
14378                            .stream_find_iter(bytes_before_first_selection)
14379                            .map(|result| (0, result)),
14380                    );
14381
14382                for (start_offset, query_match) in query_matches {
14383                    let query_match = query_match.unwrap(); // can only fail due to I/O
14384                    let offset_range =
14385                        start_offset + query_match.start()..start_offset + query_match.end();
14386
14387                    if !select_next_state.wordwise
14388                        || (!buffer.is_inside_word(offset_range.start, None)
14389                            && !buffer.is_inside_word(offset_range.end, None))
14390                    {
14391                        let idx = selections
14392                            .partition_point(|selection| selection.end <= offset_range.start);
14393                        let overlaps = selections
14394                            .get(idx)
14395                            .map_or(false, |selection| selection.start < offset_range.end);
14396
14397                        if !overlaps {
14398                            next_selected_range = Some(offset_range);
14399                            break;
14400                        }
14401                    }
14402                }
14403
14404                if let Some(next_selected_range) = next_selected_range {
14405                    self.select_match_ranges(
14406                        next_selected_range,
14407                        last_selection.reversed,
14408                        replace_newest,
14409                        autoscroll,
14410                        window,
14411                        cx,
14412                    );
14413                } else {
14414                    select_next_state.done = true;
14415                }
14416            }
14417
14418            self.select_next_state = Some(select_next_state);
14419        } else {
14420            let mut only_carets = true;
14421            let mut same_text_selected = true;
14422            let mut selected_text = None;
14423
14424            let mut selections_iter = selections.iter().peekable();
14425            while let Some(selection) = selections_iter.next() {
14426                if selection.start != selection.end {
14427                    only_carets = false;
14428                }
14429
14430                if same_text_selected {
14431                    if selected_text.is_none() {
14432                        selected_text =
14433                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14434                    }
14435
14436                    if let Some(next_selection) = selections_iter.peek() {
14437                        if next_selection.range().len() == selection.range().len() {
14438                            let next_selected_text = buffer
14439                                .text_for_range(next_selection.range())
14440                                .collect::<String>();
14441                            if Some(next_selected_text) != selected_text {
14442                                same_text_selected = false;
14443                                selected_text = None;
14444                            }
14445                        } else {
14446                            same_text_selected = false;
14447                            selected_text = None;
14448                        }
14449                    }
14450                }
14451            }
14452
14453            if only_carets {
14454                for selection in &mut selections {
14455                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14456                    selection.start = word_range.start;
14457                    selection.end = word_range.end;
14458                    selection.goal = SelectionGoal::None;
14459                    selection.reversed = false;
14460                    self.select_match_ranges(
14461                        selection.start..selection.end,
14462                        selection.reversed,
14463                        replace_newest,
14464                        autoscroll,
14465                        window,
14466                        cx,
14467                    );
14468                }
14469
14470                if selections.len() == 1 {
14471                    let selection = selections
14472                        .last()
14473                        .expect("ensured that there's only one selection");
14474                    let query = buffer
14475                        .text_for_range(selection.start..selection.end)
14476                        .collect::<String>();
14477                    let is_empty = query.is_empty();
14478                    let select_state = SelectNextState {
14479                        query: AhoCorasick::new(&[query])?,
14480                        wordwise: true,
14481                        done: is_empty,
14482                    };
14483                    self.select_next_state = Some(select_state);
14484                } else {
14485                    self.select_next_state = None;
14486                }
14487            } else if let Some(selected_text) = selected_text {
14488                self.select_next_state = Some(SelectNextState {
14489                    query: AhoCorasick::new(&[selected_text])?,
14490                    wordwise: false,
14491                    done: false,
14492                });
14493                self.select_next_match_internal(
14494                    display_map,
14495                    replace_newest,
14496                    autoscroll,
14497                    window,
14498                    cx,
14499                )?;
14500            }
14501        }
14502        Ok(())
14503    }
14504
14505    pub fn select_all_matches(
14506        &mut self,
14507        _action: &SelectAllMatches,
14508        window: &mut Window,
14509        cx: &mut Context<Self>,
14510    ) -> Result<()> {
14511        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14512
14513        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14514
14515        self.select_next_match_internal(&display_map, false, None, window, cx)?;
14516        let Some(select_next_state) = self.select_next_state.as_mut() else {
14517            return Ok(());
14518        };
14519        if select_next_state.done {
14520            return Ok(());
14521        }
14522
14523        let mut new_selections = Vec::new();
14524
14525        let reversed = self.selections.oldest::<usize>(&display_map).reversed;
14526        let buffer = display_map.buffer_snapshot();
14527        let query_matches = select_next_state
14528            .query
14529            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
14530
14531        for query_match in query_matches.into_iter() {
14532            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
14533            let offset_range = if reversed {
14534                query_match.end()..query_match.start()
14535            } else {
14536                query_match.start()..query_match.end()
14537            };
14538
14539            if !select_next_state.wordwise
14540                || (!buffer.is_inside_word(offset_range.start, None)
14541                    && !buffer.is_inside_word(offset_range.end, None))
14542            {
14543                new_selections.push(offset_range.start..offset_range.end);
14544            }
14545        }
14546
14547        select_next_state.done = true;
14548
14549        if new_selections.is_empty() {
14550            log::error!("bug: new_selections is empty in select_all_matches");
14551            return Ok(());
14552        }
14553
14554        self.unfold_ranges(&new_selections.clone(), false, false, cx);
14555        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
14556            selections.select_ranges(new_selections)
14557        });
14558
14559        Ok(())
14560    }
14561
14562    pub fn select_next(
14563        &mut self,
14564        action: &SelectNext,
14565        window: &mut Window,
14566        cx: &mut Context<Self>,
14567    ) -> Result<()> {
14568        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14569        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14570        self.select_next_match_internal(
14571            &display_map,
14572            action.replace_newest,
14573            Some(Autoscroll::newest()),
14574            window,
14575            cx,
14576        )?;
14577        Ok(())
14578    }
14579
14580    pub fn select_previous(
14581        &mut self,
14582        action: &SelectPrevious,
14583        window: &mut Window,
14584        cx: &mut Context<Self>,
14585    ) -> Result<()> {
14586        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14587        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14588        let buffer = display_map.buffer_snapshot();
14589        let mut selections = self.selections.all::<usize>(&display_map);
14590        if let Some(mut select_prev_state) = self.select_prev_state.take() {
14591            let query = &select_prev_state.query;
14592            if !select_prev_state.done {
14593                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14594                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14595                let mut next_selected_range = None;
14596                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
14597                let bytes_before_last_selection =
14598                    buffer.reversed_bytes_in_range(0..last_selection.start);
14599                let bytes_after_first_selection =
14600                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
14601                let query_matches = query
14602                    .stream_find_iter(bytes_before_last_selection)
14603                    .map(|result| (last_selection.start, result))
14604                    .chain(
14605                        query
14606                            .stream_find_iter(bytes_after_first_selection)
14607                            .map(|result| (buffer.len(), result)),
14608                    );
14609                for (end_offset, query_match) in query_matches {
14610                    let query_match = query_match.unwrap(); // can only fail due to I/O
14611                    let offset_range =
14612                        end_offset - query_match.end()..end_offset - query_match.start();
14613
14614                    if !select_prev_state.wordwise
14615                        || (!buffer.is_inside_word(offset_range.start, None)
14616                            && !buffer.is_inside_word(offset_range.end, None))
14617                    {
14618                        next_selected_range = Some(offset_range);
14619                        break;
14620                    }
14621                }
14622
14623                if let Some(next_selected_range) = next_selected_range {
14624                    self.select_match_ranges(
14625                        next_selected_range,
14626                        last_selection.reversed,
14627                        action.replace_newest,
14628                        Some(Autoscroll::newest()),
14629                        window,
14630                        cx,
14631                    );
14632                } else {
14633                    select_prev_state.done = true;
14634                }
14635            }
14636
14637            self.select_prev_state = Some(select_prev_state);
14638        } else {
14639            let mut only_carets = true;
14640            let mut same_text_selected = true;
14641            let mut selected_text = None;
14642
14643            let mut selections_iter = selections.iter().peekable();
14644            while let Some(selection) = selections_iter.next() {
14645                if selection.start != selection.end {
14646                    only_carets = false;
14647                }
14648
14649                if same_text_selected {
14650                    if selected_text.is_none() {
14651                        selected_text =
14652                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14653                    }
14654
14655                    if let Some(next_selection) = selections_iter.peek() {
14656                        if next_selection.range().len() == selection.range().len() {
14657                            let next_selected_text = buffer
14658                                .text_for_range(next_selection.range())
14659                                .collect::<String>();
14660                            if Some(next_selected_text) != selected_text {
14661                                same_text_selected = false;
14662                                selected_text = None;
14663                            }
14664                        } else {
14665                            same_text_selected = false;
14666                            selected_text = None;
14667                        }
14668                    }
14669                }
14670            }
14671
14672            if only_carets {
14673                for selection in &mut selections {
14674                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14675                    selection.start = word_range.start;
14676                    selection.end = word_range.end;
14677                    selection.goal = SelectionGoal::None;
14678                    selection.reversed = false;
14679                    self.select_match_ranges(
14680                        selection.start..selection.end,
14681                        selection.reversed,
14682                        action.replace_newest,
14683                        Some(Autoscroll::newest()),
14684                        window,
14685                        cx,
14686                    );
14687                }
14688                if selections.len() == 1 {
14689                    let selection = selections
14690                        .last()
14691                        .expect("ensured that there's only one selection");
14692                    let query = buffer
14693                        .text_for_range(selection.start..selection.end)
14694                        .collect::<String>();
14695                    let is_empty = query.is_empty();
14696                    let select_state = SelectNextState {
14697                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
14698                        wordwise: true,
14699                        done: is_empty,
14700                    };
14701                    self.select_prev_state = Some(select_state);
14702                } else {
14703                    self.select_prev_state = None;
14704                }
14705            } else if let Some(selected_text) = selected_text {
14706                self.select_prev_state = Some(SelectNextState {
14707                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
14708                    wordwise: false,
14709                    done: false,
14710                });
14711                self.select_previous(action, window, cx)?;
14712            }
14713        }
14714        Ok(())
14715    }
14716
14717    pub fn find_next_match(
14718        &mut self,
14719        _: &FindNextMatch,
14720        window: &mut Window,
14721        cx: &mut Context<Self>,
14722    ) -> Result<()> {
14723        let selections = self.selections.disjoint_anchors_arc();
14724        match selections.first() {
14725            Some(first) if selections.len() >= 2 => {
14726                self.change_selections(Default::default(), window, cx, |s| {
14727                    s.select_ranges([first.range()]);
14728                });
14729            }
14730            _ => self.select_next(
14731                &SelectNext {
14732                    replace_newest: true,
14733                },
14734                window,
14735                cx,
14736            )?,
14737        }
14738        Ok(())
14739    }
14740
14741    pub fn find_previous_match(
14742        &mut self,
14743        _: &FindPreviousMatch,
14744        window: &mut Window,
14745        cx: &mut Context<Self>,
14746    ) -> Result<()> {
14747        let selections = self.selections.disjoint_anchors_arc();
14748        match selections.last() {
14749            Some(last) if selections.len() >= 2 => {
14750                self.change_selections(Default::default(), window, cx, |s| {
14751                    s.select_ranges([last.range()]);
14752                });
14753            }
14754            _ => self.select_previous(
14755                &SelectPrevious {
14756                    replace_newest: true,
14757                },
14758                window,
14759                cx,
14760            )?,
14761        }
14762        Ok(())
14763    }
14764
14765    pub fn toggle_comments(
14766        &mut self,
14767        action: &ToggleComments,
14768        window: &mut Window,
14769        cx: &mut Context<Self>,
14770    ) {
14771        if self.read_only(cx) {
14772            return;
14773        }
14774        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14775        let text_layout_details = &self.text_layout_details(window);
14776        self.transact(window, cx, |this, window, cx| {
14777            let mut selections = this
14778                .selections
14779                .all::<MultiBufferPoint>(&this.display_snapshot(cx));
14780            let mut edits = Vec::new();
14781            let mut selection_edit_ranges = Vec::new();
14782            let mut last_toggled_row = None;
14783            let snapshot = this.buffer.read(cx).read(cx);
14784            let empty_str: Arc<str> = Arc::default();
14785            let mut suffixes_inserted = Vec::new();
14786            let ignore_indent = action.ignore_indent;
14787
14788            fn comment_prefix_range(
14789                snapshot: &MultiBufferSnapshot,
14790                row: MultiBufferRow,
14791                comment_prefix: &str,
14792                comment_prefix_whitespace: &str,
14793                ignore_indent: bool,
14794            ) -> Range<Point> {
14795                let indent_size = if ignore_indent {
14796                    0
14797                } else {
14798                    snapshot.indent_size_for_line(row).len
14799                };
14800
14801                let start = Point::new(row.0, indent_size);
14802
14803                let mut line_bytes = snapshot
14804                    .bytes_in_range(start..snapshot.max_point())
14805                    .flatten()
14806                    .copied();
14807
14808                // If this line currently begins with the line comment prefix, then record
14809                // the range containing the prefix.
14810                if line_bytes
14811                    .by_ref()
14812                    .take(comment_prefix.len())
14813                    .eq(comment_prefix.bytes())
14814                {
14815                    // Include any whitespace that matches the comment prefix.
14816                    let matching_whitespace_len = line_bytes
14817                        .zip(comment_prefix_whitespace.bytes())
14818                        .take_while(|(a, b)| a == b)
14819                        .count() as u32;
14820                    let end = Point::new(
14821                        start.row,
14822                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
14823                    );
14824                    start..end
14825                } else {
14826                    start..start
14827                }
14828            }
14829
14830            fn comment_suffix_range(
14831                snapshot: &MultiBufferSnapshot,
14832                row: MultiBufferRow,
14833                comment_suffix: &str,
14834                comment_suffix_has_leading_space: bool,
14835            ) -> Range<Point> {
14836                let end = Point::new(row.0, snapshot.line_len(row));
14837                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
14838
14839                let mut line_end_bytes = snapshot
14840                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
14841                    .flatten()
14842                    .copied();
14843
14844                let leading_space_len = if suffix_start_column > 0
14845                    && line_end_bytes.next() == Some(b' ')
14846                    && comment_suffix_has_leading_space
14847                {
14848                    1
14849                } else {
14850                    0
14851                };
14852
14853                // If this line currently begins with the line comment prefix, then record
14854                // the range containing the prefix.
14855                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
14856                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
14857                    start..end
14858                } else {
14859                    end..end
14860                }
14861            }
14862
14863            // TODO: Handle selections that cross excerpts
14864            for selection in &mut selections {
14865                let start_column = snapshot
14866                    .indent_size_for_line(MultiBufferRow(selection.start.row))
14867                    .len;
14868                let language = if let Some(language) =
14869                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
14870                {
14871                    language
14872                } else {
14873                    continue;
14874                };
14875
14876                selection_edit_ranges.clear();
14877
14878                // If multiple selections contain a given row, avoid processing that
14879                // row more than once.
14880                let mut start_row = MultiBufferRow(selection.start.row);
14881                if last_toggled_row == Some(start_row) {
14882                    start_row = start_row.next_row();
14883                }
14884                let end_row =
14885                    if selection.end.row > selection.start.row && selection.end.column == 0 {
14886                        MultiBufferRow(selection.end.row - 1)
14887                    } else {
14888                        MultiBufferRow(selection.end.row)
14889                    };
14890                last_toggled_row = Some(end_row);
14891
14892                if start_row > end_row {
14893                    continue;
14894                }
14895
14896                // If the language has line comments, toggle those.
14897                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
14898
14899                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
14900                if ignore_indent {
14901                    full_comment_prefixes = full_comment_prefixes
14902                        .into_iter()
14903                        .map(|s| Arc::from(s.trim_end()))
14904                        .collect();
14905                }
14906
14907                if !full_comment_prefixes.is_empty() {
14908                    let first_prefix = full_comment_prefixes
14909                        .first()
14910                        .expect("prefixes is non-empty");
14911                    let prefix_trimmed_lengths = full_comment_prefixes
14912                        .iter()
14913                        .map(|p| p.trim_end_matches(' ').len())
14914                        .collect::<SmallVec<[usize; 4]>>();
14915
14916                    let mut all_selection_lines_are_comments = true;
14917
14918                    for row in start_row.0..=end_row.0 {
14919                        let row = MultiBufferRow(row);
14920                        if start_row < end_row && snapshot.is_line_blank(row) {
14921                            continue;
14922                        }
14923
14924                        let prefix_range = full_comment_prefixes
14925                            .iter()
14926                            .zip(prefix_trimmed_lengths.iter().copied())
14927                            .map(|(prefix, trimmed_prefix_len)| {
14928                                comment_prefix_range(
14929                                    snapshot.deref(),
14930                                    row,
14931                                    &prefix[..trimmed_prefix_len],
14932                                    &prefix[trimmed_prefix_len..],
14933                                    ignore_indent,
14934                                )
14935                            })
14936                            .max_by_key(|range| range.end.column - range.start.column)
14937                            .expect("prefixes is non-empty");
14938
14939                        if prefix_range.is_empty() {
14940                            all_selection_lines_are_comments = false;
14941                        }
14942
14943                        selection_edit_ranges.push(prefix_range);
14944                    }
14945
14946                    if all_selection_lines_are_comments {
14947                        edits.extend(
14948                            selection_edit_ranges
14949                                .iter()
14950                                .cloned()
14951                                .map(|range| (range, empty_str.clone())),
14952                        );
14953                    } else {
14954                        let min_column = selection_edit_ranges
14955                            .iter()
14956                            .map(|range| range.start.column)
14957                            .min()
14958                            .unwrap_or(0);
14959                        edits.extend(selection_edit_ranges.iter().map(|range| {
14960                            let position = Point::new(range.start.row, min_column);
14961                            (position..position, first_prefix.clone())
14962                        }));
14963                    }
14964                } else if let Some(BlockCommentConfig {
14965                    start: full_comment_prefix,
14966                    end: comment_suffix,
14967                    ..
14968                }) = language.block_comment()
14969                {
14970                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
14971                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
14972                    let prefix_range = comment_prefix_range(
14973                        snapshot.deref(),
14974                        start_row,
14975                        comment_prefix,
14976                        comment_prefix_whitespace,
14977                        ignore_indent,
14978                    );
14979                    let suffix_range = comment_suffix_range(
14980                        snapshot.deref(),
14981                        end_row,
14982                        comment_suffix.trim_start_matches(' '),
14983                        comment_suffix.starts_with(' '),
14984                    );
14985
14986                    if prefix_range.is_empty() || suffix_range.is_empty() {
14987                        edits.push((
14988                            prefix_range.start..prefix_range.start,
14989                            full_comment_prefix.clone(),
14990                        ));
14991                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
14992                        suffixes_inserted.push((end_row, comment_suffix.len()));
14993                    } else {
14994                        edits.push((prefix_range, empty_str.clone()));
14995                        edits.push((suffix_range, empty_str.clone()));
14996                    }
14997                } else {
14998                    continue;
14999                }
15000            }
15001
15002            drop(snapshot);
15003            this.buffer.update(cx, |buffer, cx| {
15004                buffer.edit(edits, None, cx);
15005            });
15006
15007            // Adjust selections so that they end before any comment suffixes that
15008            // were inserted.
15009            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
15010            let mut selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15011            let snapshot = this.buffer.read(cx).read(cx);
15012            for selection in &mut selections {
15013                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
15014                    match row.cmp(&MultiBufferRow(selection.end.row)) {
15015                        Ordering::Less => {
15016                            suffixes_inserted.next();
15017                            continue;
15018                        }
15019                        Ordering::Greater => break,
15020                        Ordering::Equal => {
15021                            if selection.end.column == snapshot.line_len(row) {
15022                                if selection.is_empty() {
15023                                    selection.start.column -= suffix_len as u32;
15024                                }
15025                                selection.end.column -= suffix_len as u32;
15026                            }
15027                            break;
15028                        }
15029                    }
15030                }
15031            }
15032
15033            drop(snapshot);
15034            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
15035
15036            let selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15037            let selections_on_single_row = selections.windows(2).all(|selections| {
15038                selections[0].start.row == selections[1].start.row
15039                    && selections[0].end.row == selections[1].end.row
15040                    && selections[0].start.row == selections[0].end.row
15041            });
15042            let selections_selecting = selections
15043                .iter()
15044                .any(|selection| selection.start != selection.end);
15045            let advance_downwards = action.advance_downwards
15046                && selections_on_single_row
15047                && !selections_selecting
15048                && !matches!(this.mode, EditorMode::SingleLine);
15049
15050            if advance_downwards {
15051                let snapshot = this.buffer.read(cx).snapshot(cx);
15052
15053                this.change_selections(Default::default(), window, cx, |s| {
15054                    s.move_cursors_with(|display_snapshot, display_point, _| {
15055                        let mut point = display_point.to_point(display_snapshot);
15056                        point.row += 1;
15057                        point = snapshot.clip_point(point, Bias::Left);
15058                        let display_point = point.to_display_point(display_snapshot);
15059                        let goal = SelectionGoal::HorizontalPosition(
15060                            display_snapshot
15061                                .x_for_display_point(display_point, text_layout_details)
15062                                .into(),
15063                        );
15064                        (display_point, goal)
15065                    })
15066                });
15067            }
15068        });
15069    }
15070
15071    pub fn select_enclosing_symbol(
15072        &mut self,
15073        _: &SelectEnclosingSymbol,
15074        window: &mut Window,
15075        cx: &mut Context<Self>,
15076    ) {
15077        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15078
15079        let buffer = self.buffer.read(cx).snapshot(cx);
15080        let old_selections = self
15081            .selections
15082            .all::<usize>(&self.display_snapshot(cx))
15083            .into_boxed_slice();
15084
15085        fn update_selection(
15086            selection: &Selection<usize>,
15087            buffer_snap: &MultiBufferSnapshot,
15088        ) -> Option<Selection<usize>> {
15089            let cursor = selection.head();
15090            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
15091            for symbol in symbols.iter().rev() {
15092                let start = symbol.range.start.to_offset(buffer_snap);
15093                let end = symbol.range.end.to_offset(buffer_snap);
15094                let new_range = start..end;
15095                if start < selection.start || end > selection.end {
15096                    return Some(Selection {
15097                        id: selection.id,
15098                        start: new_range.start,
15099                        end: new_range.end,
15100                        goal: SelectionGoal::None,
15101                        reversed: selection.reversed,
15102                    });
15103                }
15104            }
15105            None
15106        }
15107
15108        let mut selected_larger_symbol = false;
15109        let new_selections = old_selections
15110            .iter()
15111            .map(|selection| match update_selection(selection, &buffer) {
15112                Some(new_selection) => {
15113                    if new_selection.range() != selection.range() {
15114                        selected_larger_symbol = true;
15115                    }
15116                    new_selection
15117                }
15118                None => selection.clone(),
15119            })
15120            .collect::<Vec<_>>();
15121
15122        if selected_larger_symbol {
15123            self.change_selections(Default::default(), window, cx, |s| {
15124                s.select(new_selections);
15125            });
15126        }
15127    }
15128
15129    pub fn select_larger_syntax_node(
15130        &mut self,
15131        _: &SelectLargerSyntaxNode,
15132        window: &mut Window,
15133        cx: &mut Context<Self>,
15134    ) {
15135        let Some(visible_row_count) = self.visible_row_count() else {
15136            return;
15137        };
15138        let old_selections: Box<[_]> = self
15139            .selections
15140            .all::<usize>(&self.display_snapshot(cx))
15141            .into();
15142        if old_selections.is_empty() {
15143            return;
15144        }
15145
15146        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15147
15148        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15149        let buffer = self.buffer.read(cx).snapshot(cx);
15150
15151        let mut selected_larger_node = false;
15152        let mut new_selections = old_selections
15153            .iter()
15154            .map(|selection| {
15155                let old_range = selection.start..selection.end;
15156
15157                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
15158                    // manually select word at selection
15159                    if ["string_content", "inline"].contains(&node.kind()) {
15160                        let (word_range, _) = buffer.surrounding_word(old_range.start, None);
15161                        // ignore if word is already selected
15162                        if !word_range.is_empty() && old_range != word_range {
15163                            let (last_word_range, _) = buffer.surrounding_word(old_range.end, None);
15164                            // only select word if start and end point belongs to same word
15165                            if word_range == last_word_range {
15166                                selected_larger_node = true;
15167                                return Selection {
15168                                    id: selection.id,
15169                                    start: word_range.start,
15170                                    end: word_range.end,
15171                                    goal: SelectionGoal::None,
15172                                    reversed: selection.reversed,
15173                                };
15174                            }
15175                        }
15176                    }
15177                }
15178
15179                let mut new_range = old_range.clone();
15180                while let Some((node, range)) = buffer.syntax_ancestor(new_range.clone()) {
15181                    new_range = range;
15182                    if !node.is_named() {
15183                        continue;
15184                    }
15185                    if !display_map.intersects_fold(new_range.start)
15186                        && !display_map.intersects_fold(new_range.end)
15187                    {
15188                        break;
15189                    }
15190                }
15191
15192                selected_larger_node |= new_range != old_range;
15193                Selection {
15194                    id: selection.id,
15195                    start: new_range.start,
15196                    end: new_range.end,
15197                    goal: SelectionGoal::None,
15198                    reversed: selection.reversed,
15199                }
15200            })
15201            .collect::<Vec<_>>();
15202
15203        if !selected_larger_node {
15204            return; // don't put this call in the history
15205        }
15206
15207        // scroll based on transformation done to the last selection created by the user
15208        let (last_old, last_new) = old_selections
15209            .last()
15210            .zip(new_selections.last().cloned())
15211            .expect("old_selections isn't empty");
15212
15213        // revert selection
15214        let is_selection_reversed = {
15215            let should_newest_selection_be_reversed = last_old.start != last_new.start;
15216            new_selections.last_mut().expect("checked above").reversed =
15217                should_newest_selection_be_reversed;
15218            should_newest_selection_be_reversed
15219        };
15220
15221        if selected_larger_node {
15222            self.select_syntax_node_history.disable_clearing = true;
15223            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15224                s.select(new_selections.clone());
15225            });
15226            self.select_syntax_node_history.disable_clearing = false;
15227        }
15228
15229        let start_row = last_new.start.to_display_point(&display_map).row().0;
15230        let end_row = last_new.end.to_display_point(&display_map).row().0;
15231        let selection_height = end_row - start_row + 1;
15232        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
15233
15234        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
15235        let scroll_behavior = if fits_on_the_screen {
15236            self.request_autoscroll(Autoscroll::fit(), cx);
15237            SelectSyntaxNodeScrollBehavior::FitSelection
15238        } else if is_selection_reversed {
15239            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15240            SelectSyntaxNodeScrollBehavior::CursorTop
15241        } else {
15242            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15243            SelectSyntaxNodeScrollBehavior::CursorBottom
15244        };
15245
15246        self.select_syntax_node_history.push((
15247            old_selections,
15248            scroll_behavior,
15249            is_selection_reversed,
15250        ));
15251    }
15252
15253    pub fn select_smaller_syntax_node(
15254        &mut self,
15255        _: &SelectSmallerSyntaxNode,
15256        window: &mut Window,
15257        cx: &mut Context<Self>,
15258    ) {
15259        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15260
15261        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
15262            self.select_syntax_node_history.pop()
15263        {
15264            if let Some(selection) = selections.last_mut() {
15265                selection.reversed = is_selection_reversed;
15266            }
15267
15268            self.select_syntax_node_history.disable_clearing = true;
15269            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15270                s.select(selections.to_vec());
15271            });
15272            self.select_syntax_node_history.disable_clearing = false;
15273
15274            match scroll_behavior {
15275                SelectSyntaxNodeScrollBehavior::CursorTop => {
15276                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15277                }
15278                SelectSyntaxNodeScrollBehavior::FitSelection => {
15279                    self.request_autoscroll(Autoscroll::fit(), cx);
15280                }
15281                SelectSyntaxNodeScrollBehavior::CursorBottom => {
15282                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15283                }
15284            }
15285        }
15286    }
15287
15288    pub fn unwrap_syntax_node(
15289        &mut self,
15290        _: &UnwrapSyntaxNode,
15291        window: &mut Window,
15292        cx: &mut Context<Self>,
15293    ) {
15294        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15295
15296        let buffer = self.buffer.read(cx).snapshot(cx);
15297        let selections = self
15298            .selections
15299            .all::<usize>(&self.display_snapshot(cx))
15300            .into_iter()
15301            // subtracting the offset requires sorting
15302            .sorted_by_key(|i| i.start);
15303
15304        let full_edits = selections
15305            .into_iter()
15306            .filter_map(|selection| {
15307                let child = if selection.is_empty()
15308                    && let Some((_, ancestor_range)) =
15309                        buffer.syntax_ancestor(selection.start..selection.end)
15310                {
15311                    ancestor_range
15312                } else {
15313                    selection.range()
15314                };
15315
15316                let mut parent = child.clone();
15317                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
15318                    parent = ancestor_range;
15319                    if parent.start < child.start || parent.end > child.end {
15320                        break;
15321                    }
15322                }
15323
15324                if parent == child {
15325                    return None;
15326                }
15327                let text = buffer.text_for_range(child).collect::<String>();
15328                Some((selection.id, parent, text))
15329            })
15330            .collect::<Vec<_>>();
15331        if full_edits.is_empty() {
15332            return;
15333        }
15334
15335        self.transact(window, cx, |this, window, cx| {
15336            this.buffer.update(cx, |buffer, cx| {
15337                buffer.edit(
15338                    full_edits
15339                        .iter()
15340                        .map(|(_, p, t)| (p.clone(), t.clone()))
15341                        .collect::<Vec<_>>(),
15342                    None,
15343                    cx,
15344                );
15345            });
15346            this.change_selections(Default::default(), window, cx, |s| {
15347                let mut offset = 0;
15348                let mut selections = vec![];
15349                for (id, parent, text) in full_edits {
15350                    let start = parent.start - offset;
15351                    offset += parent.len() - text.len();
15352                    selections.push(Selection {
15353                        id,
15354                        start,
15355                        end: start + text.len(),
15356                        reversed: false,
15357                        goal: Default::default(),
15358                    });
15359                }
15360                s.select(selections);
15361            });
15362        });
15363    }
15364
15365    pub fn select_next_syntax_node(
15366        &mut self,
15367        _: &SelectNextSyntaxNode,
15368        window: &mut Window,
15369        cx: &mut Context<Self>,
15370    ) {
15371        let old_selections: Box<[_]> = self
15372            .selections
15373            .all::<usize>(&self.display_snapshot(cx))
15374            .into();
15375        if old_selections.is_empty() {
15376            return;
15377        }
15378
15379        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15380
15381        let buffer = self.buffer.read(cx).snapshot(cx);
15382        let mut selected_sibling = false;
15383
15384        let new_selections = old_selections
15385            .iter()
15386            .map(|selection| {
15387                let old_range = selection.start..selection.end;
15388
15389                if let Some(node) = buffer.syntax_next_sibling(old_range) {
15390                    let new_range = node.byte_range();
15391                    selected_sibling = true;
15392                    Selection {
15393                        id: selection.id,
15394                        start: new_range.start,
15395                        end: new_range.end,
15396                        goal: SelectionGoal::None,
15397                        reversed: selection.reversed,
15398                    }
15399                } else {
15400                    selection.clone()
15401                }
15402            })
15403            .collect::<Vec<_>>();
15404
15405        if selected_sibling {
15406            self.change_selections(
15407                SelectionEffects::scroll(Autoscroll::fit()),
15408                window,
15409                cx,
15410                |s| {
15411                    s.select(new_selections);
15412                },
15413            );
15414        }
15415    }
15416
15417    pub fn select_prev_syntax_node(
15418        &mut self,
15419        _: &SelectPreviousSyntaxNode,
15420        window: &mut Window,
15421        cx: &mut Context<Self>,
15422    ) {
15423        let old_selections: Box<[_]> = self
15424            .selections
15425            .all::<usize>(&self.display_snapshot(cx))
15426            .into();
15427        if old_selections.is_empty() {
15428            return;
15429        }
15430
15431        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15432
15433        let buffer = self.buffer.read(cx).snapshot(cx);
15434        let mut selected_sibling = false;
15435
15436        let new_selections = old_selections
15437            .iter()
15438            .map(|selection| {
15439                let old_range = selection.start..selection.end;
15440
15441                if let Some(node) = buffer.syntax_prev_sibling(old_range) {
15442                    let new_range = node.byte_range();
15443                    selected_sibling = true;
15444                    Selection {
15445                        id: selection.id,
15446                        start: new_range.start,
15447                        end: new_range.end,
15448                        goal: SelectionGoal::None,
15449                        reversed: selection.reversed,
15450                    }
15451                } else {
15452                    selection.clone()
15453                }
15454            })
15455            .collect::<Vec<_>>();
15456
15457        if selected_sibling {
15458            self.change_selections(
15459                SelectionEffects::scroll(Autoscroll::fit()),
15460                window,
15461                cx,
15462                |s| {
15463                    s.select(new_selections);
15464                },
15465            );
15466        }
15467    }
15468
15469    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
15470        if !EditorSettings::get_global(cx).gutter.runnables {
15471            self.clear_tasks();
15472            return Task::ready(());
15473        }
15474        let project = self.project().map(Entity::downgrade);
15475        let task_sources = self.lsp_task_sources(cx);
15476        let multi_buffer = self.buffer.downgrade();
15477        cx.spawn_in(window, async move |editor, cx| {
15478            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
15479            let Some(project) = project.and_then(|p| p.upgrade()) else {
15480                return;
15481            };
15482            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
15483                this.display_map.update(cx, |map, cx| map.snapshot(cx))
15484            }) else {
15485                return;
15486            };
15487
15488            let hide_runnables = project
15489                .update(cx, |project, _| project.is_via_collab())
15490                .unwrap_or(true);
15491            if hide_runnables {
15492                return;
15493            }
15494            let new_rows =
15495                cx.background_spawn({
15496                    let snapshot = display_snapshot.clone();
15497                    async move {
15498                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
15499                    }
15500                })
15501                    .await;
15502            let Ok(lsp_tasks) =
15503                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
15504            else {
15505                return;
15506            };
15507            let lsp_tasks = lsp_tasks.await;
15508
15509            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
15510                lsp_tasks
15511                    .into_iter()
15512                    .flat_map(|(kind, tasks)| {
15513                        tasks.into_iter().filter_map(move |(location, task)| {
15514                            Some((kind.clone(), location?, task))
15515                        })
15516                    })
15517                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
15518                        let buffer = location.target.buffer;
15519                        let buffer_snapshot = buffer.read(cx).snapshot();
15520                        let offset = display_snapshot.buffer_snapshot().excerpts().find_map(
15521                            |(excerpt_id, snapshot, _)| {
15522                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
15523                                    display_snapshot
15524                                        .buffer_snapshot()
15525                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
15526                                } else {
15527                                    None
15528                                }
15529                            },
15530                        );
15531                        if let Some(offset) = offset {
15532                            let task_buffer_range =
15533                                location.target.range.to_point(&buffer_snapshot);
15534                            let context_buffer_range =
15535                                task_buffer_range.to_offset(&buffer_snapshot);
15536                            let context_range = BufferOffset(context_buffer_range.start)
15537                                ..BufferOffset(context_buffer_range.end);
15538
15539                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
15540                                .or_insert_with(|| RunnableTasks {
15541                                    templates: Vec::new(),
15542                                    offset,
15543                                    column: task_buffer_range.start.column,
15544                                    extra_variables: HashMap::default(),
15545                                    context_range,
15546                                })
15547                                .templates
15548                                .push((kind, task.original_task().clone()));
15549                        }
15550
15551                        acc
15552                    })
15553            }) else {
15554                return;
15555            };
15556
15557            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
15558                buffer.language_settings(cx).tasks.prefer_lsp
15559            }) else {
15560                return;
15561            };
15562
15563            let rows = Self::runnable_rows(
15564                project,
15565                display_snapshot,
15566                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
15567                new_rows,
15568                cx.clone(),
15569            )
15570            .await;
15571            editor
15572                .update(cx, |editor, _| {
15573                    editor.clear_tasks();
15574                    for (key, mut value) in rows {
15575                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
15576                            value.templates.extend(lsp_tasks.templates);
15577                        }
15578
15579                        editor.insert_tasks(key, value);
15580                    }
15581                    for (key, value) in lsp_tasks_by_rows {
15582                        editor.insert_tasks(key, value);
15583                    }
15584                })
15585                .ok();
15586        })
15587    }
15588    fn fetch_runnable_ranges(
15589        snapshot: &DisplaySnapshot,
15590        range: Range<Anchor>,
15591    ) -> Vec<language::RunnableRange> {
15592        snapshot.buffer_snapshot().runnable_ranges(range).collect()
15593    }
15594
15595    fn runnable_rows(
15596        project: Entity<Project>,
15597        snapshot: DisplaySnapshot,
15598        prefer_lsp: bool,
15599        runnable_ranges: Vec<RunnableRange>,
15600        cx: AsyncWindowContext,
15601    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
15602        cx.spawn(async move |cx| {
15603            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
15604            for mut runnable in runnable_ranges {
15605                let Some(tasks) = cx
15606                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
15607                    .ok()
15608                else {
15609                    continue;
15610                };
15611                let mut tasks = tasks.await;
15612
15613                if prefer_lsp {
15614                    tasks.retain(|(task_kind, _)| {
15615                        !matches!(task_kind, TaskSourceKind::Language { .. })
15616                    });
15617                }
15618                if tasks.is_empty() {
15619                    continue;
15620                }
15621
15622                let point = runnable
15623                    .run_range
15624                    .start
15625                    .to_point(&snapshot.buffer_snapshot());
15626                let Some(row) = snapshot
15627                    .buffer_snapshot()
15628                    .buffer_line_for_row(MultiBufferRow(point.row))
15629                    .map(|(_, range)| range.start.row)
15630                else {
15631                    continue;
15632                };
15633
15634                let context_range =
15635                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
15636                runnable_rows.push((
15637                    (runnable.buffer_id, row),
15638                    RunnableTasks {
15639                        templates: tasks,
15640                        offset: snapshot
15641                            .buffer_snapshot()
15642                            .anchor_before(runnable.run_range.start),
15643                        context_range,
15644                        column: point.column,
15645                        extra_variables: runnable.extra_captures,
15646                    },
15647                ));
15648            }
15649            runnable_rows
15650        })
15651    }
15652
15653    fn templates_with_tags(
15654        project: &Entity<Project>,
15655        runnable: &mut Runnable,
15656        cx: &mut App,
15657    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
15658        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
15659            let (worktree_id, file) = project
15660                .buffer_for_id(runnable.buffer, cx)
15661                .and_then(|buffer| buffer.read(cx).file())
15662                .map(|file| (file.worktree_id(cx), file.clone()))
15663                .unzip();
15664
15665            (
15666                project.task_store().read(cx).task_inventory().cloned(),
15667                worktree_id,
15668                file,
15669            )
15670        });
15671
15672        let tags = mem::take(&mut runnable.tags);
15673        let language = runnable.language.clone();
15674        cx.spawn(async move |cx| {
15675            let mut templates_with_tags = Vec::new();
15676            if let Some(inventory) = inventory {
15677                for RunnableTag(tag) in tags {
15678                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
15679                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
15680                    }) else {
15681                        return templates_with_tags;
15682                    };
15683                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
15684                        move |(_, template)| {
15685                            template.tags.iter().any(|source_tag| source_tag == &tag)
15686                        },
15687                    ));
15688                }
15689            }
15690            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
15691
15692            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
15693                // Strongest source wins; if we have worktree tag binding, prefer that to
15694                // global and language bindings;
15695                // if we have a global binding, prefer that to language binding.
15696                let first_mismatch = templates_with_tags
15697                    .iter()
15698                    .position(|(tag_source, _)| tag_source != leading_tag_source);
15699                if let Some(index) = first_mismatch {
15700                    templates_with_tags.truncate(index);
15701                }
15702            }
15703
15704            templates_with_tags
15705        })
15706    }
15707
15708    pub fn move_to_enclosing_bracket(
15709        &mut self,
15710        _: &MoveToEnclosingBracket,
15711        window: &mut Window,
15712        cx: &mut Context<Self>,
15713    ) {
15714        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15715        self.change_selections(Default::default(), window, cx, |s| {
15716            s.move_offsets_with(|snapshot, selection| {
15717                let Some(enclosing_bracket_ranges) =
15718                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
15719                else {
15720                    return;
15721                };
15722
15723                let mut best_length = usize::MAX;
15724                let mut best_inside = false;
15725                let mut best_in_bracket_range = false;
15726                let mut best_destination = None;
15727                for (open, close) in enclosing_bracket_ranges {
15728                    let close = close.to_inclusive();
15729                    let length = close.end() - open.start;
15730                    let inside = selection.start >= open.end && selection.end <= *close.start();
15731                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
15732                        || close.contains(&selection.head());
15733
15734                    // If best is next to a bracket and current isn't, skip
15735                    if !in_bracket_range && best_in_bracket_range {
15736                        continue;
15737                    }
15738
15739                    // Prefer smaller lengths unless best is inside and current isn't
15740                    if length > best_length && (best_inside || !inside) {
15741                        continue;
15742                    }
15743
15744                    best_length = length;
15745                    best_inside = inside;
15746                    best_in_bracket_range = in_bracket_range;
15747                    best_destination = Some(
15748                        if close.contains(&selection.start) && close.contains(&selection.end) {
15749                            if inside { open.end } else { open.start }
15750                        } else if inside {
15751                            *close.start()
15752                        } else {
15753                            *close.end()
15754                        },
15755                    );
15756                }
15757
15758                if let Some(destination) = best_destination {
15759                    selection.collapse_to(destination, SelectionGoal::None);
15760                }
15761            })
15762        });
15763    }
15764
15765    pub fn undo_selection(
15766        &mut self,
15767        _: &UndoSelection,
15768        window: &mut Window,
15769        cx: &mut Context<Self>,
15770    ) {
15771        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15772        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
15773            self.selection_history.mode = SelectionHistoryMode::Undoing;
15774            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15775                this.end_selection(window, cx);
15776                this.change_selections(
15777                    SelectionEffects::scroll(Autoscroll::newest()),
15778                    window,
15779                    cx,
15780                    |s| s.select_anchors(entry.selections.to_vec()),
15781                );
15782            });
15783            self.selection_history.mode = SelectionHistoryMode::Normal;
15784
15785            self.select_next_state = entry.select_next_state;
15786            self.select_prev_state = entry.select_prev_state;
15787            self.add_selections_state = entry.add_selections_state;
15788        }
15789    }
15790
15791    pub fn redo_selection(
15792        &mut self,
15793        _: &RedoSelection,
15794        window: &mut Window,
15795        cx: &mut Context<Self>,
15796    ) {
15797        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15798        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
15799            self.selection_history.mode = SelectionHistoryMode::Redoing;
15800            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15801                this.end_selection(window, cx);
15802                this.change_selections(
15803                    SelectionEffects::scroll(Autoscroll::newest()),
15804                    window,
15805                    cx,
15806                    |s| s.select_anchors(entry.selections.to_vec()),
15807                );
15808            });
15809            self.selection_history.mode = SelectionHistoryMode::Normal;
15810
15811            self.select_next_state = entry.select_next_state;
15812            self.select_prev_state = entry.select_prev_state;
15813            self.add_selections_state = entry.add_selections_state;
15814        }
15815    }
15816
15817    pub fn expand_excerpts(
15818        &mut self,
15819        action: &ExpandExcerpts,
15820        _: &mut Window,
15821        cx: &mut Context<Self>,
15822    ) {
15823        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
15824    }
15825
15826    pub fn expand_excerpts_down(
15827        &mut self,
15828        action: &ExpandExcerptsDown,
15829        _: &mut Window,
15830        cx: &mut Context<Self>,
15831    ) {
15832        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
15833    }
15834
15835    pub fn expand_excerpts_up(
15836        &mut self,
15837        action: &ExpandExcerptsUp,
15838        _: &mut Window,
15839        cx: &mut Context<Self>,
15840    ) {
15841        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
15842    }
15843
15844    pub fn expand_excerpts_for_direction(
15845        &mut self,
15846        lines: u32,
15847        direction: ExpandExcerptDirection,
15848
15849        cx: &mut Context<Self>,
15850    ) {
15851        let selections = self.selections.disjoint_anchors_arc();
15852
15853        let lines = if lines == 0 {
15854            EditorSettings::get_global(cx).expand_excerpt_lines
15855        } else {
15856            lines
15857        };
15858
15859        self.buffer.update(cx, |buffer, cx| {
15860            let snapshot = buffer.snapshot(cx);
15861            let mut excerpt_ids = selections
15862                .iter()
15863                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
15864                .collect::<Vec<_>>();
15865            excerpt_ids.sort();
15866            excerpt_ids.dedup();
15867            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
15868        })
15869    }
15870
15871    pub fn expand_excerpt(
15872        &mut self,
15873        excerpt: ExcerptId,
15874        direction: ExpandExcerptDirection,
15875        window: &mut Window,
15876        cx: &mut Context<Self>,
15877    ) {
15878        let current_scroll_position = self.scroll_position(cx);
15879        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
15880        let mut scroll = None;
15881
15882        if direction == ExpandExcerptDirection::Down {
15883            let multi_buffer = self.buffer.read(cx);
15884            let snapshot = multi_buffer.snapshot(cx);
15885            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
15886                && let Some(buffer) = multi_buffer.buffer(buffer_id)
15887                && let Some(excerpt_range) = snapshot.context_range_for_excerpt(excerpt)
15888            {
15889                let buffer_snapshot = buffer.read(cx).snapshot();
15890                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
15891                let last_row = buffer_snapshot.max_point().row;
15892                let lines_below = last_row.saturating_sub(excerpt_end_row);
15893                if lines_below >= lines_to_expand {
15894                    scroll = Some(
15895                        current_scroll_position
15896                            + gpui::Point::new(0.0, lines_to_expand as ScrollOffset),
15897                    );
15898                }
15899            }
15900        }
15901        if direction == ExpandExcerptDirection::Up
15902            && self
15903                .buffer
15904                .read(cx)
15905                .snapshot(cx)
15906                .excerpt_before(excerpt)
15907                .is_none()
15908        {
15909            scroll = Some(current_scroll_position);
15910        }
15911
15912        self.buffer.update(cx, |buffer, cx| {
15913            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
15914        });
15915
15916        if let Some(new_scroll_position) = scroll {
15917            self.set_scroll_position(new_scroll_position, window, cx);
15918        }
15919    }
15920
15921    pub fn go_to_singleton_buffer_point(
15922        &mut self,
15923        point: Point,
15924        window: &mut Window,
15925        cx: &mut Context<Self>,
15926    ) {
15927        self.go_to_singleton_buffer_range(point..point, window, cx);
15928    }
15929
15930    pub fn go_to_singleton_buffer_range(
15931        &mut self,
15932        range: Range<Point>,
15933        window: &mut Window,
15934        cx: &mut Context<Self>,
15935    ) {
15936        let multibuffer = self.buffer().read(cx);
15937        let Some(buffer) = multibuffer.as_singleton() else {
15938            return;
15939        };
15940        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
15941            return;
15942        };
15943        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
15944            return;
15945        };
15946        self.change_selections(
15947            SelectionEffects::default().nav_history(true),
15948            window,
15949            cx,
15950            |s| s.select_anchor_ranges([start..end]),
15951        );
15952    }
15953
15954    pub fn go_to_diagnostic(
15955        &mut self,
15956        action: &GoToDiagnostic,
15957        window: &mut Window,
15958        cx: &mut Context<Self>,
15959    ) {
15960        if !self.diagnostics_enabled() {
15961            return;
15962        }
15963        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15964        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
15965    }
15966
15967    pub fn go_to_prev_diagnostic(
15968        &mut self,
15969        action: &GoToPreviousDiagnostic,
15970        window: &mut Window,
15971        cx: &mut Context<Self>,
15972    ) {
15973        if !self.diagnostics_enabled() {
15974            return;
15975        }
15976        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15977        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
15978    }
15979
15980    pub fn go_to_diagnostic_impl(
15981        &mut self,
15982        direction: Direction,
15983        severity: GoToDiagnosticSeverityFilter,
15984        window: &mut Window,
15985        cx: &mut Context<Self>,
15986    ) {
15987        let buffer = self.buffer.read(cx).snapshot(cx);
15988        let selection = self.selections.newest::<usize>(&self.display_snapshot(cx));
15989
15990        let mut active_group_id = None;
15991        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
15992            && active_group.active_range.start.to_offset(&buffer) == selection.start
15993        {
15994            active_group_id = Some(active_group.group_id);
15995        }
15996
15997        fn filtered<'a>(
15998            snapshot: EditorSnapshot,
15999            severity: GoToDiagnosticSeverityFilter,
16000            diagnostics: impl Iterator<Item = DiagnosticEntryRef<'a, usize>>,
16001        ) -> impl Iterator<Item = DiagnosticEntryRef<'a, usize>> {
16002            diagnostics
16003                .filter(move |entry| severity.matches(entry.diagnostic.severity))
16004                .filter(|entry| entry.range.start != entry.range.end)
16005                .filter(|entry| !entry.diagnostic.is_unnecessary)
16006                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
16007        }
16008
16009        let snapshot = self.snapshot(window, cx);
16010        let before = filtered(
16011            snapshot.clone(),
16012            severity,
16013            buffer
16014                .diagnostics_in_range(0..selection.start)
16015                .filter(|entry| entry.range.start <= selection.start),
16016        );
16017        let after = filtered(
16018            snapshot,
16019            severity,
16020            buffer
16021                .diagnostics_in_range(selection.start..buffer.len())
16022                .filter(|entry| entry.range.start >= selection.start),
16023        );
16024
16025        let mut found: Option<DiagnosticEntryRef<usize>> = None;
16026        if direction == Direction::Prev {
16027            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
16028            {
16029                for diagnostic in prev_diagnostics.into_iter().rev() {
16030                    if diagnostic.range.start != selection.start
16031                        || active_group_id
16032                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
16033                    {
16034                        found = Some(diagnostic);
16035                        break 'outer;
16036                    }
16037                }
16038            }
16039        } else {
16040            for diagnostic in after.chain(before) {
16041                if diagnostic.range.start != selection.start
16042                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
16043                {
16044                    found = Some(diagnostic);
16045                    break;
16046                }
16047            }
16048        }
16049        let Some(next_diagnostic) = found else {
16050            return;
16051        };
16052
16053        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
16054        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
16055            return;
16056        };
16057        self.change_selections(Default::default(), window, cx, |s| {
16058            s.select_ranges(vec![
16059                next_diagnostic.range.start..next_diagnostic.range.start,
16060            ])
16061        });
16062        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
16063        self.refresh_edit_prediction(false, true, window, cx);
16064    }
16065
16066    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
16067        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16068        let snapshot = self.snapshot(window, cx);
16069        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
16070        self.go_to_hunk_before_or_after_position(
16071            &snapshot,
16072            selection.head(),
16073            Direction::Next,
16074            window,
16075            cx,
16076        );
16077    }
16078
16079    pub fn go_to_hunk_before_or_after_position(
16080        &mut self,
16081        snapshot: &EditorSnapshot,
16082        position: Point,
16083        direction: Direction,
16084        window: &mut Window,
16085        cx: &mut Context<Editor>,
16086    ) {
16087        let row = if direction == Direction::Next {
16088            self.hunk_after_position(snapshot, position)
16089                .map(|hunk| hunk.row_range.start)
16090        } else {
16091            self.hunk_before_position(snapshot, position)
16092        };
16093
16094        if let Some(row) = row {
16095            let destination = Point::new(row.0, 0);
16096            let autoscroll = Autoscroll::center();
16097
16098            self.unfold_ranges(&[destination..destination], false, false, cx);
16099            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16100                s.select_ranges([destination..destination]);
16101            });
16102        }
16103    }
16104
16105    fn hunk_after_position(
16106        &mut self,
16107        snapshot: &EditorSnapshot,
16108        position: Point,
16109    ) -> Option<MultiBufferDiffHunk> {
16110        snapshot
16111            .buffer_snapshot()
16112            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
16113            .find(|hunk| hunk.row_range.start.0 > position.row)
16114            .or_else(|| {
16115                snapshot
16116                    .buffer_snapshot()
16117                    .diff_hunks_in_range(Point::zero()..position)
16118                    .find(|hunk| hunk.row_range.end.0 < position.row)
16119            })
16120    }
16121
16122    fn go_to_prev_hunk(
16123        &mut self,
16124        _: &GoToPreviousHunk,
16125        window: &mut Window,
16126        cx: &mut Context<Self>,
16127    ) {
16128        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16129        let snapshot = self.snapshot(window, cx);
16130        let selection = self.selections.newest::<Point>(&snapshot.display_snapshot);
16131        self.go_to_hunk_before_or_after_position(
16132            &snapshot,
16133            selection.head(),
16134            Direction::Prev,
16135            window,
16136            cx,
16137        );
16138    }
16139
16140    fn hunk_before_position(
16141        &mut self,
16142        snapshot: &EditorSnapshot,
16143        position: Point,
16144    ) -> Option<MultiBufferRow> {
16145        snapshot
16146            .buffer_snapshot()
16147            .diff_hunk_before(position)
16148            .or_else(|| snapshot.buffer_snapshot().diff_hunk_before(Point::MAX))
16149    }
16150
16151    fn go_to_next_change(
16152        &mut self,
16153        _: &GoToNextChange,
16154        window: &mut Window,
16155        cx: &mut Context<Self>,
16156    ) {
16157        if let Some(selections) = self
16158            .change_list
16159            .next_change(1, Direction::Next)
16160            .map(|s| s.to_vec())
16161        {
16162            self.change_selections(Default::default(), window, cx, |s| {
16163                let map = s.display_map();
16164                s.select_display_ranges(selections.iter().map(|a| {
16165                    let point = a.to_display_point(&map);
16166                    point..point
16167                }))
16168            })
16169        }
16170    }
16171
16172    fn go_to_previous_change(
16173        &mut self,
16174        _: &GoToPreviousChange,
16175        window: &mut Window,
16176        cx: &mut Context<Self>,
16177    ) {
16178        if let Some(selections) = self
16179            .change_list
16180            .next_change(1, Direction::Prev)
16181            .map(|s| s.to_vec())
16182        {
16183            self.change_selections(Default::default(), window, cx, |s| {
16184                let map = s.display_map();
16185                s.select_display_ranges(selections.iter().map(|a| {
16186                    let point = a.to_display_point(&map);
16187                    point..point
16188                }))
16189            })
16190        }
16191    }
16192
16193    pub fn go_to_next_document_highlight(
16194        &mut self,
16195        _: &GoToNextDocumentHighlight,
16196        window: &mut Window,
16197        cx: &mut Context<Self>,
16198    ) {
16199        self.go_to_document_highlight_before_or_after_position(Direction::Next, window, cx);
16200    }
16201
16202    pub fn go_to_prev_document_highlight(
16203        &mut self,
16204        _: &GoToPreviousDocumentHighlight,
16205        window: &mut Window,
16206        cx: &mut Context<Self>,
16207    ) {
16208        self.go_to_document_highlight_before_or_after_position(Direction::Prev, window, cx);
16209    }
16210
16211    pub fn go_to_document_highlight_before_or_after_position(
16212        &mut self,
16213        direction: Direction,
16214        window: &mut Window,
16215        cx: &mut Context<Editor>,
16216    ) {
16217        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16218        let snapshot = self.snapshot(window, cx);
16219        let buffer = &snapshot.buffer_snapshot();
16220        let position = self
16221            .selections
16222            .newest::<Point>(&snapshot.display_snapshot)
16223            .head();
16224        let anchor_position = buffer.anchor_after(position);
16225
16226        // Get all document highlights (both read and write)
16227        let mut all_highlights = Vec::new();
16228
16229        if let Some((_, read_highlights)) = self
16230            .background_highlights
16231            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
16232        {
16233            all_highlights.extend(read_highlights.iter());
16234        }
16235
16236        if let Some((_, write_highlights)) = self
16237            .background_highlights
16238            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
16239        {
16240            all_highlights.extend(write_highlights.iter());
16241        }
16242
16243        if all_highlights.is_empty() {
16244            return;
16245        }
16246
16247        // Sort highlights by position
16248        all_highlights.sort_by(|a, b| a.start.cmp(&b.start, buffer));
16249
16250        let target_highlight = match direction {
16251            Direction::Next => {
16252                // Find the first highlight after the current position
16253                all_highlights
16254                    .iter()
16255                    .find(|highlight| highlight.start.cmp(&anchor_position, buffer).is_gt())
16256            }
16257            Direction::Prev => {
16258                // Find the last highlight before the current position
16259                all_highlights
16260                    .iter()
16261                    .rev()
16262                    .find(|highlight| highlight.end.cmp(&anchor_position, buffer).is_lt())
16263            }
16264        };
16265
16266        if let Some(highlight) = target_highlight {
16267            let destination = highlight.start.to_point(buffer);
16268            let autoscroll = Autoscroll::center();
16269
16270            self.unfold_ranges(&[destination..destination], false, false, cx);
16271            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16272                s.select_ranges([destination..destination]);
16273            });
16274        }
16275    }
16276
16277    fn go_to_line<T: 'static>(
16278        &mut self,
16279        position: Anchor,
16280        highlight_color: Option<Hsla>,
16281        window: &mut Window,
16282        cx: &mut Context<Self>,
16283    ) {
16284        let snapshot = self.snapshot(window, cx).display_snapshot;
16285        let position = position.to_point(&snapshot.buffer_snapshot());
16286        let start = snapshot
16287            .buffer_snapshot()
16288            .clip_point(Point::new(position.row, 0), Bias::Left);
16289        let end = start + Point::new(1, 0);
16290        let start = snapshot.buffer_snapshot().anchor_before(start);
16291        let end = snapshot.buffer_snapshot().anchor_before(end);
16292
16293        self.highlight_rows::<T>(
16294            start..end,
16295            highlight_color
16296                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
16297            Default::default(),
16298            cx,
16299        );
16300
16301        if self.buffer.read(cx).is_singleton() {
16302            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
16303        }
16304    }
16305
16306    pub fn go_to_definition(
16307        &mut self,
16308        _: &GoToDefinition,
16309        window: &mut Window,
16310        cx: &mut Context<Self>,
16311    ) -> Task<Result<Navigated>> {
16312        let definition =
16313            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
16314        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
16315        cx.spawn_in(window, async move |editor, cx| {
16316            if definition.await? == Navigated::Yes {
16317                return Ok(Navigated::Yes);
16318            }
16319            match fallback_strategy {
16320                GoToDefinitionFallback::None => Ok(Navigated::No),
16321                GoToDefinitionFallback::FindAllReferences => {
16322                    match editor.update_in(cx, |editor, window, cx| {
16323                        editor.find_all_references(&FindAllReferences, window, cx)
16324                    })? {
16325                        Some(references) => references.await,
16326                        None => Ok(Navigated::No),
16327                    }
16328                }
16329            }
16330        })
16331    }
16332
16333    pub fn go_to_declaration(
16334        &mut self,
16335        _: &GoToDeclaration,
16336        window: &mut Window,
16337        cx: &mut Context<Self>,
16338    ) -> Task<Result<Navigated>> {
16339        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
16340    }
16341
16342    pub fn go_to_declaration_split(
16343        &mut self,
16344        _: &GoToDeclaration,
16345        window: &mut Window,
16346        cx: &mut Context<Self>,
16347    ) -> Task<Result<Navigated>> {
16348        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
16349    }
16350
16351    pub fn go_to_implementation(
16352        &mut self,
16353        _: &GoToImplementation,
16354        window: &mut Window,
16355        cx: &mut Context<Self>,
16356    ) -> Task<Result<Navigated>> {
16357        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
16358    }
16359
16360    pub fn go_to_implementation_split(
16361        &mut self,
16362        _: &GoToImplementationSplit,
16363        window: &mut Window,
16364        cx: &mut Context<Self>,
16365    ) -> Task<Result<Navigated>> {
16366        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
16367    }
16368
16369    pub fn go_to_type_definition(
16370        &mut self,
16371        _: &GoToTypeDefinition,
16372        window: &mut Window,
16373        cx: &mut Context<Self>,
16374    ) -> Task<Result<Navigated>> {
16375        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
16376    }
16377
16378    pub fn go_to_definition_split(
16379        &mut self,
16380        _: &GoToDefinitionSplit,
16381        window: &mut Window,
16382        cx: &mut Context<Self>,
16383    ) -> Task<Result<Navigated>> {
16384        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
16385    }
16386
16387    pub fn go_to_type_definition_split(
16388        &mut self,
16389        _: &GoToTypeDefinitionSplit,
16390        window: &mut Window,
16391        cx: &mut Context<Self>,
16392    ) -> Task<Result<Navigated>> {
16393        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
16394    }
16395
16396    fn go_to_definition_of_kind(
16397        &mut self,
16398        kind: GotoDefinitionKind,
16399        split: bool,
16400        window: &mut Window,
16401        cx: &mut Context<Self>,
16402    ) -> Task<Result<Navigated>> {
16403        let Some(provider) = self.semantics_provider.clone() else {
16404            return Task::ready(Ok(Navigated::No));
16405        };
16406        let head = self
16407            .selections
16408            .newest::<usize>(&self.display_snapshot(cx))
16409            .head();
16410        let buffer = self.buffer.read(cx);
16411        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
16412            return Task::ready(Ok(Navigated::No));
16413        };
16414        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
16415            return Task::ready(Ok(Navigated::No));
16416        };
16417
16418        cx.spawn_in(window, async move |editor, cx| {
16419            let Some(definitions) = definitions.await? else {
16420                return Ok(Navigated::No);
16421            };
16422            let navigated = editor
16423                .update_in(cx, |editor, window, cx| {
16424                    editor.navigate_to_hover_links(
16425                        Some(kind),
16426                        definitions
16427                            .into_iter()
16428                            .filter(|location| {
16429                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
16430                            })
16431                            .map(HoverLink::Text)
16432                            .collect::<Vec<_>>(),
16433                        split,
16434                        window,
16435                        cx,
16436                    )
16437                })?
16438                .await?;
16439            anyhow::Ok(navigated)
16440        })
16441    }
16442
16443    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
16444        let selection = self.selections.newest_anchor();
16445        let head = selection.head();
16446        let tail = selection.tail();
16447
16448        let Some((buffer, start_position)) =
16449            self.buffer.read(cx).text_anchor_for_position(head, cx)
16450        else {
16451            return;
16452        };
16453
16454        let end_position = if head != tail {
16455            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
16456                return;
16457            };
16458            Some(pos)
16459        } else {
16460            None
16461        };
16462
16463        let url_finder = cx.spawn_in(window, async move |_editor, cx| {
16464            let url = if let Some(end_pos) = end_position {
16465                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
16466            } else {
16467                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
16468            };
16469
16470            if let Some(url) = url {
16471                cx.update(|window, cx| {
16472                    if parse_zed_link(&url, cx).is_some() {
16473                        window.dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
16474                    } else {
16475                        cx.open_url(&url);
16476                    }
16477                })?;
16478            }
16479
16480            anyhow::Ok(())
16481        });
16482
16483        url_finder.detach();
16484    }
16485
16486    pub fn open_selected_filename(
16487        &mut self,
16488        _: &OpenSelectedFilename,
16489        window: &mut Window,
16490        cx: &mut Context<Self>,
16491    ) {
16492        let Some(workspace) = self.workspace() else {
16493            return;
16494        };
16495
16496        let position = self.selections.newest_anchor().head();
16497
16498        let Some((buffer, buffer_position)) =
16499            self.buffer.read(cx).text_anchor_for_position(position, cx)
16500        else {
16501            return;
16502        };
16503
16504        let project = self.project.clone();
16505
16506        cx.spawn_in(window, async move |_, cx| {
16507            let result = find_file(&buffer, project, buffer_position, cx).await;
16508
16509            if let Some((_, path)) = result {
16510                workspace
16511                    .update_in(cx, |workspace, window, cx| {
16512                        workspace.open_resolved_path(path, window, cx)
16513                    })?
16514                    .await?;
16515            }
16516            anyhow::Ok(())
16517        })
16518        .detach();
16519    }
16520
16521    pub(crate) fn navigate_to_hover_links(
16522        &mut self,
16523        kind: Option<GotoDefinitionKind>,
16524        definitions: Vec<HoverLink>,
16525        split: bool,
16526        window: &mut Window,
16527        cx: &mut Context<Editor>,
16528    ) -> Task<Result<Navigated>> {
16529        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
16530        let mut first_url_or_file = None;
16531        let definitions: Vec<_> = definitions
16532            .into_iter()
16533            .filter_map(|def| match def {
16534                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
16535                HoverLink::InlayHint(lsp_location, server_id) => {
16536                    let computation =
16537                        self.compute_target_location(lsp_location, server_id, window, cx);
16538                    Some(cx.background_spawn(computation))
16539                }
16540                HoverLink::Url(url) => {
16541                    first_url_or_file = Some(Either::Left(url));
16542                    None
16543                }
16544                HoverLink::File(path) => {
16545                    first_url_or_file = Some(Either::Right(path));
16546                    None
16547                }
16548            })
16549            .collect();
16550
16551        let workspace = self.workspace();
16552
16553        cx.spawn_in(window, async move |editor, cx| {
16554            let locations: Vec<Location> = future::join_all(definitions)
16555                .await
16556                .into_iter()
16557                .filter_map(|location| location.transpose())
16558                .collect::<Result<_>>()
16559                .context("location tasks")?;
16560            let mut locations = cx.update(|_, cx| {
16561                locations
16562                    .into_iter()
16563                    .map(|location| {
16564                        let buffer = location.buffer.read(cx);
16565                        (location.buffer, location.range.to_point(buffer))
16566                    })
16567                    .into_group_map()
16568            })?;
16569            let mut num_locations = 0;
16570            for ranges in locations.values_mut() {
16571                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
16572                ranges.dedup();
16573                num_locations += ranges.len();
16574            }
16575
16576            if num_locations > 1 {
16577                let Some(workspace) = workspace else {
16578                    return Ok(Navigated::No);
16579                };
16580
16581                let tab_kind = match kind {
16582                    Some(GotoDefinitionKind::Implementation) => "Implementations",
16583                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
16584                    Some(GotoDefinitionKind::Declaration) => "Declarations",
16585                    Some(GotoDefinitionKind::Type) => "Types",
16586                };
16587                let title = editor
16588                    .update_in(cx, |_, _, cx| {
16589                        let target = locations
16590                            .iter()
16591                            .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
16592                            .map(|(buffer, location)| {
16593                                buffer
16594                                    .read(cx)
16595                                    .text_for_range(location.clone())
16596                                    .collect::<String>()
16597                            })
16598                            .filter(|text| !text.contains('\n'))
16599                            .unique()
16600                            .take(3)
16601                            .join(", ");
16602                        if target.is_empty() {
16603                            tab_kind.to_owned()
16604                        } else {
16605                            format!("{tab_kind} for {target}")
16606                        }
16607                    })
16608                    .context("buffer title")?;
16609
16610                let opened = workspace
16611                    .update_in(cx, |workspace, window, cx| {
16612                        Self::open_locations_in_multibuffer(
16613                            workspace,
16614                            locations,
16615                            title,
16616                            split,
16617                            MultibufferSelectionMode::First,
16618                            window,
16619                            cx,
16620                        )
16621                    })
16622                    .is_ok();
16623
16624                anyhow::Ok(Navigated::from_bool(opened))
16625            } else if num_locations == 0 {
16626                // If there is one url or file, open it directly
16627                match first_url_or_file {
16628                    Some(Either::Left(url)) => {
16629                        cx.update(|_, cx| cx.open_url(&url))?;
16630                        Ok(Navigated::Yes)
16631                    }
16632                    Some(Either::Right(path)) => {
16633                        let Some(workspace) = workspace else {
16634                            return Ok(Navigated::No);
16635                        };
16636
16637                        workspace
16638                            .update_in(cx, |workspace, window, cx| {
16639                                workspace.open_resolved_path(path, window, cx)
16640                            })?
16641                            .await?;
16642                        Ok(Navigated::Yes)
16643                    }
16644                    None => Ok(Navigated::No),
16645                }
16646            } else {
16647                let Some(workspace) = workspace else {
16648                    return Ok(Navigated::No);
16649                };
16650
16651                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
16652                let target_range = target_ranges.first().unwrap().clone();
16653
16654                editor.update_in(cx, |editor, window, cx| {
16655                    let range = target_range.to_point(target_buffer.read(cx));
16656                    let range = editor.range_for_match(&range, false);
16657                    let range = collapse_multiline_range(range);
16658
16659                    if !split
16660                        && Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref()
16661                    {
16662                        editor.go_to_singleton_buffer_range(range, window, cx);
16663                    } else {
16664                        let pane = workspace.read(cx).active_pane().clone();
16665                        window.defer(cx, move |window, cx| {
16666                            let target_editor: Entity<Self> =
16667                                workspace.update(cx, |workspace, cx| {
16668                                    let pane = if split {
16669                                        workspace.adjacent_pane(window, cx)
16670                                    } else {
16671                                        workspace.active_pane().clone()
16672                                    };
16673
16674                                    workspace.open_project_item(
16675                                        pane,
16676                                        target_buffer.clone(),
16677                                        true,
16678                                        true,
16679                                        window,
16680                                        cx,
16681                                    )
16682                                });
16683                            target_editor.update(cx, |target_editor, cx| {
16684                                // When selecting a definition in a different buffer, disable the nav history
16685                                // to avoid creating a history entry at the previous cursor location.
16686                                pane.update(cx, |pane, _| pane.disable_history());
16687                                target_editor.go_to_singleton_buffer_range(range, window, cx);
16688                                pane.update(cx, |pane, _| pane.enable_history());
16689                            });
16690                        });
16691                    }
16692                    Navigated::Yes
16693                })
16694            }
16695        })
16696    }
16697
16698    fn compute_target_location(
16699        &self,
16700        lsp_location: lsp::Location,
16701        server_id: LanguageServerId,
16702        window: &mut Window,
16703        cx: &mut Context<Self>,
16704    ) -> Task<anyhow::Result<Option<Location>>> {
16705        let Some(project) = self.project.clone() else {
16706            return Task::ready(Ok(None));
16707        };
16708
16709        cx.spawn_in(window, async move |editor, cx| {
16710            let location_task = editor.update(cx, |_, cx| {
16711                project.update(cx, |project, cx| {
16712                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
16713                })
16714            })?;
16715            let location = Some({
16716                let target_buffer_handle = location_task.await.context("open local buffer")?;
16717                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
16718                    let target_start = target_buffer
16719                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
16720                    let target_end = target_buffer
16721                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
16722                    target_buffer.anchor_after(target_start)
16723                        ..target_buffer.anchor_before(target_end)
16724                })?;
16725                Location {
16726                    buffer: target_buffer_handle,
16727                    range,
16728                }
16729            });
16730            Ok(location)
16731        })
16732    }
16733
16734    fn go_to_next_reference(
16735        &mut self,
16736        _: &GoToNextReference,
16737        window: &mut Window,
16738        cx: &mut Context<Self>,
16739    ) {
16740        let task = self.go_to_reference_before_or_after_position(Direction::Next, 1, window, cx);
16741        if let Some(task) = task {
16742            task.detach();
16743        };
16744    }
16745
16746    fn go_to_prev_reference(
16747        &mut self,
16748        _: &GoToPreviousReference,
16749        window: &mut Window,
16750        cx: &mut Context<Self>,
16751    ) {
16752        let task = self.go_to_reference_before_or_after_position(Direction::Prev, 1, window, cx);
16753        if let Some(task) = task {
16754            task.detach();
16755        };
16756    }
16757
16758    pub fn go_to_reference_before_or_after_position(
16759        &mut self,
16760        direction: Direction,
16761        count: usize,
16762        window: &mut Window,
16763        cx: &mut Context<Self>,
16764    ) -> Option<Task<Result<()>>> {
16765        let selection = self.selections.newest_anchor();
16766        let head = selection.head();
16767
16768        let multi_buffer = self.buffer.read(cx);
16769
16770        let (buffer, text_head) = multi_buffer.text_anchor_for_position(head, cx)?;
16771        let workspace = self.workspace()?;
16772        let project = workspace.read(cx).project().clone();
16773        let references =
16774            project.update(cx, |project, cx| project.references(&buffer, text_head, cx));
16775        Some(cx.spawn_in(window, async move |editor, cx| -> Result<()> {
16776            let Some(locations) = references.await? else {
16777                return Ok(());
16778            };
16779
16780            if locations.is_empty() {
16781                // totally normal - the cursor may be on something which is not
16782                // a symbol (e.g. a keyword)
16783                log::info!("no references found under cursor");
16784                return Ok(());
16785            }
16786
16787            let multi_buffer = editor.read_with(cx, |editor, _| editor.buffer().clone())?;
16788
16789            let multi_buffer_snapshot =
16790                multi_buffer.read_with(cx, |multi_buffer, cx| multi_buffer.snapshot(cx))?;
16791
16792            let (locations, current_location_index) =
16793                multi_buffer.update(cx, |multi_buffer, cx| {
16794                    let mut locations = locations
16795                        .into_iter()
16796                        .filter_map(|loc| {
16797                            let start = multi_buffer.buffer_anchor_to_anchor(
16798                                &loc.buffer,
16799                                loc.range.start,
16800                                cx,
16801                            )?;
16802                            let end = multi_buffer.buffer_anchor_to_anchor(
16803                                &loc.buffer,
16804                                loc.range.end,
16805                                cx,
16806                            )?;
16807                            Some(start..end)
16808                        })
16809                        .collect::<Vec<_>>();
16810
16811                    // There is an O(n) implementation, but given this list will be
16812                    // small (usually <100 items), the extra O(log(n)) factor isn't
16813                    // worth the (surprisingly large amount of) extra complexity.
16814                    locations
16815                        .sort_unstable_by(|l, r| l.start.cmp(&r.start, &multi_buffer_snapshot));
16816
16817                    let head_offset = head.to_offset(&multi_buffer_snapshot);
16818
16819                    let current_location_index = locations.iter().position(|loc| {
16820                        loc.start.to_offset(&multi_buffer_snapshot) <= head_offset
16821                            && loc.end.to_offset(&multi_buffer_snapshot) >= head_offset
16822                    });
16823
16824                    (locations, current_location_index)
16825                })?;
16826
16827            let Some(current_location_index) = current_location_index else {
16828                // This indicates something has gone wrong, because we already
16829                // handle the "no references" case above
16830                log::error!(
16831                    "failed to find current reference under cursor. Total references: {}",
16832                    locations.len()
16833                );
16834                return Ok(());
16835            };
16836
16837            let destination_location_index = match direction {
16838                Direction::Next => (current_location_index + count) % locations.len(),
16839                Direction::Prev => {
16840                    (current_location_index + locations.len() - count % locations.len())
16841                        % locations.len()
16842                }
16843            };
16844
16845            // TODO(cameron): is this needed?
16846            // the thinking is to avoid "jumping to the current location" (avoid
16847            // polluting "jumplist" in vim terms)
16848            if current_location_index == destination_location_index {
16849                return Ok(());
16850            }
16851
16852            let Range { start, end } = locations[destination_location_index];
16853
16854            editor.update_in(cx, |editor, window, cx| {
16855                let effects = SelectionEffects::default();
16856
16857                editor.unfold_ranges(&[start..end], false, false, cx);
16858                editor.change_selections(effects, window, cx, |s| {
16859                    s.select_ranges([start..start]);
16860                });
16861            })?;
16862
16863            Ok(())
16864        }))
16865    }
16866
16867    pub fn find_all_references(
16868        &mut self,
16869        _: &FindAllReferences,
16870        window: &mut Window,
16871        cx: &mut Context<Self>,
16872    ) -> Option<Task<Result<Navigated>>> {
16873        let selection = self.selections.newest::<usize>(&self.display_snapshot(cx));
16874        let multi_buffer = self.buffer.read(cx);
16875        let head = selection.head();
16876
16877        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
16878        let head_anchor = multi_buffer_snapshot.anchor_at(
16879            head,
16880            if head < selection.tail() {
16881                Bias::Right
16882            } else {
16883                Bias::Left
16884            },
16885        );
16886
16887        match self
16888            .find_all_references_task_sources
16889            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16890        {
16891            Ok(_) => {
16892                log::info!(
16893                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
16894                );
16895                return None;
16896            }
16897            Err(i) => {
16898                self.find_all_references_task_sources.insert(i, head_anchor);
16899            }
16900        }
16901
16902        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
16903        let workspace = self.workspace()?;
16904        let project = workspace.read(cx).project().clone();
16905        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
16906        Some(cx.spawn_in(window, async move |editor, cx| {
16907            let _cleanup = cx.on_drop(&editor, move |editor, _| {
16908                if let Ok(i) = editor
16909                    .find_all_references_task_sources
16910                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16911                {
16912                    editor.find_all_references_task_sources.remove(i);
16913                }
16914            });
16915
16916            let Some(locations) = references.await? else {
16917                return anyhow::Ok(Navigated::No);
16918            };
16919            let mut locations = cx.update(|_, cx| {
16920                locations
16921                    .into_iter()
16922                    .map(|location| {
16923                        let buffer = location.buffer.read(cx);
16924                        (location.buffer, location.range.to_point(buffer))
16925                    })
16926                    .into_group_map()
16927            })?;
16928            if locations.is_empty() {
16929                return anyhow::Ok(Navigated::No);
16930            }
16931            for ranges in locations.values_mut() {
16932                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
16933                ranges.dedup();
16934            }
16935
16936            workspace.update_in(cx, |workspace, window, cx| {
16937                let target = locations
16938                    .iter()
16939                    .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
16940                    .map(|(buffer, location)| {
16941                        buffer
16942                            .read(cx)
16943                            .text_for_range(location.clone())
16944                            .collect::<String>()
16945                    })
16946                    .filter(|text| !text.contains('\n'))
16947                    .unique()
16948                    .take(3)
16949                    .join(", ");
16950                let title = if target.is_empty() {
16951                    "References".to_owned()
16952                } else {
16953                    format!("References to {target}")
16954                };
16955                Self::open_locations_in_multibuffer(
16956                    workspace,
16957                    locations,
16958                    title,
16959                    false,
16960                    MultibufferSelectionMode::First,
16961                    window,
16962                    cx,
16963                );
16964                Navigated::Yes
16965            })
16966        }))
16967    }
16968
16969    /// Opens a multibuffer with the given project locations in it
16970    pub fn open_locations_in_multibuffer(
16971        workspace: &mut Workspace,
16972        locations: std::collections::HashMap<Entity<Buffer>, Vec<Range<Point>>>,
16973        title: String,
16974        split: bool,
16975        multibuffer_selection_mode: MultibufferSelectionMode,
16976        window: &mut Window,
16977        cx: &mut Context<Workspace>,
16978    ) {
16979        if locations.is_empty() {
16980            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
16981            return;
16982        }
16983
16984        let capability = workspace.project().read(cx).capability();
16985        let mut ranges = <Vec<Range<Anchor>>>::new();
16986
16987        // a key to find existing multibuffer editors with the same set of locations
16988        // to prevent us from opening more and more multibuffer tabs for searches and the like
16989        let mut key = (title.clone(), vec![]);
16990        let excerpt_buffer = cx.new(|cx| {
16991            let key = &mut key.1;
16992            let mut multibuffer = MultiBuffer::new(capability);
16993            for (buffer, mut ranges_for_buffer) in locations {
16994                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
16995                key.push((buffer.read(cx).remote_id(), ranges_for_buffer.clone()));
16996                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
16997                    PathKey::for_buffer(&buffer, cx),
16998                    buffer.clone(),
16999                    ranges_for_buffer,
17000                    multibuffer_context_lines(cx),
17001                    cx,
17002                );
17003                ranges.extend(new_ranges)
17004            }
17005
17006            multibuffer.with_title(title)
17007        });
17008        let existing = workspace.active_pane().update(cx, |pane, cx| {
17009            pane.items()
17010                .filter_map(|item| item.downcast::<Editor>())
17011                .find(|editor| {
17012                    editor
17013                        .read(cx)
17014                        .lookup_key
17015                        .as_ref()
17016                        .and_then(|it| {
17017                            it.downcast_ref::<(String, Vec<(BufferId, Vec<Range<Point>>)>)>()
17018                        })
17019                        .is_some_and(|it| *it == key)
17020                })
17021        });
17022        let editor = existing.unwrap_or_else(|| {
17023            cx.new(|cx| {
17024                let mut editor = Editor::for_multibuffer(
17025                    excerpt_buffer,
17026                    Some(workspace.project().clone()),
17027                    window,
17028                    cx,
17029                );
17030                editor.lookup_key = Some(Box::new(key));
17031                editor
17032            })
17033        });
17034        editor.update(cx, |editor, cx| match multibuffer_selection_mode {
17035            MultibufferSelectionMode::First => {
17036                if let Some(first_range) = ranges.first() {
17037                    editor.change_selections(
17038                        SelectionEffects::no_scroll(),
17039                        window,
17040                        cx,
17041                        |selections| {
17042                            selections.clear_disjoint();
17043                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
17044                        },
17045                    );
17046                }
17047                editor.highlight_background::<Self>(
17048                    &ranges,
17049                    |theme| theme.colors().editor_highlighted_line_background,
17050                    cx,
17051                );
17052            }
17053            MultibufferSelectionMode::All => {
17054                editor.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
17055                    selections.clear_disjoint();
17056                    selections.select_anchor_ranges(ranges);
17057                });
17058            }
17059        });
17060
17061        let item = Box::new(editor);
17062        let item_id = item.item_id();
17063
17064        if split {
17065            let pane = workspace.adjacent_pane(window, cx);
17066            workspace.add_item(pane, item, None, true, true, window, cx);
17067        } else if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
17068            let (preview_item_id, preview_item_idx) =
17069                workspace.active_pane().read_with(cx, |pane, _| {
17070                    (pane.preview_item_id(), pane.preview_item_idx())
17071                });
17072
17073            workspace.add_item_to_active_pane(item, preview_item_idx, true, window, cx);
17074
17075            if let Some(preview_item_id) = preview_item_id {
17076                workspace.active_pane().update(cx, |pane, cx| {
17077                    pane.remove_item(preview_item_id, false, false, window, cx);
17078                });
17079            }
17080        } else {
17081            workspace.add_item_to_active_pane(item, None, true, window, cx);
17082        }
17083        workspace.active_pane().update(cx, |pane, cx| {
17084            pane.set_preview_item_id(Some(item_id), cx);
17085        });
17086    }
17087
17088    pub fn rename(
17089        &mut self,
17090        _: &Rename,
17091        window: &mut Window,
17092        cx: &mut Context<Self>,
17093    ) -> Option<Task<Result<()>>> {
17094        use language::ToOffset as _;
17095
17096        let provider = self.semantics_provider.clone()?;
17097        let selection = self.selections.newest_anchor().clone();
17098        let (cursor_buffer, cursor_buffer_position) = self
17099            .buffer
17100            .read(cx)
17101            .text_anchor_for_position(selection.head(), cx)?;
17102        let (tail_buffer, cursor_buffer_position_end) = self
17103            .buffer
17104            .read(cx)
17105            .text_anchor_for_position(selection.tail(), cx)?;
17106        if tail_buffer != cursor_buffer {
17107            return None;
17108        }
17109
17110        let snapshot = cursor_buffer.read(cx).snapshot();
17111        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
17112        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
17113        let prepare_rename = provider
17114            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
17115            .unwrap_or_else(|| Task::ready(Ok(None)));
17116        drop(snapshot);
17117
17118        Some(cx.spawn_in(window, async move |this, cx| {
17119            let rename_range = if let Some(range) = prepare_rename.await? {
17120                Some(range)
17121            } else {
17122                this.update(cx, |this, cx| {
17123                    let buffer = this.buffer.read(cx).snapshot(cx);
17124                    let mut buffer_highlights = this
17125                        .document_highlights_for_position(selection.head(), &buffer)
17126                        .filter(|highlight| {
17127                            highlight.start.excerpt_id == selection.head().excerpt_id
17128                                && highlight.end.excerpt_id == selection.head().excerpt_id
17129                        });
17130                    buffer_highlights
17131                        .next()
17132                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
17133                })?
17134            };
17135            if let Some(rename_range) = rename_range {
17136                this.update_in(cx, |this, window, cx| {
17137                    let snapshot = cursor_buffer.read(cx).snapshot();
17138                    let rename_buffer_range = rename_range.to_offset(&snapshot);
17139                    let cursor_offset_in_rename_range =
17140                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
17141                    let cursor_offset_in_rename_range_end =
17142                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
17143
17144                    this.take_rename(false, window, cx);
17145                    let buffer = this.buffer.read(cx).read(cx);
17146                    let cursor_offset = selection.head().to_offset(&buffer);
17147                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
17148                    let rename_end = rename_start + rename_buffer_range.len();
17149                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
17150                    let mut old_highlight_id = None;
17151                    let old_name: Arc<str> = buffer
17152                        .chunks(rename_start..rename_end, true)
17153                        .map(|chunk| {
17154                            if old_highlight_id.is_none() {
17155                                old_highlight_id = chunk.syntax_highlight_id;
17156                            }
17157                            chunk.text
17158                        })
17159                        .collect::<String>()
17160                        .into();
17161
17162                    drop(buffer);
17163
17164                    // Position the selection in the rename editor so that it matches the current selection.
17165                    this.show_local_selections = false;
17166                    let rename_editor = cx.new(|cx| {
17167                        let mut editor = Editor::single_line(window, cx);
17168                        editor.buffer.update(cx, |buffer, cx| {
17169                            buffer.edit([(0..0, old_name.clone())], None, cx)
17170                        });
17171                        let rename_selection_range = match cursor_offset_in_rename_range
17172                            .cmp(&cursor_offset_in_rename_range_end)
17173                        {
17174                            Ordering::Equal => {
17175                                editor.select_all(&SelectAll, window, cx);
17176                                return editor;
17177                            }
17178                            Ordering::Less => {
17179                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
17180                            }
17181                            Ordering::Greater => {
17182                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
17183                            }
17184                        };
17185                        if rename_selection_range.end > old_name.len() {
17186                            editor.select_all(&SelectAll, window, cx);
17187                        } else {
17188                            editor.change_selections(Default::default(), window, cx, |s| {
17189                                s.select_ranges([rename_selection_range]);
17190                            });
17191                        }
17192                        editor
17193                    });
17194                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
17195                        if e == &EditorEvent::Focused {
17196                            cx.emit(EditorEvent::FocusedIn)
17197                        }
17198                    })
17199                    .detach();
17200
17201                    let write_highlights =
17202                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
17203                    let read_highlights =
17204                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
17205                    let ranges = write_highlights
17206                        .iter()
17207                        .flat_map(|(_, ranges)| ranges.iter())
17208                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
17209                        .cloned()
17210                        .collect();
17211
17212                    this.highlight_text::<Rename>(
17213                        ranges,
17214                        HighlightStyle {
17215                            fade_out: Some(0.6),
17216                            ..Default::default()
17217                        },
17218                        cx,
17219                    );
17220                    let rename_focus_handle = rename_editor.focus_handle(cx);
17221                    window.focus(&rename_focus_handle);
17222                    let block_id = this.insert_blocks(
17223                        [BlockProperties {
17224                            style: BlockStyle::Flex,
17225                            placement: BlockPlacement::Below(range.start),
17226                            height: Some(1),
17227                            render: Arc::new({
17228                                let rename_editor = rename_editor.clone();
17229                                move |cx: &mut BlockContext| {
17230                                    let mut text_style = cx.editor_style.text.clone();
17231                                    if let Some(highlight_style) = old_highlight_id
17232                                        .and_then(|h| h.style(&cx.editor_style.syntax))
17233                                    {
17234                                        text_style = text_style.highlight(highlight_style);
17235                                    }
17236                                    div()
17237                                        .block_mouse_except_scroll()
17238                                        .pl(cx.anchor_x)
17239                                        .child(EditorElement::new(
17240                                            &rename_editor,
17241                                            EditorStyle {
17242                                                background: cx.theme().system().transparent,
17243                                                local_player: cx.editor_style.local_player,
17244                                                text: text_style,
17245                                                scrollbar_width: cx.editor_style.scrollbar_width,
17246                                                syntax: cx.editor_style.syntax.clone(),
17247                                                status: cx.editor_style.status.clone(),
17248                                                inlay_hints_style: HighlightStyle {
17249                                                    font_weight: Some(FontWeight::BOLD),
17250                                                    ..make_inlay_hints_style(cx.app)
17251                                                },
17252                                                edit_prediction_styles: make_suggestion_styles(
17253                                                    cx.app,
17254                                                ),
17255                                                ..EditorStyle::default()
17256                                            },
17257                                        ))
17258                                        .into_any_element()
17259                                }
17260                            }),
17261                            priority: 0,
17262                        }],
17263                        Some(Autoscroll::fit()),
17264                        cx,
17265                    )[0];
17266                    this.pending_rename = Some(RenameState {
17267                        range,
17268                        old_name,
17269                        editor: rename_editor,
17270                        block_id,
17271                    });
17272                })?;
17273            }
17274
17275            Ok(())
17276        }))
17277    }
17278
17279    pub fn confirm_rename(
17280        &mut self,
17281        _: &ConfirmRename,
17282        window: &mut Window,
17283        cx: &mut Context<Self>,
17284    ) -> Option<Task<Result<()>>> {
17285        let rename = self.take_rename(false, window, cx)?;
17286        let workspace = self.workspace()?.downgrade();
17287        let (buffer, start) = self
17288            .buffer
17289            .read(cx)
17290            .text_anchor_for_position(rename.range.start, cx)?;
17291        let (end_buffer, _) = self
17292            .buffer
17293            .read(cx)
17294            .text_anchor_for_position(rename.range.end, cx)?;
17295        if buffer != end_buffer {
17296            return None;
17297        }
17298
17299        let old_name = rename.old_name;
17300        let new_name = rename.editor.read(cx).text(cx);
17301
17302        let rename = self.semantics_provider.as_ref()?.perform_rename(
17303            &buffer,
17304            start,
17305            new_name.clone(),
17306            cx,
17307        )?;
17308
17309        Some(cx.spawn_in(window, async move |editor, cx| {
17310            let project_transaction = rename.await?;
17311            Self::open_project_transaction(
17312                &editor,
17313                workspace,
17314                project_transaction,
17315                format!("Rename: {}{}", old_name, new_name),
17316                cx,
17317            )
17318            .await?;
17319
17320            editor.update(cx, |editor, cx| {
17321                editor.refresh_document_highlights(cx);
17322            })?;
17323            Ok(())
17324        }))
17325    }
17326
17327    fn take_rename(
17328        &mut self,
17329        moving_cursor: bool,
17330        window: &mut Window,
17331        cx: &mut Context<Self>,
17332    ) -> Option<RenameState> {
17333        let rename = self.pending_rename.take()?;
17334        if rename.editor.focus_handle(cx).is_focused(window) {
17335            window.focus(&self.focus_handle);
17336        }
17337
17338        self.remove_blocks(
17339            [rename.block_id].into_iter().collect(),
17340            Some(Autoscroll::fit()),
17341            cx,
17342        );
17343        self.clear_highlights::<Rename>(cx);
17344        self.show_local_selections = true;
17345
17346        if moving_cursor {
17347            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
17348                editor
17349                    .selections
17350                    .newest::<usize>(&editor.display_snapshot(cx))
17351                    .head()
17352            });
17353
17354            // Update the selection to match the position of the selection inside
17355            // the rename editor.
17356            let snapshot = self.buffer.read(cx).read(cx);
17357            let rename_range = rename.range.to_offset(&snapshot);
17358            let cursor_in_editor = snapshot
17359                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
17360                .min(rename_range.end);
17361            drop(snapshot);
17362
17363            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17364                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
17365            });
17366        } else {
17367            self.refresh_document_highlights(cx);
17368        }
17369
17370        Some(rename)
17371    }
17372
17373    pub fn pending_rename(&self) -> Option<&RenameState> {
17374        self.pending_rename.as_ref()
17375    }
17376
17377    fn format(
17378        &mut self,
17379        _: &Format,
17380        window: &mut Window,
17381        cx: &mut Context<Self>,
17382    ) -> Option<Task<Result<()>>> {
17383        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17384
17385        let project = match &self.project {
17386            Some(project) => project.clone(),
17387            None => return None,
17388        };
17389
17390        Some(self.perform_format(
17391            project,
17392            FormatTrigger::Manual,
17393            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
17394            window,
17395            cx,
17396        ))
17397    }
17398
17399    fn format_selections(
17400        &mut self,
17401        _: &FormatSelections,
17402        window: &mut Window,
17403        cx: &mut Context<Self>,
17404    ) -> Option<Task<Result<()>>> {
17405        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17406
17407        let project = match &self.project {
17408            Some(project) => project.clone(),
17409            None => return None,
17410        };
17411
17412        let ranges = self
17413            .selections
17414            .all_adjusted(&self.display_snapshot(cx))
17415            .into_iter()
17416            .map(|selection| selection.range())
17417            .collect_vec();
17418
17419        Some(self.perform_format(
17420            project,
17421            FormatTrigger::Manual,
17422            FormatTarget::Ranges(ranges),
17423            window,
17424            cx,
17425        ))
17426    }
17427
17428    fn perform_format(
17429        &mut self,
17430        project: Entity<Project>,
17431        trigger: FormatTrigger,
17432        target: FormatTarget,
17433        window: &mut Window,
17434        cx: &mut Context<Self>,
17435    ) -> Task<Result<()>> {
17436        let buffer = self.buffer.clone();
17437        let (buffers, target) = match target {
17438            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
17439            FormatTarget::Ranges(selection_ranges) => {
17440                let multi_buffer = buffer.read(cx);
17441                let snapshot = multi_buffer.read(cx);
17442                let mut buffers = HashSet::default();
17443                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
17444                    BTreeMap::new();
17445                for selection_range in selection_ranges {
17446                    for (buffer, buffer_range, _) in
17447                        snapshot.range_to_buffer_ranges(selection_range)
17448                    {
17449                        let buffer_id = buffer.remote_id();
17450                        let start = buffer.anchor_before(buffer_range.start);
17451                        let end = buffer.anchor_after(buffer_range.end);
17452                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
17453                        buffer_id_to_ranges
17454                            .entry(buffer_id)
17455                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
17456                            .or_insert_with(|| vec![start..end]);
17457                    }
17458                }
17459                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
17460            }
17461        };
17462
17463        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
17464        let selections_prev = transaction_id_prev
17465            .and_then(|transaction_id_prev| {
17466                // default to selections as they were after the last edit, if we have them,
17467                // instead of how they are now.
17468                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
17469                // will take you back to where you made the last edit, instead of staying where you scrolled
17470                self.selection_history
17471                    .transaction(transaction_id_prev)
17472                    .map(|t| t.0.clone())
17473            })
17474            .unwrap_or_else(|| self.selections.disjoint_anchors_arc());
17475
17476        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
17477        let format = project.update(cx, |project, cx| {
17478            project.format(buffers, target, true, trigger, cx)
17479        });
17480
17481        cx.spawn_in(window, async move |editor, cx| {
17482            let transaction = futures::select_biased! {
17483                transaction = format.log_err().fuse() => transaction,
17484                () = timeout => {
17485                    log::warn!("timed out waiting for formatting");
17486                    None
17487                }
17488            };
17489
17490            buffer
17491                .update(cx, |buffer, cx| {
17492                    if let Some(transaction) = transaction
17493                        && !buffer.is_singleton()
17494                    {
17495                        buffer.push_transaction(&transaction.0, cx);
17496                    }
17497                    cx.notify();
17498                })
17499                .ok();
17500
17501            if let Some(transaction_id_now) =
17502                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
17503            {
17504                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
17505                if has_new_transaction {
17506                    _ = editor.update(cx, |editor, _| {
17507                        editor
17508                            .selection_history
17509                            .insert_transaction(transaction_id_now, selections_prev);
17510                    });
17511                }
17512            }
17513
17514            Ok(())
17515        })
17516    }
17517
17518    fn organize_imports(
17519        &mut self,
17520        _: &OrganizeImports,
17521        window: &mut Window,
17522        cx: &mut Context<Self>,
17523    ) -> Option<Task<Result<()>>> {
17524        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17525        let project = match &self.project {
17526            Some(project) => project.clone(),
17527            None => return None,
17528        };
17529        Some(self.perform_code_action_kind(
17530            project,
17531            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
17532            window,
17533            cx,
17534        ))
17535    }
17536
17537    fn perform_code_action_kind(
17538        &mut self,
17539        project: Entity<Project>,
17540        kind: CodeActionKind,
17541        window: &mut Window,
17542        cx: &mut Context<Self>,
17543    ) -> Task<Result<()>> {
17544        let buffer = self.buffer.clone();
17545        let buffers = buffer.read(cx).all_buffers();
17546        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
17547        let apply_action = project.update(cx, |project, cx| {
17548            project.apply_code_action_kind(buffers, kind, true, cx)
17549        });
17550        cx.spawn_in(window, async move |_, cx| {
17551            let transaction = futures::select_biased! {
17552                () = timeout => {
17553                    log::warn!("timed out waiting for executing code action");
17554                    None
17555                }
17556                transaction = apply_action.log_err().fuse() => transaction,
17557            };
17558            buffer
17559                .update(cx, |buffer, cx| {
17560                    // check if we need this
17561                    if let Some(transaction) = transaction
17562                        && !buffer.is_singleton()
17563                    {
17564                        buffer.push_transaction(&transaction.0, cx);
17565                    }
17566                    cx.notify();
17567                })
17568                .ok();
17569            Ok(())
17570        })
17571    }
17572
17573    pub fn restart_language_server(
17574        &mut self,
17575        _: &RestartLanguageServer,
17576        _: &mut Window,
17577        cx: &mut Context<Self>,
17578    ) {
17579        if let Some(project) = self.project.clone() {
17580            self.buffer.update(cx, |multi_buffer, cx| {
17581                project.update(cx, |project, cx| {
17582                    project.restart_language_servers_for_buffers(
17583                        multi_buffer.all_buffers().into_iter().collect(),
17584                        HashSet::default(),
17585                        cx,
17586                    );
17587                });
17588            })
17589        }
17590    }
17591
17592    pub fn stop_language_server(
17593        &mut self,
17594        _: &StopLanguageServer,
17595        _: &mut Window,
17596        cx: &mut Context<Self>,
17597    ) {
17598        if let Some(project) = self.project.clone() {
17599            self.buffer.update(cx, |multi_buffer, cx| {
17600                project.update(cx, |project, cx| {
17601                    project.stop_language_servers_for_buffers(
17602                        multi_buffer.all_buffers().into_iter().collect(),
17603                        HashSet::default(),
17604                        cx,
17605                    );
17606                });
17607            });
17608            self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
17609        }
17610    }
17611
17612    fn cancel_language_server_work(
17613        workspace: &mut Workspace,
17614        _: &actions::CancelLanguageServerWork,
17615        _: &mut Window,
17616        cx: &mut Context<Workspace>,
17617    ) {
17618        let project = workspace.project();
17619        let buffers = workspace
17620            .active_item(cx)
17621            .and_then(|item| item.act_as::<Editor>(cx))
17622            .map_or(HashSet::default(), |editor| {
17623                editor.read(cx).buffer.read(cx).all_buffers()
17624            });
17625        project.update(cx, |project, cx| {
17626            project.cancel_language_server_work_for_buffers(buffers, cx);
17627        });
17628    }
17629
17630    fn show_character_palette(
17631        &mut self,
17632        _: &ShowCharacterPalette,
17633        window: &mut Window,
17634        _: &mut Context<Self>,
17635    ) {
17636        window.show_character_palette();
17637    }
17638
17639    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
17640        if !self.diagnostics_enabled() {
17641            return;
17642        }
17643
17644        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
17645            let buffer = self.buffer.read(cx).snapshot(cx);
17646            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
17647            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
17648            let is_valid = buffer
17649                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
17650                .any(|entry| {
17651                    entry.diagnostic.is_primary
17652                        && !entry.range.is_empty()
17653                        && entry.range.start == primary_range_start
17654                        && entry.diagnostic.message == active_diagnostics.active_message
17655                });
17656
17657            if !is_valid {
17658                self.dismiss_diagnostics(cx);
17659            }
17660        }
17661    }
17662
17663    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
17664        match &self.active_diagnostics {
17665            ActiveDiagnostic::Group(group) => Some(group),
17666            _ => None,
17667        }
17668    }
17669
17670    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
17671        if !self.diagnostics_enabled() {
17672            return;
17673        }
17674        self.dismiss_diagnostics(cx);
17675        self.active_diagnostics = ActiveDiagnostic::All;
17676    }
17677
17678    fn activate_diagnostics(
17679        &mut self,
17680        buffer_id: BufferId,
17681        diagnostic: DiagnosticEntryRef<'_, usize>,
17682        window: &mut Window,
17683        cx: &mut Context<Self>,
17684    ) {
17685        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17686            return;
17687        }
17688        self.dismiss_diagnostics(cx);
17689        let snapshot = self.snapshot(window, cx);
17690        let buffer = self.buffer.read(cx).snapshot(cx);
17691        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
17692            return;
17693        };
17694
17695        let diagnostic_group = buffer
17696            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
17697            .collect::<Vec<_>>();
17698
17699        let blocks =
17700            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
17701
17702        let blocks = self.display_map.update(cx, |display_map, cx| {
17703            display_map.insert_blocks(blocks, cx).into_iter().collect()
17704        });
17705        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
17706            active_range: buffer.anchor_before(diagnostic.range.start)
17707                ..buffer.anchor_after(diagnostic.range.end),
17708            active_message: diagnostic.diagnostic.message.clone(),
17709            group_id: diagnostic.diagnostic.group_id,
17710            blocks,
17711        });
17712        cx.notify();
17713    }
17714
17715    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
17716        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17717            return;
17718        };
17719
17720        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
17721        if let ActiveDiagnostic::Group(group) = prev {
17722            self.display_map.update(cx, |display_map, cx| {
17723                display_map.remove_blocks(group.blocks, cx);
17724            });
17725            cx.notify();
17726        }
17727    }
17728
17729    /// Disable inline diagnostics rendering for this editor.
17730    pub fn disable_inline_diagnostics(&mut self) {
17731        self.inline_diagnostics_enabled = false;
17732        self.inline_diagnostics_update = Task::ready(());
17733        self.inline_diagnostics.clear();
17734    }
17735
17736    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
17737        self.diagnostics_enabled = false;
17738        self.dismiss_diagnostics(cx);
17739        self.inline_diagnostics_update = Task::ready(());
17740        self.inline_diagnostics.clear();
17741    }
17742
17743    pub fn disable_word_completions(&mut self) {
17744        self.word_completions_enabled = false;
17745    }
17746
17747    pub fn diagnostics_enabled(&self) -> bool {
17748        self.diagnostics_enabled && self.mode.is_full()
17749    }
17750
17751    pub fn inline_diagnostics_enabled(&self) -> bool {
17752        self.inline_diagnostics_enabled && self.diagnostics_enabled()
17753    }
17754
17755    pub fn show_inline_diagnostics(&self) -> bool {
17756        self.show_inline_diagnostics
17757    }
17758
17759    pub fn toggle_inline_diagnostics(
17760        &mut self,
17761        _: &ToggleInlineDiagnostics,
17762        window: &mut Window,
17763        cx: &mut Context<Editor>,
17764    ) {
17765        self.show_inline_diagnostics = !self.show_inline_diagnostics;
17766        self.refresh_inline_diagnostics(false, window, cx);
17767    }
17768
17769    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
17770        self.diagnostics_max_severity = severity;
17771        self.display_map.update(cx, |display_map, _| {
17772            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
17773        });
17774    }
17775
17776    pub fn toggle_diagnostics(
17777        &mut self,
17778        _: &ToggleDiagnostics,
17779        window: &mut Window,
17780        cx: &mut Context<Editor>,
17781    ) {
17782        if !self.diagnostics_enabled() {
17783            return;
17784        }
17785
17786        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17787            EditorSettings::get_global(cx)
17788                .diagnostics_max_severity
17789                .filter(|severity| severity != &DiagnosticSeverity::Off)
17790                .unwrap_or(DiagnosticSeverity::Hint)
17791        } else {
17792            DiagnosticSeverity::Off
17793        };
17794        self.set_max_diagnostics_severity(new_severity, cx);
17795        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17796            self.active_diagnostics = ActiveDiagnostic::None;
17797            self.inline_diagnostics_update = Task::ready(());
17798            self.inline_diagnostics.clear();
17799        } else {
17800            self.refresh_inline_diagnostics(false, window, cx);
17801        }
17802
17803        cx.notify();
17804    }
17805
17806    pub fn toggle_minimap(
17807        &mut self,
17808        _: &ToggleMinimap,
17809        window: &mut Window,
17810        cx: &mut Context<Editor>,
17811    ) {
17812        if self.supports_minimap(cx) {
17813            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
17814        }
17815    }
17816
17817    fn refresh_inline_diagnostics(
17818        &mut self,
17819        debounce: bool,
17820        window: &mut Window,
17821        cx: &mut Context<Self>,
17822    ) {
17823        let max_severity = ProjectSettings::get_global(cx)
17824            .diagnostics
17825            .inline
17826            .max_severity
17827            .unwrap_or(self.diagnostics_max_severity);
17828
17829        if !self.inline_diagnostics_enabled()
17830            || !self.show_inline_diagnostics
17831            || max_severity == DiagnosticSeverity::Off
17832        {
17833            self.inline_diagnostics_update = Task::ready(());
17834            self.inline_diagnostics.clear();
17835            return;
17836        }
17837
17838        let debounce_ms = ProjectSettings::get_global(cx)
17839            .diagnostics
17840            .inline
17841            .update_debounce_ms;
17842        let debounce = if debounce && debounce_ms > 0 {
17843            Some(Duration::from_millis(debounce_ms))
17844        } else {
17845            None
17846        };
17847        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
17848            if let Some(debounce) = debounce {
17849                cx.background_executor().timer(debounce).await;
17850            }
17851            let Some(snapshot) = editor.upgrade().and_then(|editor| {
17852                editor
17853                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
17854                    .ok()
17855            }) else {
17856                return;
17857            };
17858
17859            let new_inline_diagnostics = cx
17860                .background_spawn(async move {
17861                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
17862                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
17863                        let message = diagnostic_entry
17864                            .diagnostic
17865                            .message
17866                            .split_once('\n')
17867                            .map(|(line, _)| line)
17868                            .map(SharedString::new)
17869                            .unwrap_or_else(|| {
17870                                SharedString::new(&*diagnostic_entry.diagnostic.message)
17871                            });
17872                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
17873                        let (Ok(i) | Err(i)) = inline_diagnostics
17874                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
17875                        inline_diagnostics.insert(
17876                            i,
17877                            (
17878                                start_anchor,
17879                                InlineDiagnostic {
17880                                    message,
17881                                    group_id: diagnostic_entry.diagnostic.group_id,
17882                                    start: diagnostic_entry.range.start.to_point(&snapshot),
17883                                    is_primary: diagnostic_entry.diagnostic.is_primary,
17884                                    severity: diagnostic_entry.diagnostic.severity,
17885                                },
17886                            ),
17887                        );
17888                    }
17889                    inline_diagnostics
17890                })
17891                .await;
17892
17893            editor
17894                .update(cx, |editor, cx| {
17895                    editor.inline_diagnostics = new_inline_diagnostics;
17896                    cx.notify();
17897                })
17898                .ok();
17899        });
17900    }
17901
17902    fn pull_diagnostics(
17903        &mut self,
17904        buffer_id: Option<BufferId>,
17905        window: &Window,
17906        cx: &mut Context<Self>,
17907    ) -> Option<()> {
17908        if self.ignore_lsp_data() {
17909            return None;
17910        }
17911        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
17912            .diagnostics
17913            .lsp_pull_diagnostics;
17914        if !pull_diagnostics_settings.enabled {
17915            return None;
17916        }
17917        let project = self.project()?.downgrade();
17918        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
17919        let mut buffers = self.buffer.read(cx).all_buffers();
17920        buffers.retain(|buffer| {
17921            let buffer_id_to_retain = buffer.read(cx).remote_id();
17922            buffer_id.is_none_or(|buffer_id| buffer_id == buffer_id_to_retain)
17923                && self.registered_buffers.contains_key(&buffer_id_to_retain)
17924        });
17925        if buffers.is_empty() {
17926            self.pull_diagnostics_task = Task::ready(());
17927            return None;
17928        }
17929
17930        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
17931            cx.background_executor().timer(debounce).await;
17932
17933            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
17934                buffers
17935                    .into_iter()
17936                    .filter_map(|buffer| {
17937                        project
17938                            .update(cx, |project, cx| {
17939                                project.lsp_store().update(cx, |lsp_store, cx| {
17940                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
17941                                })
17942                            })
17943                            .ok()
17944                    })
17945                    .collect::<FuturesUnordered<_>>()
17946            }) else {
17947                return;
17948            };
17949
17950            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
17951                match pull_task {
17952                    Ok(()) => {
17953                        if editor
17954                            .update_in(cx, |editor, window, cx| {
17955                                editor.update_diagnostics_state(window, cx);
17956                            })
17957                            .is_err()
17958                        {
17959                            return;
17960                        }
17961                    }
17962                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
17963                }
17964            }
17965        });
17966
17967        Some(())
17968    }
17969
17970    pub fn set_selections_from_remote(
17971        &mut self,
17972        selections: Vec<Selection<Anchor>>,
17973        pending_selection: Option<Selection<Anchor>>,
17974        window: &mut Window,
17975        cx: &mut Context<Self>,
17976    ) {
17977        let old_cursor_position = self.selections.newest_anchor().head();
17978        self.selections.change_with(cx, |s| {
17979            s.select_anchors(selections);
17980            if let Some(pending_selection) = pending_selection {
17981                s.set_pending(pending_selection, SelectMode::Character);
17982            } else {
17983                s.clear_pending();
17984            }
17985        });
17986        self.selections_did_change(
17987            false,
17988            &old_cursor_position,
17989            SelectionEffects::default(),
17990            window,
17991            cx,
17992        );
17993    }
17994
17995    pub fn transact(
17996        &mut self,
17997        window: &mut Window,
17998        cx: &mut Context<Self>,
17999        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
18000    ) -> Option<TransactionId> {
18001        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
18002            this.start_transaction_at(Instant::now(), window, cx);
18003            update(this, window, cx);
18004            this.end_transaction_at(Instant::now(), cx)
18005        })
18006    }
18007
18008    pub fn start_transaction_at(
18009        &mut self,
18010        now: Instant,
18011        window: &mut Window,
18012        cx: &mut Context<Self>,
18013    ) -> Option<TransactionId> {
18014        self.end_selection(window, cx);
18015        if let Some(tx_id) = self
18016            .buffer
18017            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
18018        {
18019            self.selection_history
18020                .insert_transaction(tx_id, self.selections.disjoint_anchors_arc());
18021            cx.emit(EditorEvent::TransactionBegun {
18022                transaction_id: tx_id,
18023            });
18024            Some(tx_id)
18025        } else {
18026            None
18027        }
18028    }
18029
18030    pub fn end_transaction_at(
18031        &mut self,
18032        now: Instant,
18033        cx: &mut Context<Self>,
18034    ) -> Option<TransactionId> {
18035        if let Some(transaction_id) = self
18036            .buffer
18037            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
18038        {
18039            if let Some((_, end_selections)) =
18040                self.selection_history.transaction_mut(transaction_id)
18041            {
18042                *end_selections = Some(self.selections.disjoint_anchors_arc());
18043            } else {
18044                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
18045            }
18046
18047            cx.emit(EditorEvent::Edited { transaction_id });
18048            Some(transaction_id)
18049        } else {
18050            None
18051        }
18052    }
18053
18054    pub fn modify_transaction_selection_history(
18055        &mut self,
18056        transaction_id: TransactionId,
18057        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
18058    ) -> bool {
18059        self.selection_history
18060            .transaction_mut(transaction_id)
18061            .map(modify)
18062            .is_some()
18063    }
18064
18065    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
18066        if self.selection_mark_mode {
18067            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18068                s.move_with(|_, sel| {
18069                    sel.collapse_to(sel.head(), SelectionGoal::None);
18070                });
18071            })
18072        }
18073        self.selection_mark_mode = true;
18074        cx.notify();
18075    }
18076
18077    pub fn swap_selection_ends(
18078        &mut self,
18079        _: &actions::SwapSelectionEnds,
18080        window: &mut Window,
18081        cx: &mut Context<Self>,
18082    ) {
18083        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18084            s.move_with(|_, sel| {
18085                if sel.start != sel.end {
18086                    sel.reversed = !sel.reversed
18087                }
18088            });
18089        });
18090        self.request_autoscroll(Autoscroll::newest(), cx);
18091        cx.notify();
18092    }
18093
18094    pub fn toggle_focus(
18095        workspace: &mut Workspace,
18096        _: &actions::ToggleFocus,
18097        window: &mut Window,
18098        cx: &mut Context<Workspace>,
18099    ) {
18100        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
18101            return;
18102        };
18103        workspace.activate_item(&item, true, true, window, cx);
18104    }
18105
18106    pub fn toggle_fold(
18107        &mut self,
18108        _: &actions::ToggleFold,
18109        window: &mut Window,
18110        cx: &mut Context<Self>,
18111    ) {
18112        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18113            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18114            let selection = self.selections.newest::<Point>(&display_map);
18115
18116            let range = if selection.is_empty() {
18117                let point = selection.head().to_display_point(&display_map);
18118                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
18119                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
18120                    .to_point(&display_map);
18121                start..end
18122            } else {
18123                selection.range()
18124            };
18125            if display_map.folds_in_range(range).next().is_some() {
18126                self.unfold_lines(&Default::default(), window, cx)
18127            } else {
18128                self.fold(&Default::default(), window, cx)
18129            }
18130        } else {
18131            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18132            let buffer_ids: HashSet<_> = self
18133                .selections
18134                .disjoint_anchor_ranges()
18135                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18136                .collect();
18137
18138            let should_unfold = buffer_ids
18139                .iter()
18140                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18141
18142            for buffer_id in buffer_ids {
18143                if should_unfold {
18144                    self.unfold_buffer(buffer_id, cx);
18145                } else {
18146                    self.fold_buffer(buffer_id, cx);
18147                }
18148            }
18149        }
18150    }
18151
18152    pub fn toggle_fold_recursive(
18153        &mut self,
18154        _: &actions::ToggleFoldRecursive,
18155        window: &mut Window,
18156        cx: &mut Context<Self>,
18157    ) {
18158        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
18159
18160        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18161        let range = if selection.is_empty() {
18162            let point = selection.head().to_display_point(&display_map);
18163            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
18164            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
18165                .to_point(&display_map);
18166            start..end
18167        } else {
18168            selection.range()
18169        };
18170        if display_map.folds_in_range(range).next().is_some() {
18171            self.unfold_recursive(&Default::default(), window, cx)
18172        } else {
18173            self.fold_recursive(&Default::default(), window, cx)
18174        }
18175    }
18176
18177    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
18178        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18179            let mut to_fold = Vec::new();
18180            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18181            let selections = self.selections.all_adjusted(&display_map);
18182
18183            for selection in selections {
18184                let range = selection.range().sorted();
18185                let buffer_start_row = range.start.row;
18186
18187                if range.start.row != range.end.row {
18188                    let mut found = false;
18189                    let mut row = range.start.row;
18190                    while row <= range.end.row {
18191                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18192                        {
18193                            found = true;
18194                            row = crease.range().end.row + 1;
18195                            to_fold.push(crease);
18196                        } else {
18197                            row += 1
18198                        }
18199                    }
18200                    if found {
18201                        continue;
18202                    }
18203                }
18204
18205                for row in (0..=range.start.row).rev() {
18206                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18207                        && crease.range().end.row >= buffer_start_row
18208                    {
18209                        to_fold.push(crease);
18210                        if row <= range.start.row {
18211                            break;
18212                        }
18213                    }
18214                }
18215            }
18216
18217            self.fold_creases(to_fold, true, window, cx);
18218        } else {
18219            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18220            let buffer_ids = self
18221                .selections
18222                .disjoint_anchor_ranges()
18223                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18224                .collect::<HashSet<_>>();
18225            for buffer_id in buffer_ids {
18226                self.fold_buffer(buffer_id, cx);
18227            }
18228        }
18229    }
18230
18231    pub fn toggle_fold_all(
18232        &mut self,
18233        _: &actions::ToggleFoldAll,
18234        window: &mut Window,
18235        cx: &mut Context<Self>,
18236    ) {
18237        if self.buffer.read(cx).is_singleton() {
18238            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18239            let has_folds = display_map
18240                .folds_in_range(0..display_map.buffer_snapshot().len())
18241                .next()
18242                .is_some();
18243
18244            if has_folds {
18245                self.unfold_all(&actions::UnfoldAll, window, cx);
18246            } else {
18247                self.fold_all(&actions::FoldAll, window, cx);
18248            }
18249        } else {
18250            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
18251            let should_unfold = buffer_ids
18252                .iter()
18253                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18254
18255            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18256                editor
18257                    .update_in(cx, |editor, _, cx| {
18258                        for buffer_id in buffer_ids {
18259                            if should_unfold {
18260                                editor.unfold_buffer(buffer_id, cx);
18261                            } else {
18262                                editor.fold_buffer(buffer_id, cx);
18263                            }
18264                        }
18265                    })
18266                    .ok();
18267            });
18268        }
18269    }
18270
18271    fn fold_at_level(
18272        &mut self,
18273        fold_at: &FoldAtLevel,
18274        window: &mut Window,
18275        cx: &mut Context<Self>,
18276    ) {
18277        if !self.buffer.read(cx).is_singleton() {
18278            return;
18279        }
18280
18281        let fold_at_level = fold_at.0;
18282        let snapshot = self.buffer.read(cx).snapshot(cx);
18283        let mut to_fold = Vec::new();
18284        let mut stack = vec![(0, snapshot.max_row().0, 1)];
18285
18286        let row_ranges_to_keep: Vec<Range<u32>> = self
18287            .selections
18288            .all::<Point>(&self.display_snapshot(cx))
18289            .into_iter()
18290            .map(|sel| sel.start.row..sel.end.row)
18291            .collect();
18292
18293        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
18294            while start_row < end_row {
18295                match self
18296                    .snapshot(window, cx)
18297                    .crease_for_buffer_row(MultiBufferRow(start_row))
18298                {
18299                    Some(crease) => {
18300                        let nested_start_row = crease.range().start.row + 1;
18301                        let nested_end_row = crease.range().end.row;
18302
18303                        if current_level < fold_at_level {
18304                            stack.push((nested_start_row, nested_end_row, current_level + 1));
18305                        } else if current_level == fold_at_level {
18306                            // Fold iff there is no selection completely contained within the fold region
18307                            if !row_ranges_to_keep.iter().any(|selection| {
18308                                selection.end >= nested_start_row
18309                                    && selection.start <= nested_end_row
18310                            }) {
18311                                to_fold.push(crease);
18312                            }
18313                        }
18314
18315                        start_row = nested_end_row + 1;
18316                    }
18317                    None => start_row += 1,
18318                }
18319            }
18320        }
18321
18322        self.fold_creases(to_fold, true, window, cx);
18323    }
18324
18325    pub fn fold_at_level_1(
18326        &mut self,
18327        _: &actions::FoldAtLevel1,
18328        window: &mut Window,
18329        cx: &mut Context<Self>,
18330    ) {
18331        self.fold_at_level(&actions::FoldAtLevel(1), window, cx);
18332    }
18333
18334    pub fn fold_at_level_2(
18335        &mut self,
18336        _: &actions::FoldAtLevel2,
18337        window: &mut Window,
18338        cx: &mut Context<Self>,
18339    ) {
18340        self.fold_at_level(&actions::FoldAtLevel(2), window, cx);
18341    }
18342
18343    pub fn fold_at_level_3(
18344        &mut self,
18345        _: &actions::FoldAtLevel3,
18346        window: &mut Window,
18347        cx: &mut Context<Self>,
18348    ) {
18349        self.fold_at_level(&actions::FoldAtLevel(3), window, cx);
18350    }
18351
18352    pub fn fold_at_level_4(
18353        &mut self,
18354        _: &actions::FoldAtLevel4,
18355        window: &mut Window,
18356        cx: &mut Context<Self>,
18357    ) {
18358        self.fold_at_level(&actions::FoldAtLevel(4), window, cx);
18359    }
18360
18361    pub fn fold_at_level_5(
18362        &mut self,
18363        _: &actions::FoldAtLevel5,
18364        window: &mut Window,
18365        cx: &mut Context<Self>,
18366    ) {
18367        self.fold_at_level(&actions::FoldAtLevel(5), window, cx);
18368    }
18369
18370    pub fn fold_at_level_6(
18371        &mut self,
18372        _: &actions::FoldAtLevel6,
18373        window: &mut Window,
18374        cx: &mut Context<Self>,
18375    ) {
18376        self.fold_at_level(&actions::FoldAtLevel(6), window, cx);
18377    }
18378
18379    pub fn fold_at_level_7(
18380        &mut self,
18381        _: &actions::FoldAtLevel7,
18382        window: &mut Window,
18383        cx: &mut Context<Self>,
18384    ) {
18385        self.fold_at_level(&actions::FoldAtLevel(7), window, cx);
18386    }
18387
18388    pub fn fold_at_level_8(
18389        &mut self,
18390        _: &actions::FoldAtLevel8,
18391        window: &mut Window,
18392        cx: &mut Context<Self>,
18393    ) {
18394        self.fold_at_level(&actions::FoldAtLevel(8), window, cx);
18395    }
18396
18397    pub fn fold_at_level_9(
18398        &mut self,
18399        _: &actions::FoldAtLevel9,
18400        window: &mut Window,
18401        cx: &mut Context<Self>,
18402    ) {
18403        self.fold_at_level(&actions::FoldAtLevel(9), window, cx);
18404    }
18405
18406    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
18407        if self.buffer.read(cx).is_singleton() {
18408            let mut fold_ranges = Vec::new();
18409            let snapshot = self.buffer.read(cx).snapshot(cx);
18410
18411            for row in 0..snapshot.max_row().0 {
18412                if let Some(foldable_range) = self
18413                    .snapshot(window, cx)
18414                    .crease_for_buffer_row(MultiBufferRow(row))
18415                {
18416                    fold_ranges.push(foldable_range);
18417                }
18418            }
18419
18420            self.fold_creases(fold_ranges, true, window, cx);
18421        } else {
18422            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18423                editor
18424                    .update_in(cx, |editor, _, cx| {
18425                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18426                            editor.fold_buffer(buffer_id, cx);
18427                        }
18428                    })
18429                    .ok();
18430            });
18431        }
18432    }
18433
18434    pub fn fold_function_bodies(
18435        &mut self,
18436        _: &actions::FoldFunctionBodies,
18437        window: &mut Window,
18438        cx: &mut Context<Self>,
18439    ) {
18440        let snapshot = self.buffer.read(cx).snapshot(cx);
18441
18442        let ranges = snapshot
18443            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
18444            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
18445            .collect::<Vec<_>>();
18446
18447        let creases = ranges
18448            .into_iter()
18449            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
18450            .collect();
18451
18452        self.fold_creases(creases, true, window, cx);
18453    }
18454
18455    pub fn fold_recursive(
18456        &mut self,
18457        _: &actions::FoldRecursive,
18458        window: &mut Window,
18459        cx: &mut Context<Self>,
18460    ) {
18461        let mut to_fold = Vec::new();
18462        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18463        let selections = self.selections.all_adjusted(&display_map);
18464
18465        for selection in selections {
18466            let range = selection.range().sorted();
18467            let buffer_start_row = range.start.row;
18468
18469            if range.start.row != range.end.row {
18470                let mut found = false;
18471                for row in range.start.row..=range.end.row {
18472                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18473                        found = true;
18474                        to_fold.push(crease);
18475                    }
18476                }
18477                if found {
18478                    continue;
18479                }
18480            }
18481
18482            for row in (0..=range.start.row).rev() {
18483                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18484                    if crease.range().end.row >= buffer_start_row {
18485                        to_fold.push(crease);
18486                    } else {
18487                        break;
18488                    }
18489                }
18490            }
18491        }
18492
18493        self.fold_creases(to_fold, true, window, cx);
18494    }
18495
18496    pub fn fold_at(
18497        &mut self,
18498        buffer_row: MultiBufferRow,
18499        window: &mut Window,
18500        cx: &mut Context<Self>,
18501    ) {
18502        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18503
18504        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
18505            let autoscroll = self
18506                .selections
18507                .all::<Point>(&display_map)
18508                .iter()
18509                .any(|selection| crease.range().overlaps(&selection.range()));
18510
18511            self.fold_creases(vec![crease], autoscroll, window, cx);
18512        }
18513    }
18514
18515    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
18516        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18517            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18518            let buffer = display_map.buffer_snapshot();
18519            let selections = self.selections.all::<Point>(&display_map);
18520            let ranges = selections
18521                .iter()
18522                .map(|s| {
18523                    let range = s.display_range(&display_map).sorted();
18524                    let mut start = range.start.to_point(&display_map);
18525                    let mut end = range.end.to_point(&display_map);
18526                    start.column = 0;
18527                    end.column = buffer.line_len(MultiBufferRow(end.row));
18528                    start..end
18529                })
18530                .collect::<Vec<_>>();
18531
18532            self.unfold_ranges(&ranges, true, true, cx);
18533        } else {
18534            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18535            let buffer_ids = self
18536                .selections
18537                .disjoint_anchor_ranges()
18538                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18539                .collect::<HashSet<_>>();
18540            for buffer_id in buffer_ids {
18541                self.unfold_buffer(buffer_id, cx);
18542            }
18543        }
18544    }
18545
18546    pub fn unfold_recursive(
18547        &mut self,
18548        _: &UnfoldRecursive,
18549        _window: &mut Window,
18550        cx: &mut Context<Self>,
18551    ) {
18552        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18553        let selections = self.selections.all::<Point>(&display_map);
18554        let ranges = selections
18555            .iter()
18556            .map(|s| {
18557                let mut range = s.display_range(&display_map).sorted();
18558                *range.start.column_mut() = 0;
18559                *range.end.column_mut() = display_map.line_len(range.end.row());
18560                let start = range.start.to_point(&display_map);
18561                let end = range.end.to_point(&display_map);
18562                start..end
18563            })
18564            .collect::<Vec<_>>();
18565
18566        self.unfold_ranges(&ranges, true, true, cx);
18567    }
18568
18569    pub fn unfold_at(
18570        &mut self,
18571        buffer_row: MultiBufferRow,
18572        _window: &mut Window,
18573        cx: &mut Context<Self>,
18574    ) {
18575        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18576
18577        let intersection_range = Point::new(buffer_row.0, 0)
18578            ..Point::new(
18579                buffer_row.0,
18580                display_map.buffer_snapshot().line_len(buffer_row),
18581            );
18582
18583        let autoscroll = self
18584            .selections
18585            .all::<Point>(&display_map)
18586            .iter()
18587            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
18588
18589        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
18590    }
18591
18592    pub fn unfold_all(
18593        &mut self,
18594        _: &actions::UnfoldAll,
18595        _window: &mut Window,
18596        cx: &mut Context<Self>,
18597    ) {
18598        if self.buffer.read(cx).is_singleton() {
18599            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18600            self.unfold_ranges(&[0..display_map.buffer_snapshot().len()], true, true, cx);
18601        } else {
18602            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
18603                editor
18604                    .update(cx, |editor, cx| {
18605                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18606                            editor.unfold_buffer(buffer_id, cx);
18607                        }
18608                    })
18609                    .ok();
18610            });
18611        }
18612    }
18613
18614    pub fn fold_selected_ranges(
18615        &mut self,
18616        _: &FoldSelectedRanges,
18617        window: &mut Window,
18618        cx: &mut Context<Self>,
18619    ) {
18620        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18621        let selections = self.selections.all_adjusted(&display_map);
18622        let ranges = selections
18623            .into_iter()
18624            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
18625            .collect::<Vec<_>>();
18626        self.fold_creases(ranges, true, window, cx);
18627    }
18628
18629    pub fn fold_ranges<T: ToOffset + Clone>(
18630        &mut self,
18631        ranges: Vec<Range<T>>,
18632        auto_scroll: bool,
18633        window: &mut Window,
18634        cx: &mut Context<Self>,
18635    ) {
18636        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18637        let ranges = ranges
18638            .into_iter()
18639            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
18640            .collect::<Vec<_>>();
18641        self.fold_creases(ranges, auto_scroll, window, cx);
18642    }
18643
18644    pub fn fold_creases<T: ToOffset + Clone>(
18645        &mut self,
18646        creases: Vec<Crease<T>>,
18647        auto_scroll: bool,
18648        _window: &mut Window,
18649        cx: &mut Context<Self>,
18650    ) {
18651        if creases.is_empty() {
18652            return;
18653        }
18654
18655        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
18656
18657        if auto_scroll {
18658            self.request_autoscroll(Autoscroll::fit(), cx);
18659        }
18660
18661        cx.notify();
18662
18663        self.scrollbar_marker_state.dirty = true;
18664        self.folds_did_change(cx);
18665    }
18666
18667    /// Removes any folds whose ranges intersect any of the given ranges.
18668    pub fn unfold_ranges<T: ToOffset + Clone>(
18669        &mut self,
18670        ranges: &[Range<T>],
18671        inclusive: bool,
18672        auto_scroll: bool,
18673        cx: &mut Context<Self>,
18674    ) {
18675        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18676            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
18677        });
18678        self.folds_did_change(cx);
18679    }
18680
18681    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18682        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
18683            return;
18684        }
18685        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18686        self.display_map.update(cx, |display_map, cx| {
18687            display_map.fold_buffers([buffer_id], cx)
18688        });
18689        cx.emit(EditorEvent::BufferFoldToggled {
18690            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
18691            folded: true,
18692        });
18693        cx.notify();
18694    }
18695
18696    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18697        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
18698            return;
18699        }
18700        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18701        self.display_map.update(cx, |display_map, cx| {
18702            display_map.unfold_buffers([buffer_id], cx);
18703        });
18704        cx.emit(EditorEvent::BufferFoldToggled {
18705            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
18706            folded: false,
18707        });
18708        cx.notify();
18709    }
18710
18711    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
18712        self.display_map.read(cx).is_buffer_folded(buffer)
18713    }
18714
18715    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
18716        self.display_map.read(cx).folded_buffers()
18717    }
18718
18719    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18720        self.display_map.update(cx, |display_map, cx| {
18721            display_map.disable_header_for_buffer(buffer_id, cx);
18722        });
18723        cx.notify();
18724    }
18725
18726    /// Removes any folds with the given ranges.
18727    pub fn remove_folds_with_type<T: ToOffset + Clone>(
18728        &mut self,
18729        ranges: &[Range<T>],
18730        type_id: TypeId,
18731        auto_scroll: bool,
18732        cx: &mut Context<Self>,
18733    ) {
18734        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18735            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
18736        });
18737        self.folds_did_change(cx);
18738    }
18739
18740    fn remove_folds_with<T: ToOffset + Clone>(
18741        &mut self,
18742        ranges: &[Range<T>],
18743        auto_scroll: bool,
18744        cx: &mut Context<Self>,
18745        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
18746    ) {
18747        if ranges.is_empty() {
18748            return;
18749        }
18750
18751        let mut buffers_affected = HashSet::default();
18752        let multi_buffer = self.buffer().read(cx);
18753        for range in ranges {
18754            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
18755                buffers_affected.insert(buffer.read(cx).remote_id());
18756            };
18757        }
18758
18759        self.display_map.update(cx, update);
18760
18761        if auto_scroll {
18762            self.request_autoscroll(Autoscroll::fit(), cx);
18763        }
18764
18765        cx.notify();
18766        self.scrollbar_marker_state.dirty = true;
18767        self.active_indent_guides_state.dirty = true;
18768    }
18769
18770    pub fn update_renderer_widths(
18771        &mut self,
18772        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
18773        cx: &mut Context<Self>,
18774    ) -> bool {
18775        self.display_map
18776            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
18777    }
18778
18779    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
18780        self.display_map.read(cx).fold_placeholder.clone()
18781    }
18782
18783    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
18784        self.buffer.update(cx, |buffer, cx| {
18785            buffer.set_all_diff_hunks_expanded(cx);
18786        });
18787    }
18788
18789    pub fn expand_all_diff_hunks(
18790        &mut self,
18791        _: &ExpandAllDiffHunks,
18792        _window: &mut Window,
18793        cx: &mut Context<Self>,
18794    ) {
18795        self.buffer.update(cx, |buffer, cx| {
18796            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
18797        });
18798    }
18799
18800    pub fn collapse_all_diff_hunks(
18801        &mut self,
18802        _: &CollapseAllDiffHunks,
18803        _window: &mut Window,
18804        cx: &mut Context<Self>,
18805    ) {
18806        self.buffer.update(cx, |buffer, cx| {
18807            buffer.collapse_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
18808        });
18809    }
18810
18811    pub fn toggle_selected_diff_hunks(
18812        &mut self,
18813        _: &ToggleSelectedDiffHunks,
18814        _window: &mut Window,
18815        cx: &mut Context<Self>,
18816    ) {
18817        let ranges: Vec<_> = self
18818            .selections
18819            .disjoint_anchors()
18820            .iter()
18821            .map(|s| s.range())
18822            .collect();
18823        self.toggle_diff_hunks_in_ranges(ranges, cx);
18824    }
18825
18826    pub fn diff_hunks_in_ranges<'a>(
18827        &'a self,
18828        ranges: &'a [Range<Anchor>],
18829        buffer: &'a MultiBufferSnapshot,
18830    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
18831        ranges.iter().flat_map(move |range| {
18832            let end_excerpt_id = range.end.excerpt_id;
18833            let range = range.to_point(buffer);
18834            let mut peek_end = range.end;
18835            if range.end.row < buffer.max_row().0 {
18836                peek_end = Point::new(range.end.row + 1, 0);
18837            }
18838            buffer
18839                .diff_hunks_in_range(range.start..peek_end)
18840                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
18841        })
18842    }
18843
18844    pub fn has_stageable_diff_hunks_in_ranges(
18845        &self,
18846        ranges: &[Range<Anchor>],
18847        snapshot: &MultiBufferSnapshot,
18848    ) -> bool {
18849        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
18850        hunks.any(|hunk| hunk.status().has_secondary_hunk())
18851    }
18852
18853    pub fn toggle_staged_selected_diff_hunks(
18854        &mut self,
18855        _: &::git::ToggleStaged,
18856        _: &mut Window,
18857        cx: &mut Context<Self>,
18858    ) {
18859        let snapshot = self.buffer.read(cx).snapshot(cx);
18860        let ranges: Vec<_> = self
18861            .selections
18862            .disjoint_anchors()
18863            .iter()
18864            .map(|s| s.range())
18865            .collect();
18866        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
18867        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18868    }
18869
18870    pub fn set_render_diff_hunk_controls(
18871        &mut self,
18872        render_diff_hunk_controls: RenderDiffHunkControlsFn,
18873        cx: &mut Context<Self>,
18874    ) {
18875        self.render_diff_hunk_controls = render_diff_hunk_controls;
18876        cx.notify();
18877    }
18878
18879    pub fn stage_and_next(
18880        &mut self,
18881        _: &::git::StageAndNext,
18882        window: &mut Window,
18883        cx: &mut Context<Self>,
18884    ) {
18885        self.do_stage_or_unstage_and_next(true, window, cx);
18886    }
18887
18888    pub fn unstage_and_next(
18889        &mut self,
18890        _: &::git::UnstageAndNext,
18891        window: &mut Window,
18892        cx: &mut Context<Self>,
18893    ) {
18894        self.do_stage_or_unstage_and_next(false, window, cx);
18895    }
18896
18897    pub fn stage_or_unstage_diff_hunks(
18898        &mut self,
18899        stage: bool,
18900        ranges: Vec<Range<Anchor>>,
18901        cx: &mut Context<Self>,
18902    ) {
18903        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
18904        cx.spawn(async move |this, cx| {
18905            task.await?;
18906            this.update(cx, |this, cx| {
18907                let snapshot = this.buffer.read(cx).snapshot(cx);
18908                let chunk_by = this
18909                    .diff_hunks_in_ranges(&ranges, &snapshot)
18910                    .chunk_by(|hunk| hunk.buffer_id);
18911                for (buffer_id, hunks) in &chunk_by {
18912                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
18913                }
18914            })
18915        })
18916        .detach_and_log_err(cx);
18917    }
18918
18919    fn save_buffers_for_ranges_if_needed(
18920        &mut self,
18921        ranges: &[Range<Anchor>],
18922        cx: &mut Context<Editor>,
18923    ) -> Task<Result<()>> {
18924        let multibuffer = self.buffer.read(cx);
18925        let snapshot = multibuffer.read(cx);
18926        let buffer_ids: HashSet<_> = ranges
18927            .iter()
18928            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
18929            .collect();
18930        drop(snapshot);
18931
18932        let mut buffers = HashSet::default();
18933        for buffer_id in buffer_ids {
18934            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
18935                let buffer = buffer_entity.read(cx);
18936                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
18937                {
18938                    buffers.insert(buffer_entity);
18939                }
18940            }
18941        }
18942
18943        if let Some(project) = &self.project {
18944            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
18945        } else {
18946            Task::ready(Ok(()))
18947        }
18948    }
18949
18950    fn do_stage_or_unstage_and_next(
18951        &mut self,
18952        stage: bool,
18953        window: &mut Window,
18954        cx: &mut Context<Self>,
18955    ) {
18956        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
18957
18958        if ranges.iter().any(|range| range.start != range.end) {
18959            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18960            return;
18961        }
18962
18963        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18964        let snapshot = self.snapshot(window, cx);
18965        let position = self
18966            .selections
18967            .newest::<Point>(&snapshot.display_snapshot)
18968            .head();
18969        let mut row = snapshot
18970            .buffer_snapshot()
18971            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
18972            .find(|hunk| hunk.row_range.start.0 > position.row)
18973            .map(|hunk| hunk.row_range.start);
18974
18975        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
18976        // Outside of the project diff editor, wrap around to the beginning.
18977        if !all_diff_hunks_expanded {
18978            row = row.or_else(|| {
18979                snapshot
18980                    .buffer_snapshot()
18981                    .diff_hunks_in_range(Point::zero()..position)
18982                    .find(|hunk| hunk.row_range.end.0 < position.row)
18983                    .map(|hunk| hunk.row_range.start)
18984            });
18985        }
18986
18987        if let Some(row) = row {
18988            let destination = Point::new(row.0, 0);
18989            let autoscroll = Autoscroll::center();
18990
18991            self.unfold_ranges(&[destination..destination], false, false, cx);
18992            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
18993                s.select_ranges([destination..destination]);
18994            });
18995        }
18996    }
18997
18998    fn do_stage_or_unstage(
18999        &self,
19000        stage: bool,
19001        buffer_id: BufferId,
19002        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
19003        cx: &mut App,
19004    ) -> Option<()> {
19005        let project = self.project()?;
19006        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
19007        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
19008        let buffer_snapshot = buffer.read(cx).snapshot();
19009        let file_exists = buffer_snapshot
19010            .file()
19011            .is_some_and(|file| file.disk_state().exists());
19012        diff.update(cx, |diff, cx| {
19013            diff.stage_or_unstage_hunks(
19014                stage,
19015                &hunks
19016                    .map(|hunk| buffer_diff::DiffHunk {
19017                        buffer_range: hunk.buffer_range,
19018                        diff_base_byte_range: hunk.diff_base_byte_range,
19019                        secondary_status: hunk.secondary_status,
19020                        range: Point::zero()..Point::zero(), // unused
19021                    })
19022                    .collect::<Vec<_>>(),
19023                &buffer_snapshot,
19024                file_exists,
19025                cx,
19026            )
19027        });
19028        None
19029    }
19030
19031    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
19032        let ranges: Vec<_> = self
19033            .selections
19034            .disjoint_anchors()
19035            .iter()
19036            .map(|s| s.range())
19037            .collect();
19038        self.buffer
19039            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
19040    }
19041
19042    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
19043        self.buffer.update(cx, |buffer, cx| {
19044            let ranges = vec![Anchor::min()..Anchor::max()];
19045            if !buffer.all_diff_hunks_expanded()
19046                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
19047            {
19048                buffer.collapse_diff_hunks(ranges, cx);
19049                true
19050            } else {
19051                false
19052            }
19053        })
19054    }
19055
19056    fn toggle_diff_hunks_in_ranges(
19057        &mut self,
19058        ranges: Vec<Range<Anchor>>,
19059        cx: &mut Context<Editor>,
19060    ) {
19061        self.buffer.update(cx, |buffer, cx| {
19062            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
19063            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
19064        })
19065    }
19066
19067    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
19068        self.buffer.update(cx, |buffer, cx| {
19069            let snapshot = buffer.snapshot(cx);
19070            let excerpt_id = range.end.excerpt_id;
19071            let point_range = range.to_point(&snapshot);
19072            let expand = !buffer.single_hunk_is_expanded(range, cx);
19073            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
19074        })
19075    }
19076
19077    pub(crate) fn apply_all_diff_hunks(
19078        &mut self,
19079        _: &ApplyAllDiffHunks,
19080        window: &mut Window,
19081        cx: &mut Context<Self>,
19082    ) {
19083        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19084
19085        let buffers = self.buffer.read(cx).all_buffers();
19086        for branch_buffer in buffers {
19087            branch_buffer.update(cx, |branch_buffer, cx| {
19088                branch_buffer.merge_into_base(Vec::new(), cx);
19089            });
19090        }
19091
19092        if let Some(project) = self.project.clone() {
19093            self.save(
19094                SaveOptions {
19095                    format: true,
19096                    autosave: false,
19097                },
19098                project,
19099                window,
19100                cx,
19101            )
19102            .detach_and_log_err(cx);
19103        }
19104    }
19105
19106    pub(crate) fn apply_selected_diff_hunks(
19107        &mut self,
19108        _: &ApplyDiffHunk,
19109        window: &mut Window,
19110        cx: &mut Context<Self>,
19111    ) {
19112        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19113        let snapshot = self.snapshot(window, cx);
19114        let hunks = snapshot.hunks_for_ranges(
19115            self.selections
19116                .all(&snapshot.display_snapshot)
19117                .into_iter()
19118                .map(|selection| selection.range()),
19119        );
19120        let mut ranges_by_buffer = HashMap::default();
19121        self.transact(window, cx, |editor, _window, cx| {
19122            for hunk in hunks {
19123                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
19124                    ranges_by_buffer
19125                        .entry(buffer.clone())
19126                        .or_insert_with(Vec::new)
19127                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
19128                }
19129            }
19130
19131            for (buffer, ranges) in ranges_by_buffer {
19132                buffer.update(cx, |buffer, cx| {
19133                    buffer.merge_into_base(ranges, cx);
19134                });
19135            }
19136        });
19137
19138        if let Some(project) = self.project.clone() {
19139            self.save(
19140                SaveOptions {
19141                    format: true,
19142                    autosave: false,
19143                },
19144                project,
19145                window,
19146                cx,
19147            )
19148            .detach_and_log_err(cx);
19149        }
19150    }
19151
19152    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
19153        if hovered != self.gutter_hovered {
19154            self.gutter_hovered = hovered;
19155            cx.notify();
19156        }
19157    }
19158
19159    pub fn insert_blocks(
19160        &mut self,
19161        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
19162        autoscroll: Option<Autoscroll>,
19163        cx: &mut Context<Self>,
19164    ) -> Vec<CustomBlockId> {
19165        let blocks = self
19166            .display_map
19167            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
19168        if let Some(autoscroll) = autoscroll {
19169            self.request_autoscroll(autoscroll, cx);
19170        }
19171        cx.notify();
19172        blocks
19173    }
19174
19175    pub fn resize_blocks(
19176        &mut self,
19177        heights: HashMap<CustomBlockId, u32>,
19178        autoscroll: Option<Autoscroll>,
19179        cx: &mut Context<Self>,
19180    ) {
19181        self.display_map
19182            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
19183        if let Some(autoscroll) = autoscroll {
19184            self.request_autoscroll(autoscroll, cx);
19185        }
19186        cx.notify();
19187    }
19188
19189    pub fn replace_blocks(
19190        &mut self,
19191        renderers: HashMap<CustomBlockId, RenderBlock>,
19192        autoscroll: Option<Autoscroll>,
19193        cx: &mut Context<Self>,
19194    ) {
19195        self.display_map
19196            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
19197        if let Some(autoscroll) = autoscroll {
19198            self.request_autoscroll(autoscroll, cx);
19199        }
19200        cx.notify();
19201    }
19202
19203    pub fn remove_blocks(
19204        &mut self,
19205        block_ids: HashSet<CustomBlockId>,
19206        autoscroll: Option<Autoscroll>,
19207        cx: &mut Context<Self>,
19208    ) {
19209        self.display_map.update(cx, |display_map, cx| {
19210            display_map.remove_blocks(block_ids, cx)
19211        });
19212        if let Some(autoscroll) = autoscroll {
19213            self.request_autoscroll(autoscroll, cx);
19214        }
19215        cx.notify();
19216    }
19217
19218    pub fn row_for_block(
19219        &self,
19220        block_id: CustomBlockId,
19221        cx: &mut Context<Self>,
19222    ) -> Option<DisplayRow> {
19223        self.display_map
19224            .update(cx, |map, cx| map.row_for_block(block_id, cx))
19225    }
19226
19227    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
19228        self.focused_block = Some(focused_block);
19229    }
19230
19231    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
19232        self.focused_block.take()
19233    }
19234
19235    pub fn insert_creases(
19236        &mut self,
19237        creases: impl IntoIterator<Item = Crease<Anchor>>,
19238        cx: &mut Context<Self>,
19239    ) -> Vec<CreaseId> {
19240        self.display_map
19241            .update(cx, |map, cx| map.insert_creases(creases, cx))
19242    }
19243
19244    pub fn remove_creases(
19245        &mut self,
19246        ids: impl IntoIterator<Item = CreaseId>,
19247        cx: &mut Context<Self>,
19248    ) -> Vec<(CreaseId, Range<Anchor>)> {
19249        self.display_map
19250            .update(cx, |map, cx| map.remove_creases(ids, cx))
19251    }
19252
19253    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
19254        self.display_map
19255            .update(cx, |map, cx| map.snapshot(cx))
19256            .longest_row()
19257    }
19258
19259    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
19260        self.display_map
19261            .update(cx, |map, cx| map.snapshot(cx))
19262            .max_point()
19263    }
19264
19265    pub fn text(&self, cx: &App) -> String {
19266        self.buffer.read(cx).read(cx).text()
19267    }
19268
19269    pub fn is_empty(&self, cx: &App) -> bool {
19270        self.buffer.read(cx).read(cx).is_empty()
19271    }
19272
19273    pub fn text_option(&self, cx: &App) -> Option<String> {
19274        let text = self.text(cx);
19275        let text = text.trim();
19276
19277        if text.is_empty() {
19278            return None;
19279        }
19280
19281        Some(text.to_string())
19282    }
19283
19284    pub fn set_text(
19285        &mut self,
19286        text: impl Into<Arc<str>>,
19287        window: &mut Window,
19288        cx: &mut Context<Self>,
19289    ) {
19290        self.transact(window, cx, |this, _, cx| {
19291            this.buffer
19292                .read(cx)
19293                .as_singleton()
19294                .expect("you can only call set_text on editors for singleton buffers")
19295                .update(cx, |buffer, cx| buffer.set_text(text, cx));
19296        });
19297    }
19298
19299    pub fn display_text(&self, cx: &mut App) -> String {
19300        self.display_map
19301            .update(cx, |map, cx| map.snapshot(cx))
19302            .text()
19303    }
19304
19305    fn create_minimap(
19306        &self,
19307        minimap_settings: MinimapSettings,
19308        window: &mut Window,
19309        cx: &mut Context<Self>,
19310    ) -> Option<Entity<Self>> {
19311        (minimap_settings.minimap_enabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton)
19312            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
19313    }
19314
19315    fn initialize_new_minimap(
19316        &self,
19317        minimap_settings: MinimapSettings,
19318        window: &mut Window,
19319        cx: &mut Context<Self>,
19320    ) -> Entity<Self> {
19321        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
19322
19323        let mut minimap = Editor::new_internal(
19324            EditorMode::Minimap {
19325                parent: cx.weak_entity(),
19326            },
19327            self.buffer.clone(),
19328            None,
19329            Some(self.display_map.clone()),
19330            window,
19331            cx,
19332        );
19333        minimap.scroll_manager.clone_state(&self.scroll_manager);
19334        minimap.set_text_style_refinement(TextStyleRefinement {
19335            font_size: Some(MINIMAP_FONT_SIZE),
19336            font_weight: Some(MINIMAP_FONT_WEIGHT),
19337            ..Default::default()
19338        });
19339        minimap.update_minimap_configuration(minimap_settings, cx);
19340        cx.new(|_| minimap)
19341    }
19342
19343    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
19344        let current_line_highlight = minimap_settings
19345            .current_line_highlight
19346            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
19347        self.set_current_line_highlight(Some(current_line_highlight));
19348    }
19349
19350    pub fn minimap(&self) -> Option<&Entity<Self>> {
19351        self.minimap
19352            .as_ref()
19353            .filter(|_| self.minimap_visibility.visible())
19354    }
19355
19356    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
19357        let mut wrap_guides = smallvec![];
19358
19359        if self.show_wrap_guides == Some(false) {
19360            return wrap_guides;
19361        }
19362
19363        let settings = self.buffer.read(cx).language_settings(cx);
19364        if settings.show_wrap_guides {
19365            match self.soft_wrap_mode(cx) {
19366                SoftWrap::Column(soft_wrap) => {
19367                    wrap_guides.push((soft_wrap as usize, true));
19368                }
19369                SoftWrap::Bounded(soft_wrap) => {
19370                    wrap_guides.push((soft_wrap as usize, true));
19371                }
19372                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
19373            }
19374            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
19375        }
19376
19377        wrap_guides
19378    }
19379
19380    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
19381        let settings = self.buffer.read(cx).language_settings(cx);
19382        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
19383        match mode {
19384            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
19385                SoftWrap::None
19386            }
19387            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
19388            language_settings::SoftWrap::PreferredLineLength => {
19389                SoftWrap::Column(settings.preferred_line_length)
19390            }
19391            language_settings::SoftWrap::Bounded => {
19392                SoftWrap::Bounded(settings.preferred_line_length)
19393            }
19394        }
19395    }
19396
19397    pub fn set_soft_wrap_mode(
19398        &mut self,
19399        mode: language_settings::SoftWrap,
19400
19401        cx: &mut Context<Self>,
19402    ) {
19403        self.soft_wrap_mode_override = Some(mode);
19404        cx.notify();
19405    }
19406
19407    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
19408        self.hard_wrap = hard_wrap;
19409        cx.notify();
19410    }
19411
19412    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
19413        self.text_style_refinement = Some(style);
19414    }
19415
19416    /// called by the Element so we know what style we were most recently rendered with.
19417    pub fn set_style(&mut self, style: EditorStyle, window: &mut Window, cx: &mut Context<Self>) {
19418        // We intentionally do not inform the display map about the minimap style
19419        // so that wrapping is not recalculated and stays consistent for the editor
19420        // and its linked minimap.
19421        if !self.mode.is_minimap() {
19422            let font = style.text.font();
19423            let font_size = style.text.font_size.to_pixels(window.rem_size());
19424            let display_map = self
19425                .placeholder_display_map
19426                .as_ref()
19427                .filter(|_| self.is_empty(cx))
19428                .unwrap_or(&self.display_map);
19429
19430            display_map.update(cx, |map, cx| map.set_font(font, font_size, cx));
19431        }
19432        self.style = Some(style);
19433    }
19434
19435    pub fn style(&self) -> Option<&EditorStyle> {
19436        self.style.as_ref()
19437    }
19438
19439    // Called by the element. This method is not designed to be called outside of the editor
19440    // element's layout code because it does not notify when rewrapping is computed synchronously.
19441    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
19442        if self.is_empty(cx) {
19443            self.placeholder_display_map
19444                .as_ref()
19445                .map_or(false, |display_map| {
19446                    display_map.update(cx, |map, cx| map.set_wrap_width(width, cx))
19447                })
19448        } else {
19449            self.display_map
19450                .update(cx, |map, cx| map.set_wrap_width(width, cx))
19451        }
19452    }
19453
19454    pub fn set_soft_wrap(&mut self) {
19455        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
19456    }
19457
19458    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
19459        if self.soft_wrap_mode_override.is_some() {
19460            self.soft_wrap_mode_override.take();
19461        } else {
19462            let soft_wrap = match self.soft_wrap_mode(cx) {
19463                SoftWrap::GitDiff => return,
19464                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
19465                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
19466                    language_settings::SoftWrap::None
19467                }
19468            };
19469            self.soft_wrap_mode_override = Some(soft_wrap);
19470        }
19471        cx.notify();
19472    }
19473
19474    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
19475        let Some(workspace) = self.workspace() else {
19476            return;
19477        };
19478        let fs = workspace.read(cx).app_state().fs.clone();
19479        let current_show = TabBarSettings::get_global(cx).show;
19480        update_settings_file(fs, cx, move |setting, _| {
19481            setting.tab_bar.get_or_insert_default().show = Some(!current_show);
19482        });
19483    }
19484
19485    pub fn toggle_indent_guides(
19486        &mut self,
19487        _: &ToggleIndentGuides,
19488        _: &mut Window,
19489        cx: &mut Context<Self>,
19490    ) {
19491        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
19492            self.buffer
19493                .read(cx)
19494                .language_settings(cx)
19495                .indent_guides
19496                .enabled
19497        });
19498        self.show_indent_guides = Some(!currently_enabled);
19499        cx.notify();
19500    }
19501
19502    fn should_show_indent_guides(&self) -> Option<bool> {
19503        self.show_indent_guides
19504    }
19505
19506    pub fn toggle_line_numbers(
19507        &mut self,
19508        _: &ToggleLineNumbers,
19509        _: &mut Window,
19510        cx: &mut Context<Self>,
19511    ) {
19512        let mut editor_settings = EditorSettings::get_global(cx).clone();
19513        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
19514        EditorSettings::override_global(editor_settings, cx);
19515    }
19516
19517    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
19518        if let Some(show_line_numbers) = self.show_line_numbers {
19519            return show_line_numbers;
19520        }
19521        EditorSettings::get_global(cx).gutter.line_numbers
19522    }
19523
19524    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
19525        self.use_relative_line_numbers
19526            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
19527    }
19528
19529    pub fn toggle_relative_line_numbers(
19530        &mut self,
19531        _: &ToggleRelativeLineNumbers,
19532        _: &mut Window,
19533        cx: &mut Context<Self>,
19534    ) {
19535        let is_relative = self.should_use_relative_line_numbers(cx);
19536        self.set_relative_line_number(Some(!is_relative), cx)
19537    }
19538
19539    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
19540        self.use_relative_line_numbers = is_relative;
19541        cx.notify();
19542    }
19543
19544    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
19545        self.show_gutter = show_gutter;
19546        cx.notify();
19547    }
19548
19549    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
19550        self.show_scrollbars = ScrollbarAxes {
19551            horizontal: show,
19552            vertical: show,
19553        };
19554        cx.notify();
19555    }
19556
19557    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19558        self.show_scrollbars.vertical = show;
19559        cx.notify();
19560    }
19561
19562    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19563        self.show_scrollbars.horizontal = show;
19564        cx.notify();
19565    }
19566
19567    pub fn set_minimap_visibility(
19568        &mut self,
19569        minimap_visibility: MinimapVisibility,
19570        window: &mut Window,
19571        cx: &mut Context<Self>,
19572    ) {
19573        if self.minimap_visibility != minimap_visibility {
19574            if minimap_visibility.visible() && self.minimap.is_none() {
19575                let minimap_settings = EditorSettings::get_global(cx).minimap;
19576                self.minimap =
19577                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
19578            }
19579            self.minimap_visibility = minimap_visibility;
19580            cx.notify();
19581        }
19582    }
19583
19584    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19585        self.set_show_scrollbars(false, cx);
19586        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
19587    }
19588
19589    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19590        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
19591    }
19592
19593    /// Normally the text in full mode and auto height editors is padded on the
19594    /// left side by roughly half a character width for improved hit testing.
19595    ///
19596    /// Use this method to disable this for cases where this is not wanted (e.g.
19597    /// if you want to align the editor text with some other text above or below)
19598    /// or if you want to add this padding to single-line editors.
19599    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
19600        self.offset_content = offset_content;
19601        cx.notify();
19602    }
19603
19604    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
19605        self.show_line_numbers = Some(show_line_numbers);
19606        cx.notify();
19607    }
19608
19609    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
19610        self.disable_expand_excerpt_buttons = true;
19611        cx.notify();
19612    }
19613
19614    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
19615        self.show_git_diff_gutter = Some(show_git_diff_gutter);
19616        cx.notify();
19617    }
19618
19619    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
19620        self.show_code_actions = Some(show_code_actions);
19621        cx.notify();
19622    }
19623
19624    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
19625        self.show_runnables = Some(show_runnables);
19626        cx.notify();
19627    }
19628
19629    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
19630        self.show_breakpoints = Some(show_breakpoints);
19631        cx.notify();
19632    }
19633
19634    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
19635        if self.display_map.read(cx).masked != masked {
19636            self.display_map.update(cx, |map, _| map.masked = masked);
19637        }
19638        cx.notify()
19639    }
19640
19641    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
19642        self.show_wrap_guides = Some(show_wrap_guides);
19643        cx.notify();
19644    }
19645
19646    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
19647        self.show_indent_guides = Some(show_indent_guides);
19648        cx.notify();
19649    }
19650
19651    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
19652        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
19653            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
19654                && let Some(dir) = file.abs_path(cx).parent()
19655            {
19656                return Some(dir.to_owned());
19657            }
19658        }
19659
19660        None
19661    }
19662
19663    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
19664        self.active_excerpt(cx)?
19665            .1
19666            .read(cx)
19667            .file()
19668            .and_then(|f| f.as_local())
19669    }
19670
19671    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
19672        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19673            let buffer = buffer.read(cx);
19674            if let Some(project_path) = buffer.project_path(cx) {
19675                let project = self.project()?.read(cx);
19676                project.absolute_path(&project_path, cx)
19677            } else {
19678                buffer
19679                    .file()
19680                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
19681            }
19682        })
19683    }
19684
19685    pub fn reveal_in_finder(
19686        &mut self,
19687        _: &RevealInFileManager,
19688        _window: &mut Window,
19689        cx: &mut Context<Self>,
19690    ) {
19691        if let Some(target) = self.target_file(cx) {
19692            cx.reveal_path(&target.abs_path(cx));
19693        }
19694    }
19695
19696    pub fn copy_path(
19697        &mut self,
19698        _: &zed_actions::workspace::CopyPath,
19699        _window: &mut Window,
19700        cx: &mut Context<Self>,
19701    ) {
19702        if let Some(path) = self.target_file_abs_path(cx)
19703            && let Some(path) = path.to_str()
19704        {
19705            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19706        } else {
19707            cx.propagate();
19708        }
19709    }
19710
19711    pub fn copy_relative_path(
19712        &mut self,
19713        _: &zed_actions::workspace::CopyRelativePath,
19714        _window: &mut Window,
19715        cx: &mut Context<Self>,
19716    ) {
19717        if let Some(path) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19718            let project = self.project()?.read(cx);
19719            let path = buffer.read(cx).file()?.path();
19720            let path = path.display(project.path_style(cx));
19721            Some(path)
19722        }) {
19723            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19724        } else {
19725            cx.propagate();
19726        }
19727    }
19728
19729    /// Returns the project path for the editor's buffer, if any buffer is
19730    /// opened in the editor.
19731    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
19732        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
19733            buffer.read(cx).project_path(cx)
19734        } else {
19735            None
19736        }
19737    }
19738
19739    // Returns true if the editor handled a go-to-line request
19740    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
19741        maybe!({
19742            let breakpoint_store = self.breakpoint_store.as_ref()?;
19743
19744            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
19745            else {
19746                self.clear_row_highlights::<ActiveDebugLine>();
19747                return None;
19748            };
19749
19750            let position = active_stack_frame.position;
19751            let buffer_id = position.buffer_id?;
19752            let snapshot = self
19753                .project
19754                .as_ref()?
19755                .read(cx)
19756                .buffer_for_id(buffer_id, cx)?
19757                .read(cx)
19758                .snapshot();
19759
19760            let mut handled = false;
19761            for (id, ExcerptRange { context, .. }) in
19762                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
19763            {
19764                if context.start.cmp(&position, &snapshot).is_ge()
19765                    || context.end.cmp(&position, &snapshot).is_lt()
19766                {
19767                    continue;
19768                }
19769                let snapshot = self.buffer.read(cx).snapshot(cx);
19770                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
19771
19772                handled = true;
19773                self.clear_row_highlights::<ActiveDebugLine>();
19774
19775                self.go_to_line::<ActiveDebugLine>(
19776                    multibuffer_anchor,
19777                    Some(cx.theme().colors().editor_debugger_active_line_background),
19778                    window,
19779                    cx,
19780                );
19781
19782                cx.notify();
19783            }
19784
19785            handled.then_some(())
19786        })
19787        .is_some()
19788    }
19789
19790    pub fn copy_file_name_without_extension(
19791        &mut self,
19792        _: &CopyFileNameWithoutExtension,
19793        _: &mut Window,
19794        cx: &mut Context<Self>,
19795    ) {
19796        if let Some(file) = self.target_file(cx)
19797            && let Some(file_stem) = file.path().file_stem()
19798        {
19799            cx.write_to_clipboard(ClipboardItem::new_string(file_stem.to_string()));
19800        }
19801    }
19802
19803    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
19804        if let Some(file) = self.target_file(cx)
19805            && let Some(name) = file.path().file_name()
19806        {
19807            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
19808        }
19809    }
19810
19811    pub fn toggle_git_blame(
19812        &mut self,
19813        _: &::git::Blame,
19814        window: &mut Window,
19815        cx: &mut Context<Self>,
19816    ) {
19817        self.show_git_blame_gutter = !self.show_git_blame_gutter;
19818
19819        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
19820            self.start_git_blame(true, window, cx);
19821        }
19822
19823        cx.notify();
19824    }
19825
19826    pub fn toggle_git_blame_inline(
19827        &mut self,
19828        _: &ToggleGitBlameInline,
19829        window: &mut Window,
19830        cx: &mut Context<Self>,
19831    ) {
19832        self.toggle_git_blame_inline_internal(true, window, cx);
19833        cx.notify();
19834    }
19835
19836    pub fn open_git_blame_commit(
19837        &mut self,
19838        _: &OpenGitBlameCommit,
19839        window: &mut Window,
19840        cx: &mut Context<Self>,
19841    ) {
19842        self.open_git_blame_commit_internal(window, cx);
19843    }
19844
19845    fn open_git_blame_commit_internal(
19846        &mut self,
19847        window: &mut Window,
19848        cx: &mut Context<Self>,
19849    ) -> Option<()> {
19850        let blame = self.blame.as_ref()?;
19851        let snapshot = self.snapshot(window, cx);
19852        let cursor = self
19853            .selections
19854            .newest::<Point>(&snapshot.display_snapshot)
19855            .head();
19856        let (buffer, point, _) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)?;
19857        let (_, blame_entry) = blame
19858            .update(cx, |blame, cx| {
19859                blame
19860                    .blame_for_rows(
19861                        &[RowInfo {
19862                            buffer_id: Some(buffer.remote_id()),
19863                            buffer_row: Some(point.row),
19864                            ..Default::default()
19865                        }],
19866                        cx,
19867                    )
19868                    .next()
19869            })
19870            .flatten()?;
19871        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
19872        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
19873        let workspace = self.workspace()?.downgrade();
19874        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
19875        None
19876    }
19877
19878    pub fn git_blame_inline_enabled(&self) -> bool {
19879        self.git_blame_inline_enabled
19880    }
19881
19882    pub fn toggle_selection_menu(
19883        &mut self,
19884        _: &ToggleSelectionMenu,
19885        _: &mut Window,
19886        cx: &mut Context<Self>,
19887    ) {
19888        self.show_selection_menu = self
19889            .show_selection_menu
19890            .map(|show_selections_menu| !show_selections_menu)
19891            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
19892
19893        cx.notify();
19894    }
19895
19896    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
19897        self.show_selection_menu
19898            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
19899    }
19900
19901    fn start_git_blame(
19902        &mut self,
19903        user_triggered: bool,
19904        window: &mut Window,
19905        cx: &mut Context<Self>,
19906    ) {
19907        if let Some(project) = self.project() {
19908            if let Some(buffer) = self.buffer().read(cx).as_singleton()
19909                && buffer.read(cx).file().is_none()
19910            {
19911                return;
19912            }
19913
19914            let focused = self.focus_handle(cx).contains_focused(window, cx);
19915
19916            let project = project.clone();
19917            let blame = cx
19918                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
19919            self.blame_subscription =
19920                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
19921            self.blame = Some(blame);
19922        }
19923    }
19924
19925    fn toggle_git_blame_inline_internal(
19926        &mut self,
19927        user_triggered: bool,
19928        window: &mut Window,
19929        cx: &mut Context<Self>,
19930    ) {
19931        if self.git_blame_inline_enabled {
19932            self.git_blame_inline_enabled = false;
19933            self.show_git_blame_inline = false;
19934            self.show_git_blame_inline_delay_task.take();
19935        } else {
19936            self.git_blame_inline_enabled = true;
19937            self.start_git_blame_inline(user_triggered, window, cx);
19938        }
19939
19940        cx.notify();
19941    }
19942
19943    fn start_git_blame_inline(
19944        &mut self,
19945        user_triggered: bool,
19946        window: &mut Window,
19947        cx: &mut Context<Self>,
19948    ) {
19949        self.start_git_blame(user_triggered, window, cx);
19950
19951        if ProjectSettings::get_global(cx)
19952            .git
19953            .inline_blame_delay()
19954            .is_some()
19955        {
19956            self.start_inline_blame_timer(window, cx);
19957        } else {
19958            self.show_git_blame_inline = true
19959        }
19960    }
19961
19962    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
19963        self.blame.as_ref()
19964    }
19965
19966    pub fn show_git_blame_gutter(&self) -> bool {
19967        self.show_git_blame_gutter
19968    }
19969
19970    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
19971        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
19972    }
19973
19974    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
19975        self.show_git_blame_inline
19976            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
19977            && !self.newest_selection_head_on_empty_line(cx)
19978            && self.has_blame_entries(cx)
19979    }
19980
19981    fn has_blame_entries(&self, cx: &App) -> bool {
19982        self.blame()
19983            .is_some_and(|blame| blame.read(cx).has_generated_entries())
19984    }
19985
19986    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
19987        let cursor_anchor = self.selections.newest_anchor().head();
19988
19989        let snapshot = self.buffer.read(cx).snapshot(cx);
19990        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
19991
19992        snapshot.line_len(buffer_row) == 0
19993    }
19994
19995    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
19996        let buffer_and_selection = maybe!({
19997            let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
19998            let selection_range = selection.range();
19999
20000            let multi_buffer = self.buffer().read(cx);
20001            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
20002            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
20003
20004            let (buffer, range, _) = if selection.reversed {
20005                buffer_ranges.first()
20006            } else {
20007                buffer_ranges.last()
20008            }?;
20009
20010            let selection = text::ToPoint::to_point(&range.start, buffer).row
20011                ..text::ToPoint::to_point(&range.end, buffer).row;
20012            Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection))
20013        });
20014
20015        let Some((buffer, selection)) = buffer_and_selection else {
20016            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
20017        };
20018
20019        let Some(project) = self.project() else {
20020            return Task::ready(Err(anyhow!("editor does not have project")));
20021        };
20022
20023        project.update(cx, |project, cx| {
20024            project.get_permalink_to_line(&buffer, selection, cx)
20025        })
20026    }
20027
20028    pub fn copy_permalink_to_line(
20029        &mut self,
20030        _: &CopyPermalinkToLine,
20031        window: &mut Window,
20032        cx: &mut Context<Self>,
20033    ) {
20034        let permalink_task = self.get_permalink_to_line(cx);
20035        let workspace = self.workspace();
20036
20037        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
20038            Ok(permalink) => {
20039                cx.update(|_, cx| {
20040                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
20041                })
20042                .ok();
20043            }
20044            Err(err) => {
20045                let message = format!("Failed to copy permalink: {err}");
20046
20047                anyhow::Result::<()>::Err(err).log_err();
20048
20049                if let Some(workspace) = workspace {
20050                    workspace
20051                        .update_in(cx, |workspace, _, cx| {
20052                            struct CopyPermalinkToLine;
20053
20054                            workspace.show_toast(
20055                                Toast::new(
20056                                    NotificationId::unique::<CopyPermalinkToLine>(),
20057                                    message,
20058                                ),
20059                                cx,
20060                            )
20061                        })
20062                        .ok();
20063                }
20064            }
20065        })
20066        .detach();
20067    }
20068
20069    pub fn copy_file_location(
20070        &mut self,
20071        _: &CopyFileLocation,
20072        _: &mut Window,
20073        cx: &mut Context<Self>,
20074    ) {
20075        let selection = self
20076            .selections
20077            .newest::<Point>(&self.display_snapshot(cx))
20078            .start
20079            .row
20080            + 1;
20081        if let Some(file) = self.target_file(cx) {
20082            let path = file.path().display(file.path_style(cx));
20083            cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
20084        }
20085    }
20086
20087    pub fn open_permalink_to_line(
20088        &mut self,
20089        _: &OpenPermalinkToLine,
20090        window: &mut Window,
20091        cx: &mut Context<Self>,
20092    ) {
20093        let permalink_task = self.get_permalink_to_line(cx);
20094        let workspace = self.workspace();
20095
20096        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
20097            Ok(permalink) => {
20098                cx.update(|_, cx| {
20099                    cx.open_url(permalink.as_ref());
20100                })
20101                .ok();
20102            }
20103            Err(err) => {
20104                let message = format!("Failed to open permalink: {err}");
20105
20106                anyhow::Result::<()>::Err(err).log_err();
20107
20108                if let Some(workspace) = workspace {
20109                    workspace
20110                        .update(cx, |workspace, cx| {
20111                            struct OpenPermalinkToLine;
20112
20113                            workspace.show_toast(
20114                                Toast::new(
20115                                    NotificationId::unique::<OpenPermalinkToLine>(),
20116                                    message,
20117                                ),
20118                                cx,
20119                            )
20120                        })
20121                        .ok();
20122                }
20123            }
20124        })
20125        .detach();
20126    }
20127
20128    pub fn insert_uuid_v4(
20129        &mut self,
20130        _: &InsertUuidV4,
20131        window: &mut Window,
20132        cx: &mut Context<Self>,
20133    ) {
20134        self.insert_uuid(UuidVersion::V4, window, cx);
20135    }
20136
20137    pub fn insert_uuid_v7(
20138        &mut self,
20139        _: &InsertUuidV7,
20140        window: &mut Window,
20141        cx: &mut Context<Self>,
20142    ) {
20143        self.insert_uuid(UuidVersion::V7, window, cx);
20144    }
20145
20146    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
20147        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
20148        self.transact(window, cx, |this, window, cx| {
20149            let edits = this
20150                .selections
20151                .all::<Point>(&this.display_snapshot(cx))
20152                .into_iter()
20153                .map(|selection| {
20154                    let uuid = match version {
20155                        UuidVersion::V4 => uuid::Uuid::new_v4(),
20156                        UuidVersion::V7 => uuid::Uuid::now_v7(),
20157                    };
20158
20159                    (selection.range(), uuid.to_string())
20160                });
20161            this.edit(edits, cx);
20162            this.refresh_edit_prediction(true, false, window, cx);
20163        });
20164    }
20165
20166    pub fn open_selections_in_multibuffer(
20167        &mut self,
20168        _: &OpenSelectionsInMultibuffer,
20169        window: &mut Window,
20170        cx: &mut Context<Self>,
20171    ) {
20172        let multibuffer = self.buffer.read(cx);
20173
20174        let Some(buffer) = multibuffer.as_singleton() else {
20175            return;
20176        };
20177
20178        let Some(workspace) = self.workspace() else {
20179            return;
20180        };
20181
20182        let title = multibuffer.title(cx).to_string();
20183
20184        let locations = self
20185            .selections
20186            .all_anchors(cx)
20187            .iter()
20188            .map(|selection| {
20189                (
20190                    buffer.clone(),
20191                    (selection.start.text_anchor..selection.end.text_anchor)
20192                        .to_point(buffer.read(cx)),
20193                )
20194            })
20195            .into_group_map();
20196
20197        cx.spawn_in(window, async move |_, cx| {
20198            workspace.update_in(cx, |workspace, window, cx| {
20199                Self::open_locations_in_multibuffer(
20200                    workspace,
20201                    locations,
20202                    format!("Selections for '{title}'"),
20203                    false,
20204                    MultibufferSelectionMode::All,
20205                    window,
20206                    cx,
20207                );
20208            })
20209        })
20210        .detach();
20211    }
20212
20213    /// Adds a row highlight for the given range. If a row has multiple highlights, the
20214    /// last highlight added will be used.
20215    ///
20216    /// If the range ends at the beginning of a line, then that line will not be highlighted.
20217    pub fn highlight_rows<T: 'static>(
20218        &mut self,
20219        range: Range<Anchor>,
20220        color: Hsla,
20221        options: RowHighlightOptions,
20222        cx: &mut Context<Self>,
20223    ) {
20224        let snapshot = self.buffer().read(cx).snapshot(cx);
20225        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20226        let ix = row_highlights.binary_search_by(|highlight| {
20227            Ordering::Equal
20228                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
20229                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
20230        });
20231
20232        if let Err(mut ix) = ix {
20233            let index = post_inc(&mut self.highlight_order);
20234
20235            // If this range intersects with the preceding highlight, then merge it with
20236            // the preceding highlight. Otherwise insert a new highlight.
20237            let mut merged = false;
20238            if ix > 0 {
20239                let prev_highlight = &mut row_highlights[ix - 1];
20240                if prev_highlight
20241                    .range
20242                    .end
20243                    .cmp(&range.start, &snapshot)
20244                    .is_ge()
20245                {
20246                    ix -= 1;
20247                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
20248                        prev_highlight.range.end = range.end;
20249                    }
20250                    merged = true;
20251                    prev_highlight.index = index;
20252                    prev_highlight.color = color;
20253                    prev_highlight.options = options;
20254                }
20255            }
20256
20257            if !merged {
20258                row_highlights.insert(
20259                    ix,
20260                    RowHighlight {
20261                        range,
20262                        index,
20263                        color,
20264                        options,
20265                        type_id: TypeId::of::<T>(),
20266                    },
20267                );
20268            }
20269
20270            // If any of the following highlights intersect with this one, merge them.
20271            while let Some(next_highlight) = row_highlights.get(ix + 1) {
20272                let highlight = &row_highlights[ix];
20273                if next_highlight
20274                    .range
20275                    .start
20276                    .cmp(&highlight.range.end, &snapshot)
20277                    .is_le()
20278                {
20279                    if next_highlight
20280                        .range
20281                        .end
20282                        .cmp(&highlight.range.end, &snapshot)
20283                        .is_gt()
20284                    {
20285                        row_highlights[ix].range.end = next_highlight.range.end;
20286                    }
20287                    row_highlights.remove(ix + 1);
20288                } else {
20289                    break;
20290                }
20291            }
20292        }
20293    }
20294
20295    /// Remove any highlighted row ranges of the given type that intersect the
20296    /// given ranges.
20297    pub fn remove_highlighted_rows<T: 'static>(
20298        &mut self,
20299        ranges_to_remove: Vec<Range<Anchor>>,
20300        cx: &mut Context<Self>,
20301    ) {
20302        let snapshot = self.buffer().read(cx).snapshot(cx);
20303        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20304        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20305        row_highlights.retain(|highlight| {
20306            while let Some(range_to_remove) = ranges_to_remove.peek() {
20307                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
20308                    Ordering::Less | Ordering::Equal => {
20309                        ranges_to_remove.next();
20310                    }
20311                    Ordering::Greater => {
20312                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
20313                            Ordering::Less | Ordering::Equal => {
20314                                return false;
20315                            }
20316                            Ordering::Greater => break,
20317                        }
20318                    }
20319                }
20320            }
20321
20322            true
20323        })
20324    }
20325
20326    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
20327    pub fn clear_row_highlights<T: 'static>(&mut self) {
20328        self.highlighted_rows.remove(&TypeId::of::<T>());
20329    }
20330
20331    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
20332    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
20333        self.highlighted_rows
20334            .get(&TypeId::of::<T>())
20335            .map_or(&[] as &[_], |vec| vec.as_slice())
20336            .iter()
20337            .map(|highlight| (highlight.range.clone(), highlight.color))
20338    }
20339
20340    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
20341    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
20342    /// Allows to ignore certain kinds of highlights.
20343    pub fn highlighted_display_rows(
20344        &self,
20345        window: &mut Window,
20346        cx: &mut App,
20347    ) -> BTreeMap<DisplayRow, LineHighlight> {
20348        let snapshot = self.snapshot(window, cx);
20349        let mut used_highlight_orders = HashMap::default();
20350        self.highlighted_rows
20351            .iter()
20352            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
20353            .fold(
20354                BTreeMap::<DisplayRow, LineHighlight>::new(),
20355                |mut unique_rows, highlight| {
20356                    let start = highlight.range.start.to_display_point(&snapshot);
20357                    let end = highlight.range.end.to_display_point(&snapshot);
20358                    let start_row = start.row().0;
20359                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
20360                        && end.column() == 0
20361                    {
20362                        end.row().0.saturating_sub(1)
20363                    } else {
20364                        end.row().0
20365                    };
20366                    for row in start_row..=end_row {
20367                        let used_index =
20368                            used_highlight_orders.entry(row).or_insert(highlight.index);
20369                        if highlight.index >= *used_index {
20370                            *used_index = highlight.index;
20371                            unique_rows.insert(
20372                                DisplayRow(row),
20373                                LineHighlight {
20374                                    include_gutter: highlight.options.include_gutter,
20375                                    border: None,
20376                                    background: highlight.color.into(),
20377                                    type_id: Some(highlight.type_id),
20378                                },
20379                            );
20380                        }
20381                    }
20382                    unique_rows
20383                },
20384            )
20385    }
20386
20387    pub fn highlighted_display_row_for_autoscroll(
20388        &self,
20389        snapshot: &DisplaySnapshot,
20390    ) -> Option<DisplayRow> {
20391        self.highlighted_rows
20392            .values()
20393            .flat_map(|highlighted_rows| highlighted_rows.iter())
20394            .filter_map(|highlight| {
20395                if highlight.options.autoscroll {
20396                    Some(highlight.range.start.to_display_point(snapshot).row())
20397                } else {
20398                    None
20399                }
20400            })
20401            .min()
20402    }
20403
20404    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
20405        self.highlight_background::<SearchWithinRange>(
20406            ranges,
20407            |colors| colors.colors().editor_document_highlight_read_background,
20408            cx,
20409        )
20410    }
20411
20412    pub fn set_breadcrumb_header(&mut self, new_header: String) {
20413        self.breadcrumb_header = Some(new_header);
20414    }
20415
20416    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
20417        self.clear_background_highlights::<SearchWithinRange>(cx);
20418    }
20419
20420    pub fn highlight_background<T: 'static>(
20421        &mut self,
20422        ranges: &[Range<Anchor>],
20423        color_fetcher: fn(&Theme) -> Hsla,
20424        cx: &mut Context<Self>,
20425    ) {
20426        self.background_highlights.insert(
20427            HighlightKey::Type(TypeId::of::<T>()),
20428            (color_fetcher, Arc::from(ranges)),
20429        );
20430        self.scrollbar_marker_state.dirty = true;
20431        cx.notify();
20432    }
20433
20434    pub fn highlight_background_key<T: 'static>(
20435        &mut self,
20436        key: usize,
20437        ranges: &[Range<Anchor>],
20438        color_fetcher: fn(&Theme) -> Hsla,
20439        cx: &mut Context<Self>,
20440    ) {
20441        self.background_highlights.insert(
20442            HighlightKey::TypePlus(TypeId::of::<T>(), key),
20443            (color_fetcher, Arc::from(ranges)),
20444        );
20445        self.scrollbar_marker_state.dirty = true;
20446        cx.notify();
20447    }
20448
20449    pub fn clear_background_highlights<T: 'static>(
20450        &mut self,
20451        cx: &mut Context<Self>,
20452    ) -> Option<BackgroundHighlight> {
20453        let text_highlights = self
20454            .background_highlights
20455            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
20456        if !text_highlights.1.is_empty() {
20457            self.scrollbar_marker_state.dirty = true;
20458            cx.notify();
20459        }
20460        Some(text_highlights)
20461    }
20462
20463    pub fn highlight_gutter<T: 'static>(
20464        &mut self,
20465        ranges: impl Into<Vec<Range<Anchor>>>,
20466        color_fetcher: fn(&App) -> Hsla,
20467        cx: &mut Context<Self>,
20468    ) {
20469        self.gutter_highlights
20470            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
20471        cx.notify();
20472    }
20473
20474    pub fn clear_gutter_highlights<T: 'static>(
20475        &mut self,
20476        cx: &mut Context<Self>,
20477    ) -> Option<GutterHighlight> {
20478        cx.notify();
20479        self.gutter_highlights.remove(&TypeId::of::<T>())
20480    }
20481
20482    pub fn insert_gutter_highlight<T: 'static>(
20483        &mut self,
20484        range: Range<Anchor>,
20485        color_fetcher: fn(&App) -> Hsla,
20486        cx: &mut Context<Self>,
20487    ) {
20488        let snapshot = self.buffer().read(cx).snapshot(cx);
20489        let mut highlights = self
20490            .gutter_highlights
20491            .remove(&TypeId::of::<T>())
20492            .map(|(_, highlights)| highlights)
20493            .unwrap_or_default();
20494        let ix = highlights.binary_search_by(|highlight| {
20495            Ordering::Equal
20496                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
20497                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
20498        });
20499        if let Err(ix) = ix {
20500            highlights.insert(ix, range);
20501        }
20502        self.gutter_highlights
20503            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
20504    }
20505
20506    pub fn remove_gutter_highlights<T: 'static>(
20507        &mut self,
20508        ranges_to_remove: Vec<Range<Anchor>>,
20509        cx: &mut Context<Self>,
20510    ) {
20511        let snapshot = self.buffer().read(cx).snapshot(cx);
20512        let Some((color_fetcher, mut gutter_highlights)) =
20513            self.gutter_highlights.remove(&TypeId::of::<T>())
20514        else {
20515            return;
20516        };
20517        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20518        gutter_highlights.retain(|highlight| {
20519            while let Some(range_to_remove) = ranges_to_remove.peek() {
20520                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
20521                    Ordering::Less | Ordering::Equal => {
20522                        ranges_to_remove.next();
20523                    }
20524                    Ordering::Greater => {
20525                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
20526                            Ordering::Less | Ordering::Equal => {
20527                                return false;
20528                            }
20529                            Ordering::Greater => break,
20530                        }
20531                    }
20532                }
20533            }
20534
20535            true
20536        });
20537        self.gutter_highlights
20538            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
20539    }
20540
20541    #[cfg(feature = "test-support")]
20542    pub fn all_text_highlights(
20543        &self,
20544        window: &mut Window,
20545        cx: &mut Context<Self>,
20546    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
20547        let snapshot = self.snapshot(window, cx);
20548        self.display_map.update(cx, |display_map, _| {
20549            display_map
20550                .all_text_highlights()
20551                .map(|highlight| {
20552                    let (style, ranges) = highlight.as_ref();
20553                    (
20554                        *style,
20555                        ranges
20556                            .iter()
20557                            .map(|range| range.clone().to_display_points(&snapshot))
20558                            .collect(),
20559                    )
20560                })
20561                .collect()
20562        })
20563    }
20564
20565    #[cfg(feature = "test-support")]
20566    pub fn all_text_background_highlights(
20567        &self,
20568        window: &mut Window,
20569        cx: &mut Context<Self>,
20570    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20571        let snapshot = self.snapshot(window, cx);
20572        let buffer = &snapshot.buffer_snapshot();
20573        let start = buffer.anchor_before(0);
20574        let end = buffer.anchor_after(buffer.len());
20575        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
20576    }
20577
20578    #[cfg(any(test, feature = "test-support"))]
20579    pub fn sorted_background_highlights_in_range(
20580        &self,
20581        search_range: Range<Anchor>,
20582        display_snapshot: &DisplaySnapshot,
20583        theme: &Theme,
20584    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20585        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
20586        res.sort_by(|a, b| {
20587            a.0.start
20588                .cmp(&b.0.start)
20589                .then_with(|| a.0.end.cmp(&b.0.end))
20590                .then_with(|| a.1.cmp(&b.1))
20591        });
20592        res
20593    }
20594
20595    #[cfg(feature = "test-support")]
20596    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
20597        let snapshot = self.buffer().read(cx).snapshot(cx);
20598
20599        let highlights = self
20600            .background_highlights
20601            .get(&HighlightKey::Type(TypeId::of::<
20602                items::BufferSearchHighlights,
20603            >()));
20604
20605        if let Some((_color, ranges)) = highlights {
20606            ranges
20607                .iter()
20608                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
20609                .collect_vec()
20610        } else {
20611            vec![]
20612        }
20613    }
20614
20615    fn document_highlights_for_position<'a>(
20616        &'a self,
20617        position: Anchor,
20618        buffer: &'a MultiBufferSnapshot,
20619    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
20620        let read_highlights = self
20621            .background_highlights
20622            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
20623            .map(|h| &h.1);
20624        let write_highlights = self
20625            .background_highlights
20626            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
20627            .map(|h| &h.1);
20628        let left_position = position.bias_left(buffer);
20629        let right_position = position.bias_right(buffer);
20630        read_highlights
20631            .into_iter()
20632            .chain(write_highlights)
20633            .flat_map(move |ranges| {
20634                let start_ix = match ranges.binary_search_by(|probe| {
20635                    let cmp = probe.end.cmp(&left_position, buffer);
20636                    if cmp.is_ge() {
20637                        Ordering::Greater
20638                    } else {
20639                        Ordering::Less
20640                    }
20641                }) {
20642                    Ok(i) | Err(i) => i,
20643                };
20644
20645                ranges[start_ix..]
20646                    .iter()
20647                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
20648            })
20649    }
20650
20651    pub fn has_background_highlights<T: 'static>(&self) -> bool {
20652        self.background_highlights
20653            .get(&HighlightKey::Type(TypeId::of::<T>()))
20654            .is_some_and(|(_, highlights)| !highlights.is_empty())
20655    }
20656
20657    /// Returns all background highlights for a given range.
20658    ///
20659    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
20660    pub fn background_highlights_in_range(
20661        &self,
20662        search_range: Range<Anchor>,
20663        display_snapshot: &DisplaySnapshot,
20664        theme: &Theme,
20665    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20666        let mut results = Vec::new();
20667        for (color_fetcher, ranges) in self.background_highlights.values() {
20668            let color = color_fetcher(theme);
20669            let start_ix = match ranges.binary_search_by(|probe| {
20670                let cmp = probe
20671                    .end
20672                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
20673                if cmp.is_gt() {
20674                    Ordering::Greater
20675                } else {
20676                    Ordering::Less
20677                }
20678            }) {
20679                Ok(i) | Err(i) => i,
20680            };
20681            for range in &ranges[start_ix..] {
20682                if range
20683                    .start
20684                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
20685                    .is_ge()
20686                {
20687                    break;
20688                }
20689
20690                let start = range.start.to_display_point(display_snapshot);
20691                let end = range.end.to_display_point(display_snapshot);
20692                results.push((start..end, color))
20693            }
20694        }
20695        results
20696    }
20697
20698    pub fn gutter_highlights_in_range(
20699        &self,
20700        search_range: Range<Anchor>,
20701        display_snapshot: &DisplaySnapshot,
20702        cx: &App,
20703    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20704        let mut results = Vec::new();
20705        for (color_fetcher, ranges) in self.gutter_highlights.values() {
20706            let color = color_fetcher(cx);
20707            let start_ix = match ranges.binary_search_by(|probe| {
20708                let cmp = probe
20709                    .end
20710                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
20711                if cmp.is_gt() {
20712                    Ordering::Greater
20713                } else {
20714                    Ordering::Less
20715                }
20716            }) {
20717                Ok(i) | Err(i) => i,
20718            };
20719            for range in &ranges[start_ix..] {
20720                if range
20721                    .start
20722                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
20723                    .is_ge()
20724                {
20725                    break;
20726                }
20727
20728                let start = range.start.to_display_point(display_snapshot);
20729                let end = range.end.to_display_point(display_snapshot);
20730                results.push((start..end, color))
20731            }
20732        }
20733        results
20734    }
20735
20736    /// Get the text ranges corresponding to the redaction query
20737    pub fn redacted_ranges(
20738        &self,
20739        search_range: Range<Anchor>,
20740        display_snapshot: &DisplaySnapshot,
20741        cx: &App,
20742    ) -> Vec<Range<DisplayPoint>> {
20743        display_snapshot
20744            .buffer_snapshot()
20745            .redacted_ranges(search_range, |file| {
20746                if let Some(file) = file {
20747                    file.is_private()
20748                        && EditorSettings::get(
20749                            Some(SettingsLocation {
20750                                worktree_id: file.worktree_id(cx),
20751                                path: file.path().as_ref(),
20752                            }),
20753                            cx,
20754                        )
20755                        .redact_private_values
20756                } else {
20757                    false
20758                }
20759            })
20760            .map(|range| {
20761                range.start.to_display_point(display_snapshot)
20762                    ..range.end.to_display_point(display_snapshot)
20763            })
20764            .collect()
20765    }
20766
20767    pub fn highlight_text_key<T: 'static>(
20768        &mut self,
20769        key: usize,
20770        ranges: Vec<Range<Anchor>>,
20771        style: HighlightStyle,
20772        cx: &mut Context<Self>,
20773    ) {
20774        self.display_map.update(cx, |map, _| {
20775            map.highlight_text(
20776                HighlightKey::TypePlus(TypeId::of::<T>(), key),
20777                ranges,
20778                style,
20779            );
20780        });
20781        cx.notify();
20782    }
20783
20784    pub fn highlight_text<T: 'static>(
20785        &mut self,
20786        ranges: Vec<Range<Anchor>>,
20787        style: HighlightStyle,
20788        cx: &mut Context<Self>,
20789    ) {
20790        self.display_map.update(cx, |map, _| {
20791            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
20792        });
20793        cx.notify();
20794    }
20795
20796    pub fn text_highlights<'a, T: 'static>(
20797        &'a self,
20798        cx: &'a App,
20799    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
20800        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
20801    }
20802
20803    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
20804        let cleared = self
20805            .display_map
20806            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
20807        if cleared {
20808            cx.notify();
20809        }
20810    }
20811
20812    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
20813        (self.read_only(cx) || self.blink_manager.read(cx).visible())
20814            && self.focus_handle.is_focused(window)
20815    }
20816
20817    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
20818        self.show_cursor_when_unfocused = is_enabled;
20819        cx.notify();
20820    }
20821
20822    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
20823        cx.notify();
20824    }
20825
20826    fn on_debug_session_event(
20827        &mut self,
20828        _session: Entity<Session>,
20829        event: &SessionEvent,
20830        cx: &mut Context<Self>,
20831    ) {
20832        if let SessionEvent::InvalidateInlineValue = event {
20833            self.refresh_inline_values(cx);
20834        }
20835    }
20836
20837    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
20838        let Some(project) = self.project.clone() else {
20839            return;
20840        };
20841
20842        if !self.inline_value_cache.enabled {
20843            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
20844            self.splice_inlays(&inlays, Vec::new(), cx);
20845            return;
20846        }
20847
20848        let current_execution_position = self
20849            .highlighted_rows
20850            .get(&TypeId::of::<ActiveDebugLine>())
20851            .and_then(|lines| lines.last().map(|line| line.range.end));
20852
20853        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
20854            let inline_values = editor
20855                .update(cx, |editor, cx| {
20856                    let Some(current_execution_position) = current_execution_position else {
20857                        return Some(Task::ready(Ok(Vec::new())));
20858                    };
20859
20860                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
20861                        let snapshot = buffer.snapshot(cx);
20862
20863                        let excerpt = snapshot.excerpt_containing(
20864                            current_execution_position..current_execution_position,
20865                        )?;
20866
20867                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
20868                    })?;
20869
20870                    let range =
20871                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
20872
20873                    project.inline_values(buffer, range, cx)
20874                })
20875                .ok()
20876                .flatten()?
20877                .await
20878                .context("refreshing debugger inlays")
20879                .log_err()?;
20880
20881            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
20882
20883            for (buffer_id, inline_value) in inline_values
20884                .into_iter()
20885                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
20886            {
20887                buffer_inline_values
20888                    .entry(buffer_id)
20889                    .or_default()
20890                    .push(inline_value);
20891            }
20892
20893            editor
20894                .update(cx, |editor, cx| {
20895                    let snapshot = editor.buffer.read(cx).snapshot(cx);
20896                    let mut new_inlays = Vec::default();
20897
20898                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
20899                        let buffer_id = buffer_snapshot.remote_id();
20900                        buffer_inline_values
20901                            .get(&buffer_id)
20902                            .into_iter()
20903                            .flatten()
20904                            .for_each(|hint| {
20905                                let inlay = Inlay::debugger(
20906                                    post_inc(&mut editor.next_inlay_id),
20907                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
20908                                    hint.text(),
20909                                );
20910                                if !inlay.text().chars().contains(&'\n') {
20911                                    new_inlays.push(inlay);
20912                                }
20913                            });
20914                    }
20915
20916                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
20917                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
20918
20919                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
20920                })
20921                .ok()?;
20922            Some(())
20923        });
20924    }
20925
20926    fn on_buffer_event(
20927        &mut self,
20928        multibuffer: &Entity<MultiBuffer>,
20929        event: &multi_buffer::Event,
20930        window: &mut Window,
20931        cx: &mut Context<Self>,
20932    ) {
20933        match event {
20934            multi_buffer::Event::Edited { edited_buffer } => {
20935                self.scrollbar_marker_state.dirty = true;
20936                self.active_indent_guides_state.dirty = true;
20937                self.refresh_active_diagnostics(cx);
20938                self.refresh_code_actions(window, cx);
20939                self.refresh_selected_text_highlights(true, window, cx);
20940                self.refresh_single_line_folds(window, cx);
20941                self.refresh_matching_bracket_highlights(window, cx);
20942                if self.has_active_edit_prediction() {
20943                    self.update_visible_edit_prediction(window, cx);
20944                }
20945
20946                if let Some(buffer) = edited_buffer {
20947                    if buffer.read(cx).file().is_none() {
20948                        cx.emit(EditorEvent::TitleChanged);
20949                    }
20950
20951                    if self.project.is_some() {
20952                        let buffer_id = buffer.read(cx).remote_id();
20953                        self.register_buffer(buffer_id, cx);
20954                        self.update_lsp_data(Some(buffer_id), window, cx);
20955                        self.refresh_inlay_hints(
20956                            InlayHintRefreshReason::BufferEdited(buffer_id),
20957                            cx,
20958                        );
20959                    }
20960                }
20961
20962                cx.emit(EditorEvent::BufferEdited);
20963                cx.emit(SearchEvent::MatchesInvalidated);
20964
20965                let Some(project) = &self.project else { return };
20966                let (telemetry, is_via_ssh) = {
20967                    let project = project.read(cx);
20968                    let telemetry = project.client().telemetry().clone();
20969                    let is_via_ssh = project.is_via_remote_server();
20970                    (telemetry, is_via_ssh)
20971                };
20972                telemetry.log_edit_event("editor", is_via_ssh);
20973            }
20974            multi_buffer::Event::ExcerptsAdded {
20975                buffer,
20976                predecessor,
20977                excerpts,
20978            } => {
20979                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20980                let buffer_id = buffer.read(cx).remote_id();
20981                if self.buffer.read(cx).diff_for(buffer_id).is_none()
20982                    && let Some(project) = &self.project
20983                {
20984                    update_uncommitted_diff_for_buffer(
20985                        cx.entity(),
20986                        project,
20987                        [buffer.clone()],
20988                        self.buffer.clone(),
20989                        cx,
20990                    )
20991                    .detach();
20992                }
20993                self.update_lsp_data(Some(buffer_id), window, cx);
20994                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20995                cx.emit(EditorEvent::ExcerptsAdded {
20996                    buffer: buffer.clone(),
20997                    predecessor: *predecessor,
20998                    excerpts: excerpts.clone(),
20999                });
21000            }
21001            multi_buffer::Event::ExcerptsRemoved {
21002                ids,
21003                removed_buffer_ids,
21004            } => {
21005                if let Some(inlay_hints) = &mut self.inlay_hints {
21006                    inlay_hints.remove_inlay_chunk_data(removed_buffer_ids);
21007                }
21008                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
21009                for buffer_id in removed_buffer_ids {
21010                    self.registered_buffers.remove(buffer_id);
21011                }
21012                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21013                cx.emit(EditorEvent::ExcerptsRemoved {
21014                    ids: ids.clone(),
21015                    removed_buffer_ids: removed_buffer_ids.clone(),
21016                });
21017            }
21018            multi_buffer::Event::ExcerptsEdited {
21019                excerpt_ids,
21020                buffer_ids,
21021            } => {
21022                self.display_map.update(cx, |map, cx| {
21023                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
21024                });
21025                cx.emit(EditorEvent::ExcerptsEdited {
21026                    ids: excerpt_ids.clone(),
21027                });
21028            }
21029            multi_buffer::Event::ExcerptsExpanded { ids } => {
21030                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
21031                self.refresh_document_highlights(cx);
21032                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
21033            }
21034            multi_buffer::Event::Reparsed(buffer_id) => {
21035                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21036                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21037
21038                cx.emit(EditorEvent::Reparsed(*buffer_id));
21039            }
21040            multi_buffer::Event::DiffHunksToggled => {
21041                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21042            }
21043            multi_buffer::Event::LanguageChanged(buffer_id) => {
21044                self.registered_buffers.remove(&buffer_id);
21045                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21046                cx.emit(EditorEvent::Reparsed(*buffer_id));
21047                cx.notify();
21048            }
21049            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
21050            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
21051            multi_buffer::Event::FileHandleChanged
21052            | multi_buffer::Event::Reloaded
21053            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
21054            multi_buffer::Event::DiagnosticsUpdated => {
21055                self.update_diagnostics_state(window, cx);
21056            }
21057            _ => {}
21058        };
21059    }
21060
21061    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
21062        if !self.diagnostics_enabled() {
21063            return;
21064        }
21065        self.refresh_active_diagnostics(cx);
21066        self.refresh_inline_diagnostics(true, window, cx);
21067        self.scrollbar_marker_state.dirty = true;
21068        cx.notify();
21069    }
21070
21071    pub fn start_temporary_diff_override(&mut self) {
21072        self.load_diff_task.take();
21073        self.temporary_diff_override = true;
21074    }
21075
21076    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
21077        self.temporary_diff_override = false;
21078        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
21079        self.buffer.update(cx, |buffer, cx| {
21080            buffer.set_all_diff_hunks_collapsed(cx);
21081        });
21082
21083        if let Some(project) = self.project.clone() {
21084            self.load_diff_task = Some(
21085                update_uncommitted_diff_for_buffer(
21086                    cx.entity(),
21087                    &project,
21088                    self.buffer.read(cx).all_buffers(),
21089                    self.buffer.clone(),
21090                    cx,
21091                )
21092                .shared(),
21093            );
21094        }
21095    }
21096
21097    fn on_display_map_changed(
21098        &mut self,
21099        _: Entity<DisplayMap>,
21100        _: &mut Window,
21101        cx: &mut Context<Self>,
21102    ) {
21103        cx.notify();
21104    }
21105
21106    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21107        if self.diagnostics_enabled() {
21108            let new_severity = EditorSettings::get_global(cx)
21109                .diagnostics_max_severity
21110                .unwrap_or(DiagnosticSeverity::Hint);
21111            self.set_max_diagnostics_severity(new_severity, cx);
21112        }
21113        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21114        self.update_edit_prediction_settings(cx);
21115        self.refresh_edit_prediction(true, false, window, cx);
21116        self.refresh_inline_values(cx);
21117        self.refresh_inlay_hints(
21118            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
21119                self.selections.newest_anchor().head(),
21120                &self.buffer.read(cx).snapshot(cx),
21121                cx,
21122            )),
21123            cx,
21124        );
21125
21126        let old_cursor_shape = self.cursor_shape;
21127        let old_show_breadcrumbs = self.show_breadcrumbs;
21128
21129        {
21130            let editor_settings = EditorSettings::get_global(cx);
21131            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
21132            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
21133            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
21134            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
21135        }
21136
21137        if old_cursor_shape != self.cursor_shape {
21138            cx.emit(EditorEvent::CursorShapeChanged);
21139        }
21140
21141        if old_show_breadcrumbs != self.show_breadcrumbs {
21142            cx.emit(EditorEvent::BreadcrumbsChanged);
21143        }
21144
21145        let project_settings = ProjectSettings::get_global(cx);
21146        self.serialize_dirty_buffers =
21147            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
21148
21149        if self.mode.is_full() {
21150            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
21151            let inline_blame_enabled = project_settings.git.inline_blame.enabled;
21152            if self.show_inline_diagnostics != show_inline_diagnostics {
21153                self.show_inline_diagnostics = show_inline_diagnostics;
21154                self.refresh_inline_diagnostics(false, window, cx);
21155            }
21156
21157            if self.git_blame_inline_enabled != inline_blame_enabled {
21158                self.toggle_git_blame_inline_internal(false, window, cx);
21159            }
21160
21161            let minimap_settings = EditorSettings::get_global(cx).minimap;
21162            if self.minimap_visibility != MinimapVisibility::Disabled {
21163                if self.minimap_visibility.settings_visibility()
21164                    != minimap_settings.minimap_enabled()
21165                {
21166                    self.set_minimap_visibility(
21167                        MinimapVisibility::for_mode(self.mode(), cx),
21168                        window,
21169                        cx,
21170                    );
21171                } else if let Some(minimap_entity) = self.minimap.as_ref() {
21172                    minimap_entity.update(cx, |minimap_editor, cx| {
21173                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
21174                    })
21175                }
21176            }
21177        }
21178
21179        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
21180            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
21181        }) {
21182            if !inlay_splice.is_empty() {
21183                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
21184            }
21185            self.refresh_colors_for_visible_range(None, window, cx);
21186        }
21187
21188        cx.notify();
21189    }
21190
21191    pub fn set_searchable(&mut self, searchable: bool) {
21192        self.searchable = searchable;
21193    }
21194
21195    pub fn searchable(&self) -> bool {
21196        self.searchable
21197    }
21198
21199    pub fn open_excerpts_in_split(
21200        &mut self,
21201        _: &OpenExcerptsSplit,
21202        window: &mut Window,
21203        cx: &mut Context<Self>,
21204    ) {
21205        self.open_excerpts_common(None, true, window, cx)
21206    }
21207
21208    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
21209        self.open_excerpts_common(None, false, window, cx)
21210    }
21211
21212    fn open_excerpts_common(
21213        &mut self,
21214        jump_data: Option<JumpData>,
21215        split: bool,
21216        window: &mut Window,
21217        cx: &mut Context<Self>,
21218    ) {
21219        let Some(workspace) = self.workspace() else {
21220            cx.propagate();
21221            return;
21222        };
21223
21224        if self.buffer.read(cx).is_singleton() {
21225            cx.propagate();
21226            return;
21227        }
21228
21229        let mut new_selections_by_buffer = HashMap::default();
21230        match &jump_data {
21231            Some(JumpData::MultiBufferPoint {
21232                excerpt_id,
21233                position,
21234                anchor,
21235                line_offset_from_top,
21236            }) => {
21237                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
21238                if let Some(buffer) = multi_buffer_snapshot
21239                    .buffer_id_for_excerpt(*excerpt_id)
21240                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
21241                {
21242                    let buffer_snapshot = buffer.read(cx).snapshot();
21243                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
21244                        language::ToPoint::to_point(anchor, &buffer_snapshot)
21245                    } else {
21246                        buffer_snapshot.clip_point(*position, Bias::Left)
21247                    };
21248                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
21249                    new_selections_by_buffer.insert(
21250                        buffer,
21251                        (
21252                            vec![jump_to_offset..jump_to_offset],
21253                            Some(*line_offset_from_top),
21254                        ),
21255                    );
21256                }
21257            }
21258            Some(JumpData::MultiBufferRow {
21259                row,
21260                line_offset_from_top,
21261            }) => {
21262                let point = MultiBufferPoint::new(row.0, 0);
21263                if let Some((buffer, buffer_point, _)) =
21264                    self.buffer.read(cx).point_to_buffer_point(point, cx)
21265                {
21266                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
21267                    new_selections_by_buffer
21268                        .entry(buffer)
21269                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
21270                        .0
21271                        .push(buffer_offset..buffer_offset)
21272                }
21273            }
21274            None => {
21275                let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
21276                let multi_buffer = self.buffer.read(cx);
21277                for selection in selections {
21278                    for (snapshot, range, _, anchor) in multi_buffer
21279                        .snapshot(cx)
21280                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
21281                    {
21282                        if let Some(anchor) = anchor {
21283                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
21284                            else {
21285                                continue;
21286                            };
21287                            let offset = text::ToOffset::to_offset(
21288                                &anchor.text_anchor,
21289                                &buffer_handle.read(cx).snapshot(),
21290                            );
21291                            let range = offset..offset;
21292                            new_selections_by_buffer
21293                                .entry(buffer_handle)
21294                                .or_insert((Vec::new(), None))
21295                                .0
21296                                .push(range)
21297                        } else {
21298                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
21299                            else {
21300                                continue;
21301                            };
21302                            new_selections_by_buffer
21303                                .entry(buffer_handle)
21304                                .or_insert((Vec::new(), None))
21305                                .0
21306                                .push(range)
21307                        }
21308                    }
21309                }
21310            }
21311        }
21312
21313        new_selections_by_buffer
21314            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
21315
21316        if new_selections_by_buffer.is_empty() {
21317            return;
21318        }
21319
21320        // We defer the pane interaction because we ourselves are a workspace item
21321        // and activating a new item causes the pane to call a method on us reentrantly,
21322        // which panics if we're on the stack.
21323        window.defer(cx, move |window, cx| {
21324            workspace.update(cx, |workspace, cx| {
21325                let pane = if split {
21326                    workspace.adjacent_pane(window, cx)
21327                } else {
21328                    workspace.active_pane().clone()
21329                };
21330
21331                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
21332                    let editor = buffer
21333                        .read(cx)
21334                        .file()
21335                        .is_none()
21336                        .then(|| {
21337                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
21338                            // so `workspace.open_project_item` will never find them, always opening a new editor.
21339                            // Instead, we try to activate the existing editor in the pane first.
21340                            let (editor, pane_item_index) =
21341                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
21342                                    let editor = item.downcast::<Editor>()?;
21343                                    let singleton_buffer =
21344                                        editor.read(cx).buffer().read(cx).as_singleton()?;
21345                                    if singleton_buffer == buffer {
21346                                        Some((editor, i))
21347                                    } else {
21348                                        None
21349                                    }
21350                                })?;
21351                            pane.update(cx, |pane, cx| {
21352                                pane.activate_item(pane_item_index, true, true, window, cx)
21353                            });
21354                            Some(editor)
21355                        })
21356                        .flatten()
21357                        .unwrap_or_else(|| {
21358                            workspace.open_project_item::<Self>(
21359                                pane.clone(),
21360                                buffer,
21361                                true,
21362                                true,
21363                                window,
21364                                cx,
21365                            )
21366                        });
21367
21368                    editor.update(cx, |editor, cx| {
21369                        let autoscroll = match scroll_offset {
21370                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
21371                            None => Autoscroll::newest(),
21372                        };
21373                        let nav_history = editor.nav_history.take();
21374                        editor.change_selections(
21375                            SelectionEffects::scroll(autoscroll),
21376                            window,
21377                            cx,
21378                            |s| {
21379                                s.select_ranges(ranges);
21380                            },
21381                        );
21382                        editor.nav_history = nav_history;
21383                    });
21384                }
21385            })
21386        });
21387    }
21388
21389    // For now, don't allow opening excerpts in buffers that aren't backed by
21390    // regular project files.
21391    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
21392        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some())
21393    }
21394
21395    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
21396        let snapshot = self.buffer.read(cx).read(cx);
21397        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
21398        Some(
21399            ranges
21400                .iter()
21401                .map(move |range| {
21402                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
21403                })
21404                .collect(),
21405        )
21406    }
21407
21408    fn selection_replacement_ranges(
21409        &self,
21410        range: Range<OffsetUtf16>,
21411        cx: &mut App,
21412    ) -> Vec<Range<OffsetUtf16>> {
21413        let selections = self
21414            .selections
21415            .all::<OffsetUtf16>(&self.display_snapshot(cx));
21416        let newest_selection = selections
21417            .iter()
21418            .max_by_key(|selection| selection.id)
21419            .unwrap();
21420        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
21421        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
21422        let snapshot = self.buffer.read(cx).read(cx);
21423        selections
21424            .into_iter()
21425            .map(|mut selection| {
21426                selection.start.0 =
21427                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
21428                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
21429                snapshot.clip_offset_utf16(selection.start, Bias::Left)
21430                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
21431            })
21432            .collect()
21433    }
21434
21435    fn report_editor_event(
21436        &self,
21437        reported_event: ReportEditorEvent,
21438        file_extension: Option<String>,
21439        cx: &App,
21440    ) {
21441        if cfg!(any(test, feature = "test-support")) {
21442            return;
21443        }
21444
21445        let Some(project) = &self.project else { return };
21446
21447        // If None, we are in a file without an extension
21448        let file = self
21449            .buffer
21450            .read(cx)
21451            .as_singleton()
21452            .and_then(|b| b.read(cx).file());
21453        let file_extension = file_extension.or(file
21454            .as_ref()
21455            .and_then(|file| Path::new(file.file_name(cx)).extension())
21456            .and_then(|e| e.to_str())
21457            .map(|a| a.to_string()));
21458
21459        let vim_mode = vim_flavor(cx).is_some();
21460
21461        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
21462        let copilot_enabled = edit_predictions_provider
21463            == language::language_settings::EditPredictionProvider::Copilot;
21464        let copilot_enabled_for_language = self
21465            .buffer
21466            .read(cx)
21467            .language_settings(cx)
21468            .show_edit_predictions;
21469
21470        let project = project.read(cx);
21471        let event_type = reported_event.event_type();
21472
21473        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
21474            telemetry::event!(
21475                event_type,
21476                type = if auto_saved {"autosave"} else {"manual"},
21477                file_extension,
21478                vim_mode,
21479                copilot_enabled,
21480                copilot_enabled_for_language,
21481                edit_predictions_provider,
21482                is_via_ssh = project.is_via_remote_server(),
21483            );
21484        } else {
21485            telemetry::event!(
21486                event_type,
21487                file_extension,
21488                vim_mode,
21489                copilot_enabled,
21490                copilot_enabled_for_language,
21491                edit_predictions_provider,
21492                is_via_ssh = project.is_via_remote_server(),
21493            );
21494        };
21495    }
21496
21497    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
21498    /// with each line being an array of {text, highlight} objects.
21499    fn copy_highlight_json(
21500        &mut self,
21501        _: &CopyHighlightJson,
21502        window: &mut Window,
21503        cx: &mut Context<Self>,
21504    ) {
21505        #[derive(Serialize)]
21506        struct Chunk<'a> {
21507            text: String,
21508            highlight: Option<&'a str>,
21509        }
21510
21511        let snapshot = self.buffer.read(cx).snapshot(cx);
21512        let range = self
21513            .selected_text_range(false, window, cx)
21514            .and_then(|selection| {
21515                if selection.range.is_empty() {
21516                    None
21517                } else {
21518                    Some(
21519                        snapshot.offset_utf16_to_offset(OffsetUtf16(selection.range.start))
21520                            ..snapshot.offset_utf16_to_offset(OffsetUtf16(selection.range.end)),
21521                    )
21522                }
21523            })
21524            .unwrap_or_else(|| 0..snapshot.len());
21525
21526        let chunks = snapshot.chunks(range, true);
21527        let mut lines = Vec::new();
21528        let mut line: VecDeque<Chunk> = VecDeque::new();
21529
21530        let Some(style) = self.style.as_ref() else {
21531            return;
21532        };
21533
21534        for chunk in chunks {
21535            let highlight = chunk
21536                .syntax_highlight_id
21537                .and_then(|id| id.name(&style.syntax));
21538            let mut chunk_lines = chunk.text.split('\n').peekable();
21539            while let Some(text) = chunk_lines.next() {
21540                let mut merged_with_last_token = false;
21541                if let Some(last_token) = line.back_mut()
21542                    && last_token.highlight == highlight
21543                {
21544                    last_token.text.push_str(text);
21545                    merged_with_last_token = true;
21546                }
21547
21548                if !merged_with_last_token {
21549                    line.push_back(Chunk {
21550                        text: text.into(),
21551                        highlight,
21552                    });
21553                }
21554
21555                if chunk_lines.peek().is_some() {
21556                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
21557                        line.pop_front();
21558                    }
21559                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
21560                        line.pop_back();
21561                    }
21562
21563                    lines.push(mem::take(&mut line));
21564                }
21565            }
21566        }
21567
21568        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
21569            return;
21570        };
21571        cx.write_to_clipboard(ClipboardItem::new_string(lines));
21572    }
21573
21574    pub fn open_context_menu(
21575        &mut self,
21576        _: &OpenContextMenu,
21577        window: &mut Window,
21578        cx: &mut Context<Self>,
21579    ) {
21580        self.request_autoscroll(Autoscroll::newest(), cx);
21581        let position = self
21582            .selections
21583            .newest_display(&self.display_snapshot(cx))
21584            .start;
21585        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
21586    }
21587
21588    pub fn replay_insert_event(
21589        &mut self,
21590        text: &str,
21591        relative_utf16_range: Option<Range<isize>>,
21592        window: &mut Window,
21593        cx: &mut Context<Self>,
21594    ) {
21595        if !self.input_enabled {
21596            cx.emit(EditorEvent::InputIgnored { text: text.into() });
21597            return;
21598        }
21599        if let Some(relative_utf16_range) = relative_utf16_range {
21600            let selections = self
21601                .selections
21602                .all::<OffsetUtf16>(&self.display_snapshot(cx));
21603            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21604                let new_ranges = selections.into_iter().map(|range| {
21605                    let start = OffsetUtf16(
21606                        range
21607                            .head()
21608                            .0
21609                            .saturating_add_signed(relative_utf16_range.start),
21610                    );
21611                    let end = OffsetUtf16(
21612                        range
21613                            .head()
21614                            .0
21615                            .saturating_add_signed(relative_utf16_range.end),
21616                    );
21617                    start..end
21618                });
21619                s.select_ranges(new_ranges);
21620            });
21621        }
21622
21623        self.handle_input(text, window, cx);
21624    }
21625
21626    pub fn is_focused(&self, window: &Window) -> bool {
21627        self.focus_handle.is_focused(window)
21628    }
21629
21630    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21631        cx.emit(EditorEvent::Focused);
21632
21633        if let Some(descendant) = self
21634            .last_focused_descendant
21635            .take()
21636            .and_then(|descendant| descendant.upgrade())
21637        {
21638            window.focus(&descendant);
21639        } else {
21640            if let Some(blame) = self.blame.as_ref() {
21641                blame.update(cx, GitBlame::focus)
21642            }
21643
21644            self.blink_manager.update(cx, BlinkManager::enable);
21645            self.show_cursor_names(window, cx);
21646            self.buffer.update(cx, |buffer, cx| {
21647                buffer.finalize_last_transaction(cx);
21648                if self.leader_id.is_none() {
21649                    buffer.set_active_selections(
21650                        &self.selections.disjoint_anchors_arc(),
21651                        self.selections.line_mode(),
21652                        self.cursor_shape,
21653                        cx,
21654                    );
21655                }
21656            });
21657        }
21658    }
21659
21660    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
21661        cx.emit(EditorEvent::FocusedIn)
21662    }
21663
21664    fn handle_focus_out(
21665        &mut self,
21666        event: FocusOutEvent,
21667        _window: &mut Window,
21668        cx: &mut Context<Self>,
21669    ) {
21670        if event.blurred != self.focus_handle {
21671            self.last_focused_descendant = Some(event.blurred);
21672        }
21673        self.selection_drag_state = SelectionDragState::None;
21674        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
21675    }
21676
21677    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21678        self.blink_manager.update(cx, BlinkManager::disable);
21679        self.buffer
21680            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
21681
21682        if let Some(blame) = self.blame.as_ref() {
21683            blame.update(cx, GitBlame::blur)
21684        }
21685        if !self.hover_state.focused(window, cx) {
21686            hide_hover(self, cx);
21687        }
21688        if !self
21689            .context_menu
21690            .borrow()
21691            .as_ref()
21692            .is_some_and(|context_menu| context_menu.focused(window, cx))
21693        {
21694            self.hide_context_menu(window, cx);
21695        }
21696        self.take_active_edit_prediction(cx);
21697        cx.emit(EditorEvent::Blurred);
21698        cx.notify();
21699    }
21700
21701    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21702        let mut pending: String = window
21703            .pending_input_keystrokes()
21704            .into_iter()
21705            .flatten()
21706            .filter_map(|keystroke| {
21707                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
21708                    keystroke.key_char.clone()
21709                } else {
21710                    None
21711                }
21712            })
21713            .collect();
21714
21715        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
21716            pending = "".to_string();
21717        }
21718
21719        let existing_pending = self
21720            .text_highlights::<PendingInput>(cx)
21721            .map(|(_, ranges)| ranges.to_vec());
21722        if existing_pending.is_none() && pending.is_empty() {
21723            return;
21724        }
21725        let transaction =
21726            self.transact(window, cx, |this, window, cx| {
21727                let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
21728                let edits = selections
21729                    .iter()
21730                    .map(|selection| (selection.end..selection.end, pending.clone()));
21731                this.edit(edits, cx);
21732                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21733                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
21734                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
21735                    }));
21736                });
21737                if let Some(existing_ranges) = existing_pending {
21738                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
21739                    this.edit(edits, cx);
21740                }
21741            });
21742
21743        let snapshot = self.snapshot(window, cx);
21744        let ranges = self
21745            .selections
21746            .all::<usize>(&snapshot.display_snapshot)
21747            .into_iter()
21748            .map(|selection| {
21749                snapshot.buffer_snapshot().anchor_after(selection.end)
21750                    ..snapshot
21751                        .buffer_snapshot()
21752                        .anchor_before(selection.end + pending.len())
21753            })
21754            .collect();
21755
21756        if pending.is_empty() {
21757            self.clear_highlights::<PendingInput>(cx);
21758        } else {
21759            self.highlight_text::<PendingInput>(
21760                ranges,
21761                HighlightStyle {
21762                    underline: Some(UnderlineStyle {
21763                        thickness: px(1.),
21764                        color: None,
21765                        wavy: false,
21766                    }),
21767                    ..Default::default()
21768                },
21769                cx,
21770            );
21771        }
21772
21773        self.ime_transaction = self.ime_transaction.or(transaction);
21774        if let Some(transaction) = self.ime_transaction {
21775            self.buffer.update(cx, |buffer, cx| {
21776                buffer.group_until_transaction(transaction, cx);
21777            });
21778        }
21779
21780        if self.text_highlights::<PendingInput>(cx).is_none() {
21781            self.ime_transaction.take();
21782        }
21783    }
21784
21785    pub fn register_action_renderer(
21786        &mut self,
21787        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
21788    ) -> Subscription {
21789        let id = self.next_editor_action_id.post_inc();
21790        self.editor_actions
21791            .borrow_mut()
21792            .insert(id, Box::new(listener));
21793
21794        let editor_actions = self.editor_actions.clone();
21795        Subscription::new(move || {
21796            editor_actions.borrow_mut().remove(&id);
21797        })
21798    }
21799
21800    pub fn register_action<A: Action>(
21801        &mut self,
21802        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
21803    ) -> Subscription {
21804        let id = self.next_editor_action_id.post_inc();
21805        let listener = Arc::new(listener);
21806        self.editor_actions.borrow_mut().insert(
21807            id,
21808            Box::new(move |_, window, _| {
21809                let listener = listener.clone();
21810                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
21811                    let action = action.downcast_ref().unwrap();
21812                    if phase == DispatchPhase::Bubble {
21813                        listener(action, window, cx)
21814                    }
21815                })
21816            }),
21817        );
21818
21819        let editor_actions = self.editor_actions.clone();
21820        Subscription::new(move || {
21821            editor_actions.borrow_mut().remove(&id);
21822        })
21823    }
21824
21825    pub fn file_header_size(&self) -> u32 {
21826        FILE_HEADER_HEIGHT
21827    }
21828
21829    pub fn restore(
21830        &mut self,
21831        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
21832        window: &mut Window,
21833        cx: &mut Context<Self>,
21834    ) {
21835        let workspace = self.workspace();
21836        let project = self.project();
21837        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
21838            let mut tasks = Vec::new();
21839            for (buffer_id, changes) in revert_changes {
21840                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
21841                    buffer.update(cx, |buffer, cx| {
21842                        buffer.edit(
21843                            changes
21844                                .into_iter()
21845                                .map(|(range, text)| (range, text.to_string())),
21846                            None,
21847                            cx,
21848                        );
21849                    });
21850
21851                    if let Some(project) =
21852                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
21853                    {
21854                        project.update(cx, |project, cx| {
21855                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
21856                        })
21857                    }
21858                }
21859            }
21860            tasks
21861        });
21862        cx.spawn_in(window, async move |_, cx| {
21863            for (buffer, task) in save_tasks {
21864                let result = task.await;
21865                if result.is_err() {
21866                    let Some(path) = buffer
21867                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
21868                        .ok()
21869                    else {
21870                        continue;
21871                    };
21872                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
21873                        let Some(task) = cx
21874                            .update_window_entity(workspace, |workspace, window, cx| {
21875                                workspace
21876                                    .open_path_preview(path, None, false, false, false, window, cx)
21877                            })
21878                            .ok()
21879                        else {
21880                            continue;
21881                        };
21882                        task.await.log_err();
21883                    }
21884                }
21885            }
21886        })
21887        .detach();
21888        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
21889            selections.refresh()
21890        });
21891    }
21892
21893    pub fn to_pixel_point(
21894        &self,
21895        source: multi_buffer::Anchor,
21896        editor_snapshot: &EditorSnapshot,
21897        window: &mut Window,
21898    ) -> Option<gpui::Point<Pixels>> {
21899        let source_point = source.to_display_point(editor_snapshot);
21900        self.display_to_pixel_point(source_point, editor_snapshot, window)
21901    }
21902
21903    pub fn display_to_pixel_point(
21904        &self,
21905        source: DisplayPoint,
21906        editor_snapshot: &EditorSnapshot,
21907        window: &mut Window,
21908    ) -> Option<gpui::Point<Pixels>> {
21909        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
21910        let text_layout_details = self.text_layout_details(window);
21911        let scroll_top = text_layout_details
21912            .scroll_anchor
21913            .scroll_position(editor_snapshot)
21914            .y;
21915
21916        if source.row().as_f64() < scroll_top.floor() {
21917            return None;
21918        }
21919        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
21920        let source_y = line_height * (source.row().as_f64() - scroll_top) as f32;
21921        Some(gpui::Point::new(source_x, source_y))
21922    }
21923
21924    pub fn has_visible_completions_menu(&self) -> bool {
21925        !self.edit_prediction_preview_is_active()
21926            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
21927                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
21928            })
21929    }
21930
21931    pub fn register_addon<T: Addon>(&mut self, instance: T) {
21932        if self.mode.is_minimap() {
21933            return;
21934        }
21935        self.addons
21936            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
21937    }
21938
21939    pub fn unregister_addon<T: Addon>(&mut self) {
21940        self.addons.remove(&std::any::TypeId::of::<T>());
21941    }
21942
21943    pub fn addon<T: Addon>(&self) -> Option<&T> {
21944        let type_id = std::any::TypeId::of::<T>();
21945        self.addons
21946            .get(&type_id)
21947            .and_then(|item| item.to_any().downcast_ref::<T>())
21948    }
21949
21950    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
21951        let type_id = std::any::TypeId::of::<T>();
21952        self.addons
21953            .get_mut(&type_id)
21954            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
21955    }
21956
21957    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
21958        let text_layout_details = self.text_layout_details(window);
21959        let style = &text_layout_details.editor_style;
21960        let font_id = window.text_system().resolve_font(&style.text.font());
21961        let font_size = style.text.font_size.to_pixels(window.rem_size());
21962        let line_height = style.text.line_height_in_pixels(window.rem_size());
21963        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
21964        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
21965
21966        CharacterDimensions {
21967            em_width,
21968            em_advance,
21969            line_height,
21970        }
21971    }
21972
21973    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
21974        self.load_diff_task.clone()
21975    }
21976
21977    fn read_metadata_from_db(
21978        &mut self,
21979        item_id: u64,
21980        workspace_id: WorkspaceId,
21981        window: &mut Window,
21982        cx: &mut Context<Editor>,
21983    ) {
21984        if self.buffer_kind(cx) == ItemBufferKind::Singleton
21985            && !self.mode.is_minimap()
21986            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
21987        {
21988            let buffer_snapshot = OnceCell::new();
21989
21990            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
21991                && !folds.is_empty()
21992            {
21993                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21994                self.fold_ranges(
21995                    folds
21996                        .into_iter()
21997                        .map(|(start, end)| {
21998                            snapshot.clip_offset(start, Bias::Left)
21999                                ..snapshot.clip_offset(end, Bias::Right)
22000                        })
22001                        .collect(),
22002                    false,
22003                    window,
22004                    cx,
22005                );
22006            }
22007
22008            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
22009                && !selections.is_empty()
22010            {
22011                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
22012                // skip adding the initial selection to selection history
22013                self.selection_history.mode = SelectionHistoryMode::Skipping;
22014                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22015                    s.select_ranges(selections.into_iter().map(|(start, end)| {
22016                        snapshot.clip_offset(start, Bias::Left)
22017                            ..snapshot.clip_offset(end, Bias::Right)
22018                    }));
22019                });
22020                self.selection_history.mode = SelectionHistoryMode::Normal;
22021            };
22022        }
22023
22024        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
22025    }
22026
22027    fn update_lsp_data(
22028        &mut self,
22029        for_buffer: Option<BufferId>,
22030        window: &mut Window,
22031        cx: &mut Context<'_, Self>,
22032    ) {
22033        self.pull_diagnostics(for_buffer, window, cx);
22034        self.refresh_colors_for_visible_range(for_buffer, window, cx);
22035    }
22036
22037    fn register_visible_buffers(&mut self, cx: &mut Context<Self>) {
22038        if self.ignore_lsp_data() {
22039            return;
22040        }
22041        for (_, (visible_buffer, _, _)) in self.visible_excerpts(cx) {
22042            self.register_buffer(visible_buffer.read(cx).remote_id(), cx);
22043        }
22044    }
22045
22046    fn register_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
22047        if !self.registered_buffers.contains_key(&buffer_id)
22048            && let Some(project) = self.project.as_ref()
22049        {
22050            if let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) {
22051                project.update(cx, |project, cx| {
22052                    self.registered_buffers.insert(
22053                        buffer_id,
22054                        project.register_buffer_with_language_servers(&buffer, cx),
22055                    );
22056                });
22057            } else {
22058                self.registered_buffers.remove(&buffer_id);
22059            }
22060        }
22061    }
22062
22063    fn ignore_lsp_data(&self) -> bool {
22064        // `ActiveDiagnostic::All` is a special mode where editor's diagnostics are managed by the external view,
22065        // skip any LSP updates for it.
22066        self.active_diagnostics == ActiveDiagnostic::All || !self.mode().is_full()
22067    }
22068}
22069
22070fn edit_for_markdown_paste<'a>(
22071    buffer: &MultiBufferSnapshot,
22072    range: Range<usize>,
22073    to_insert: &'a str,
22074    url: Option<url::Url>,
22075) -> (Range<usize>, Cow<'a, str>) {
22076    if url.is_none() {
22077        return (range, Cow::Borrowed(to_insert));
22078    };
22079
22080    let old_text = buffer.text_for_range(range.clone()).collect::<String>();
22081
22082    let new_text = if range.is_empty() || url::Url::parse(&old_text).is_ok() {
22083        Cow::Borrowed(to_insert)
22084    } else {
22085        Cow::Owned(format!("[{old_text}]({to_insert})"))
22086    };
22087    (range, new_text)
22088}
22089
22090#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
22091pub enum VimFlavor {
22092    Vim,
22093    Helix,
22094}
22095
22096pub fn vim_flavor(cx: &App) -> Option<VimFlavor> {
22097    if vim_mode_setting::HelixModeSetting::try_get(cx)
22098        .map(|helix_mode| helix_mode.0)
22099        .unwrap_or(false)
22100    {
22101        Some(VimFlavor::Helix)
22102    } else if vim_mode_setting::VimModeSetting::try_get(cx)
22103        .map(|vim_mode| vim_mode.0)
22104        .unwrap_or(false)
22105    {
22106        Some(VimFlavor::Vim)
22107    } else {
22108        None // neither vim nor helix mode
22109    }
22110}
22111
22112fn process_completion_for_edit(
22113    completion: &Completion,
22114    intent: CompletionIntent,
22115    buffer: &Entity<Buffer>,
22116    cursor_position: &text::Anchor,
22117    cx: &mut Context<Editor>,
22118) -> CompletionEdit {
22119    let buffer = buffer.read(cx);
22120    let buffer_snapshot = buffer.snapshot();
22121    let (snippet, new_text) = if completion.is_snippet() {
22122        let mut snippet_source = completion.new_text.clone();
22123        // Workaround for typescript language server issues so that methods don't expand within
22124        // strings and functions with type expressions. The previous point is used because the query
22125        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
22126        let previous_point = text::ToPoint::to_point(cursor_position, &buffer_snapshot);
22127        let previous_point = if previous_point.column > 0 {
22128            cursor_position.to_previous_offset(&buffer_snapshot)
22129        } else {
22130            cursor_position.to_offset(&buffer_snapshot)
22131        };
22132        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
22133            && scope.prefers_label_for_snippet_in_completion()
22134            && let Some(label) = completion.label()
22135            && matches!(
22136                completion.kind(),
22137                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
22138            )
22139        {
22140            snippet_source = label;
22141        }
22142        match Snippet::parse(&snippet_source).log_err() {
22143            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
22144            None => (None, completion.new_text.clone()),
22145        }
22146    } else {
22147        (None, completion.new_text.clone())
22148    };
22149
22150    let mut range_to_replace = {
22151        let replace_range = &completion.replace_range;
22152        if let CompletionSource::Lsp {
22153            insert_range: Some(insert_range),
22154            ..
22155        } = &completion.source
22156        {
22157            debug_assert_eq!(
22158                insert_range.start, replace_range.start,
22159                "insert_range and replace_range should start at the same position"
22160            );
22161            debug_assert!(
22162                insert_range
22163                    .start
22164                    .cmp(cursor_position, &buffer_snapshot)
22165                    .is_le(),
22166                "insert_range should start before or at cursor position"
22167            );
22168            debug_assert!(
22169                replace_range
22170                    .start
22171                    .cmp(cursor_position, &buffer_snapshot)
22172                    .is_le(),
22173                "replace_range should start before or at cursor position"
22174            );
22175
22176            let should_replace = match intent {
22177                CompletionIntent::CompleteWithInsert => false,
22178                CompletionIntent::CompleteWithReplace => true,
22179                CompletionIntent::Complete | CompletionIntent::Compose => {
22180                    let insert_mode =
22181                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
22182                            .completions
22183                            .lsp_insert_mode;
22184                    match insert_mode {
22185                        LspInsertMode::Insert => false,
22186                        LspInsertMode::Replace => true,
22187                        LspInsertMode::ReplaceSubsequence => {
22188                            let mut text_to_replace = buffer.chars_for_range(
22189                                buffer.anchor_before(replace_range.start)
22190                                    ..buffer.anchor_after(replace_range.end),
22191                            );
22192                            let mut current_needle = text_to_replace.next();
22193                            for haystack_ch in completion.label.text.chars() {
22194                                if let Some(needle_ch) = current_needle
22195                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
22196                                {
22197                                    current_needle = text_to_replace.next();
22198                                }
22199                            }
22200                            current_needle.is_none()
22201                        }
22202                        LspInsertMode::ReplaceSuffix => {
22203                            if replace_range
22204                                .end
22205                                .cmp(cursor_position, &buffer_snapshot)
22206                                .is_gt()
22207                            {
22208                                let range_after_cursor = *cursor_position..replace_range.end;
22209                                let text_after_cursor = buffer
22210                                    .text_for_range(
22211                                        buffer.anchor_before(range_after_cursor.start)
22212                                            ..buffer.anchor_after(range_after_cursor.end),
22213                                    )
22214                                    .collect::<String>()
22215                                    .to_ascii_lowercase();
22216                                completion
22217                                    .label
22218                                    .text
22219                                    .to_ascii_lowercase()
22220                                    .ends_with(&text_after_cursor)
22221                            } else {
22222                                true
22223                            }
22224                        }
22225                    }
22226                }
22227            };
22228
22229            if should_replace {
22230                replace_range.clone()
22231            } else {
22232                insert_range.clone()
22233            }
22234        } else {
22235            replace_range.clone()
22236        }
22237    };
22238
22239    if range_to_replace
22240        .end
22241        .cmp(cursor_position, &buffer_snapshot)
22242        .is_lt()
22243    {
22244        range_to_replace.end = *cursor_position;
22245    }
22246
22247    CompletionEdit {
22248        new_text,
22249        replace_range: range_to_replace.to_offset(buffer),
22250        snippet,
22251    }
22252}
22253
22254struct CompletionEdit {
22255    new_text: String,
22256    replace_range: Range<usize>,
22257    snippet: Option<Snippet>,
22258}
22259
22260fn insert_extra_newline_brackets(
22261    buffer: &MultiBufferSnapshot,
22262    range: Range<usize>,
22263    language: &language::LanguageScope,
22264) -> bool {
22265    let leading_whitespace_len = buffer
22266        .reversed_chars_at(range.start)
22267        .take_while(|c| c.is_whitespace() && *c != '\n')
22268        .map(|c| c.len_utf8())
22269        .sum::<usize>();
22270    let trailing_whitespace_len = buffer
22271        .chars_at(range.end)
22272        .take_while(|c| c.is_whitespace() && *c != '\n')
22273        .map(|c| c.len_utf8())
22274        .sum::<usize>();
22275    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
22276
22277    language.brackets().any(|(pair, enabled)| {
22278        let pair_start = pair.start.trim_end();
22279        let pair_end = pair.end.trim_start();
22280
22281        enabled
22282            && pair.newline
22283            && buffer.contains_str_at(range.end, pair_end)
22284            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
22285    })
22286}
22287
22288fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
22289    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
22290        [(buffer, range, _)] => (*buffer, range.clone()),
22291        _ => return false,
22292    };
22293    let pair = {
22294        let mut result: Option<BracketMatch> = None;
22295
22296        for pair in buffer
22297            .all_bracket_ranges(range.clone())
22298            .filter(move |pair| {
22299                pair.open_range.start <= range.start && pair.close_range.end >= range.end
22300            })
22301        {
22302            let len = pair.close_range.end - pair.open_range.start;
22303
22304            if let Some(existing) = &result {
22305                let existing_len = existing.close_range.end - existing.open_range.start;
22306                if len > existing_len {
22307                    continue;
22308                }
22309            }
22310
22311            result = Some(pair);
22312        }
22313
22314        result
22315    };
22316    let Some(pair) = pair else {
22317        return false;
22318    };
22319    pair.newline_only
22320        && buffer
22321            .chars_for_range(pair.open_range.end..range.start)
22322            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
22323            .all(|c| c.is_whitespace() && c != '\n')
22324}
22325
22326fn update_uncommitted_diff_for_buffer(
22327    editor: Entity<Editor>,
22328    project: &Entity<Project>,
22329    buffers: impl IntoIterator<Item = Entity<Buffer>>,
22330    buffer: Entity<MultiBuffer>,
22331    cx: &mut App,
22332) -> Task<()> {
22333    let mut tasks = Vec::new();
22334    project.update(cx, |project, cx| {
22335        for buffer in buffers {
22336            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
22337                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
22338            }
22339        }
22340    });
22341    cx.spawn(async move |cx| {
22342        let diffs = future::join_all(tasks).await;
22343        if editor
22344            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
22345            .unwrap_or(false)
22346        {
22347            return;
22348        }
22349
22350        buffer
22351            .update(cx, |buffer, cx| {
22352                for diff in diffs.into_iter().flatten() {
22353                    buffer.add_diff(diff, cx);
22354                }
22355            })
22356            .ok();
22357    })
22358}
22359
22360fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
22361    let tab_size = tab_size.get() as usize;
22362    let mut width = offset;
22363
22364    for ch in text.chars() {
22365        width += if ch == '\t' {
22366            tab_size - (width % tab_size)
22367        } else {
22368            1
22369        };
22370    }
22371
22372    width - offset
22373}
22374
22375#[cfg(test)]
22376mod tests {
22377    use super::*;
22378
22379    #[test]
22380    fn test_string_size_with_expanded_tabs() {
22381        let nz = |val| NonZeroU32::new(val).unwrap();
22382        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
22383        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
22384        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
22385        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
22386        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
22387        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
22388        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
22389        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
22390    }
22391}
22392
22393/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
22394struct WordBreakingTokenizer<'a> {
22395    input: &'a str,
22396}
22397
22398impl<'a> WordBreakingTokenizer<'a> {
22399    fn new(input: &'a str) -> Self {
22400        Self { input }
22401    }
22402}
22403
22404fn is_char_ideographic(ch: char) -> bool {
22405    use unicode_script::Script::*;
22406    use unicode_script::UnicodeScript;
22407    matches!(ch.script(), Han | Tangut | Yi)
22408}
22409
22410fn is_grapheme_ideographic(text: &str) -> bool {
22411    text.chars().any(is_char_ideographic)
22412}
22413
22414fn is_grapheme_whitespace(text: &str) -> bool {
22415    text.chars().any(|x| x.is_whitespace())
22416}
22417
22418fn should_stay_with_preceding_ideograph(text: &str) -> bool {
22419    text.chars()
22420        .next()
22421        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
22422}
22423
22424#[derive(PartialEq, Eq, Debug, Clone, Copy)]
22425enum WordBreakToken<'a> {
22426    Word { token: &'a str, grapheme_len: usize },
22427    InlineWhitespace { token: &'a str, grapheme_len: usize },
22428    Newline,
22429}
22430
22431impl<'a> Iterator for WordBreakingTokenizer<'a> {
22432    /// Yields a span, the count of graphemes in the token, and whether it was
22433    /// whitespace. Note that it also breaks at word boundaries.
22434    type Item = WordBreakToken<'a>;
22435
22436    fn next(&mut self) -> Option<Self::Item> {
22437        use unicode_segmentation::UnicodeSegmentation;
22438        if self.input.is_empty() {
22439            return None;
22440        }
22441
22442        let mut iter = self.input.graphemes(true).peekable();
22443        let mut offset = 0;
22444        let mut grapheme_len = 0;
22445        if let Some(first_grapheme) = iter.next() {
22446            let is_newline = first_grapheme == "\n";
22447            let is_whitespace = is_grapheme_whitespace(first_grapheme);
22448            offset += first_grapheme.len();
22449            grapheme_len += 1;
22450            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
22451                if let Some(grapheme) = iter.peek().copied()
22452                    && should_stay_with_preceding_ideograph(grapheme)
22453                {
22454                    offset += grapheme.len();
22455                    grapheme_len += 1;
22456                }
22457            } else {
22458                let mut words = self.input[offset..].split_word_bound_indices().peekable();
22459                let mut next_word_bound = words.peek().copied();
22460                if next_word_bound.is_some_and(|(i, _)| i == 0) {
22461                    next_word_bound = words.next();
22462                }
22463                while let Some(grapheme) = iter.peek().copied() {
22464                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
22465                        break;
22466                    };
22467                    if is_grapheme_whitespace(grapheme) != is_whitespace
22468                        || (grapheme == "\n") != is_newline
22469                    {
22470                        break;
22471                    };
22472                    offset += grapheme.len();
22473                    grapheme_len += 1;
22474                    iter.next();
22475                }
22476            }
22477            let token = &self.input[..offset];
22478            self.input = &self.input[offset..];
22479            if token == "\n" {
22480                Some(WordBreakToken::Newline)
22481            } else if is_whitespace {
22482                Some(WordBreakToken::InlineWhitespace {
22483                    token,
22484                    grapheme_len,
22485                })
22486            } else {
22487                Some(WordBreakToken::Word {
22488                    token,
22489                    grapheme_len,
22490                })
22491            }
22492        } else {
22493            None
22494        }
22495    }
22496}
22497
22498#[test]
22499fn test_word_breaking_tokenizer() {
22500    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
22501        ("", &[]),
22502        ("  ", &[whitespace("  ", 2)]),
22503        ("Ʒ", &[word("Ʒ", 1)]),
22504        ("Ǽ", &[word("Ǽ", 1)]),
22505        ("", &[word("", 1)]),
22506        ("⋑⋑", &[word("⋑⋑", 2)]),
22507        (
22508            "原理,进而",
22509            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
22510        ),
22511        (
22512            "hello world",
22513            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
22514        ),
22515        (
22516            "hello, world",
22517            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
22518        ),
22519        (
22520            "  hello world",
22521            &[
22522                whitespace("  ", 2),
22523                word("hello", 5),
22524                whitespace(" ", 1),
22525                word("world", 5),
22526            ],
22527        ),
22528        (
22529            "这是什么 \n 钢笔",
22530            &[
22531                word("", 1),
22532                word("", 1),
22533                word("", 1),
22534                word("", 1),
22535                whitespace(" ", 1),
22536                newline(),
22537                whitespace(" ", 1),
22538                word("", 1),
22539                word("", 1),
22540            ],
22541        ),
22542        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
22543    ];
22544
22545    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22546        WordBreakToken::Word {
22547            token,
22548            grapheme_len,
22549        }
22550    }
22551
22552    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22553        WordBreakToken::InlineWhitespace {
22554            token,
22555            grapheme_len,
22556        }
22557    }
22558
22559    fn newline() -> WordBreakToken<'static> {
22560        WordBreakToken::Newline
22561    }
22562
22563    for (input, result) in tests {
22564        assert_eq!(
22565            WordBreakingTokenizer::new(input)
22566                .collect::<Vec<_>>()
22567                .as_slice(),
22568            *result,
22569        );
22570    }
22571}
22572
22573fn wrap_with_prefix(
22574    first_line_prefix: String,
22575    subsequent_lines_prefix: String,
22576    unwrapped_text: String,
22577    wrap_column: usize,
22578    tab_size: NonZeroU32,
22579    preserve_existing_whitespace: bool,
22580) -> String {
22581    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
22582    let subsequent_lines_prefix_len =
22583        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
22584    let mut wrapped_text = String::new();
22585    let mut current_line = first_line_prefix;
22586    let mut is_first_line = true;
22587
22588    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
22589    let mut current_line_len = first_line_prefix_len;
22590    let mut in_whitespace = false;
22591    for token in tokenizer {
22592        let have_preceding_whitespace = in_whitespace;
22593        match token {
22594            WordBreakToken::Word {
22595                token,
22596                grapheme_len,
22597            } => {
22598                in_whitespace = false;
22599                let current_prefix_len = if is_first_line {
22600                    first_line_prefix_len
22601                } else {
22602                    subsequent_lines_prefix_len
22603                };
22604                if current_line_len + grapheme_len > wrap_column
22605                    && current_line_len != current_prefix_len
22606                {
22607                    wrapped_text.push_str(current_line.trim_end());
22608                    wrapped_text.push('\n');
22609                    is_first_line = false;
22610                    current_line = subsequent_lines_prefix.clone();
22611                    current_line_len = subsequent_lines_prefix_len;
22612                }
22613                current_line.push_str(token);
22614                current_line_len += grapheme_len;
22615            }
22616            WordBreakToken::InlineWhitespace {
22617                mut token,
22618                mut grapheme_len,
22619            } => {
22620                in_whitespace = true;
22621                if have_preceding_whitespace && !preserve_existing_whitespace {
22622                    continue;
22623                }
22624                if !preserve_existing_whitespace {
22625                    // Keep a single whitespace grapheme as-is
22626                    if let Some(first) =
22627                        unicode_segmentation::UnicodeSegmentation::graphemes(token, true).next()
22628                    {
22629                        token = first;
22630                    } else {
22631                        token = " ";
22632                    }
22633                    grapheme_len = 1;
22634                }
22635                let current_prefix_len = if is_first_line {
22636                    first_line_prefix_len
22637                } else {
22638                    subsequent_lines_prefix_len
22639                };
22640                if current_line_len + grapheme_len > wrap_column {
22641                    wrapped_text.push_str(current_line.trim_end());
22642                    wrapped_text.push('\n');
22643                    is_first_line = false;
22644                    current_line = subsequent_lines_prefix.clone();
22645                    current_line_len = subsequent_lines_prefix_len;
22646                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
22647                    current_line.push_str(token);
22648                    current_line_len += grapheme_len;
22649                }
22650            }
22651            WordBreakToken::Newline => {
22652                in_whitespace = true;
22653                let current_prefix_len = if is_first_line {
22654                    first_line_prefix_len
22655                } else {
22656                    subsequent_lines_prefix_len
22657                };
22658                if preserve_existing_whitespace {
22659                    wrapped_text.push_str(current_line.trim_end());
22660                    wrapped_text.push('\n');
22661                    is_first_line = false;
22662                    current_line = subsequent_lines_prefix.clone();
22663                    current_line_len = subsequent_lines_prefix_len;
22664                } else if have_preceding_whitespace {
22665                    continue;
22666                } else if current_line_len + 1 > wrap_column
22667                    && current_line_len != current_prefix_len
22668                {
22669                    wrapped_text.push_str(current_line.trim_end());
22670                    wrapped_text.push('\n');
22671                    is_first_line = false;
22672                    current_line = subsequent_lines_prefix.clone();
22673                    current_line_len = subsequent_lines_prefix_len;
22674                } else if current_line_len != current_prefix_len {
22675                    current_line.push(' ');
22676                    current_line_len += 1;
22677                }
22678            }
22679        }
22680    }
22681
22682    if !current_line.is_empty() {
22683        wrapped_text.push_str(&current_line);
22684    }
22685    wrapped_text
22686}
22687
22688#[test]
22689fn test_wrap_with_prefix() {
22690    assert_eq!(
22691        wrap_with_prefix(
22692            "# ".to_string(),
22693            "# ".to_string(),
22694            "abcdefg".to_string(),
22695            4,
22696            NonZeroU32::new(4).unwrap(),
22697            false,
22698        ),
22699        "# abcdefg"
22700    );
22701    assert_eq!(
22702        wrap_with_prefix(
22703            "".to_string(),
22704            "".to_string(),
22705            "\thello world".to_string(),
22706            8,
22707            NonZeroU32::new(4).unwrap(),
22708            false,
22709        ),
22710        "hello\nworld"
22711    );
22712    assert_eq!(
22713        wrap_with_prefix(
22714            "// ".to_string(),
22715            "// ".to_string(),
22716            "xx \nyy zz aa bb cc".to_string(),
22717            12,
22718            NonZeroU32::new(4).unwrap(),
22719            false,
22720        ),
22721        "// xx yy zz\n// aa bb cc"
22722    );
22723    assert_eq!(
22724        wrap_with_prefix(
22725            String::new(),
22726            String::new(),
22727            "这是什么 \n 钢笔".to_string(),
22728            3,
22729            NonZeroU32::new(4).unwrap(),
22730            false,
22731        ),
22732        "这是什\n么 钢\n"
22733    );
22734    assert_eq!(
22735        wrap_with_prefix(
22736            String::new(),
22737            String::new(),
22738            format!("foo{}bar", '\u{2009}'), // thin space
22739            80,
22740            NonZeroU32::new(4).unwrap(),
22741            false,
22742        ),
22743        format!("foo{}bar", '\u{2009}')
22744    );
22745}
22746
22747pub trait CollaborationHub {
22748    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
22749    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
22750    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
22751}
22752
22753impl CollaborationHub for Entity<Project> {
22754    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
22755        self.read(cx).collaborators()
22756    }
22757
22758    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
22759        self.read(cx).user_store().read(cx).participant_indices()
22760    }
22761
22762    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
22763        let this = self.read(cx);
22764        let user_ids = this.collaborators().values().map(|c| c.user_id);
22765        this.user_store().read(cx).participant_names(user_ids, cx)
22766    }
22767}
22768
22769pub trait SemanticsProvider {
22770    fn hover(
22771        &self,
22772        buffer: &Entity<Buffer>,
22773        position: text::Anchor,
22774        cx: &mut App,
22775    ) -> Option<Task<Option<Vec<project::Hover>>>>;
22776
22777    fn inline_values(
22778        &self,
22779        buffer_handle: Entity<Buffer>,
22780        range: Range<text::Anchor>,
22781        cx: &mut App,
22782    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22783
22784    fn applicable_inlay_chunks(
22785        &self,
22786        buffer: &Entity<Buffer>,
22787        ranges: &[Range<text::Anchor>],
22788        cx: &mut App,
22789    ) -> Vec<Range<BufferRow>>;
22790
22791    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App);
22792
22793    fn inlay_hints(
22794        &self,
22795        invalidate: InvalidationStrategy,
22796        buffer: Entity<Buffer>,
22797        ranges: Vec<Range<text::Anchor>>,
22798        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
22799        cx: &mut App,
22800    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>>;
22801
22802    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
22803
22804    fn document_highlights(
22805        &self,
22806        buffer: &Entity<Buffer>,
22807        position: text::Anchor,
22808        cx: &mut App,
22809    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
22810
22811    fn definitions(
22812        &self,
22813        buffer: &Entity<Buffer>,
22814        position: text::Anchor,
22815        kind: GotoDefinitionKind,
22816        cx: &mut App,
22817    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
22818
22819    fn range_for_rename(
22820        &self,
22821        buffer: &Entity<Buffer>,
22822        position: text::Anchor,
22823        cx: &mut App,
22824    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
22825
22826    fn perform_rename(
22827        &self,
22828        buffer: &Entity<Buffer>,
22829        position: text::Anchor,
22830        new_name: String,
22831        cx: &mut App,
22832    ) -> Option<Task<Result<ProjectTransaction>>>;
22833}
22834
22835pub trait CompletionProvider {
22836    fn completions(
22837        &self,
22838        excerpt_id: ExcerptId,
22839        buffer: &Entity<Buffer>,
22840        buffer_position: text::Anchor,
22841        trigger: CompletionContext,
22842        window: &mut Window,
22843        cx: &mut Context<Editor>,
22844    ) -> Task<Result<Vec<CompletionResponse>>>;
22845
22846    fn resolve_completions(
22847        &self,
22848        _buffer: Entity<Buffer>,
22849        _completion_indices: Vec<usize>,
22850        _completions: Rc<RefCell<Box<[Completion]>>>,
22851        _cx: &mut Context<Editor>,
22852    ) -> Task<Result<bool>> {
22853        Task::ready(Ok(false))
22854    }
22855
22856    fn apply_additional_edits_for_completion(
22857        &self,
22858        _buffer: Entity<Buffer>,
22859        _completions: Rc<RefCell<Box<[Completion]>>>,
22860        _completion_index: usize,
22861        _push_to_history: bool,
22862        _cx: &mut Context<Editor>,
22863    ) -> Task<Result<Option<language::Transaction>>> {
22864        Task::ready(Ok(None))
22865    }
22866
22867    fn is_completion_trigger(
22868        &self,
22869        buffer: &Entity<Buffer>,
22870        position: language::Anchor,
22871        text: &str,
22872        trigger_in_words: bool,
22873        menu_is_open: bool,
22874        cx: &mut Context<Editor>,
22875    ) -> bool;
22876
22877    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
22878
22879    fn sort_completions(&self) -> bool {
22880        true
22881    }
22882
22883    fn filter_completions(&self) -> bool {
22884        true
22885    }
22886}
22887
22888pub trait CodeActionProvider {
22889    fn id(&self) -> Arc<str>;
22890
22891    fn code_actions(
22892        &self,
22893        buffer: &Entity<Buffer>,
22894        range: Range<text::Anchor>,
22895        window: &mut Window,
22896        cx: &mut App,
22897    ) -> Task<Result<Vec<CodeAction>>>;
22898
22899    fn apply_code_action(
22900        &self,
22901        buffer_handle: Entity<Buffer>,
22902        action: CodeAction,
22903        excerpt_id: ExcerptId,
22904        push_to_history: bool,
22905        window: &mut Window,
22906        cx: &mut App,
22907    ) -> Task<Result<ProjectTransaction>>;
22908}
22909
22910impl CodeActionProvider for Entity<Project> {
22911    fn id(&self) -> Arc<str> {
22912        "project".into()
22913    }
22914
22915    fn code_actions(
22916        &self,
22917        buffer: &Entity<Buffer>,
22918        range: Range<text::Anchor>,
22919        _window: &mut Window,
22920        cx: &mut App,
22921    ) -> Task<Result<Vec<CodeAction>>> {
22922        self.update(cx, |project, cx| {
22923            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
22924            let code_actions = project.code_actions(buffer, range, None, cx);
22925            cx.background_spawn(async move {
22926                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
22927                Ok(code_lens_actions
22928                    .context("code lens fetch")?
22929                    .into_iter()
22930                    .flatten()
22931                    .chain(
22932                        code_actions
22933                            .context("code action fetch")?
22934                            .into_iter()
22935                            .flatten(),
22936                    )
22937                    .collect())
22938            })
22939        })
22940    }
22941
22942    fn apply_code_action(
22943        &self,
22944        buffer_handle: Entity<Buffer>,
22945        action: CodeAction,
22946        _excerpt_id: ExcerptId,
22947        push_to_history: bool,
22948        _window: &mut Window,
22949        cx: &mut App,
22950    ) -> Task<Result<ProjectTransaction>> {
22951        self.update(cx, |project, cx| {
22952            project.apply_code_action(buffer_handle, action, push_to_history, cx)
22953        })
22954    }
22955}
22956
22957fn snippet_completions(
22958    project: &Project,
22959    buffer: &Entity<Buffer>,
22960    buffer_position: text::Anchor,
22961    cx: &mut App,
22962) -> Task<Result<CompletionResponse>> {
22963    let languages = buffer.read(cx).languages_at(buffer_position);
22964    let snippet_store = project.snippets().read(cx);
22965
22966    let scopes: Vec<_> = languages
22967        .iter()
22968        .filter_map(|language| {
22969            let language_name = language.lsp_id();
22970            let snippets = snippet_store.snippets_for(Some(language_name), cx);
22971
22972            if snippets.is_empty() {
22973                None
22974            } else {
22975                Some((language.default_scope(), snippets))
22976            }
22977        })
22978        .collect();
22979
22980    if scopes.is_empty() {
22981        return Task::ready(Ok(CompletionResponse {
22982            completions: vec![],
22983            display_options: CompletionDisplayOptions::default(),
22984            is_incomplete: false,
22985        }));
22986    }
22987
22988    let snapshot = buffer.read(cx).text_snapshot();
22989    let executor = cx.background_executor().clone();
22990
22991    cx.background_spawn(async move {
22992        let mut is_incomplete = false;
22993        let mut completions: Vec<Completion> = Vec::new();
22994        for (scope, snippets) in scopes.into_iter() {
22995            let classifier =
22996                CharClassifier::new(Some(scope)).scope_context(Some(CharScopeContext::Completion));
22997
22998            const MAX_WORD_PREFIX_LEN: usize = 128;
22999            let last_word: String = snapshot
23000                .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
23001                .take(MAX_WORD_PREFIX_LEN)
23002                .take_while(|c| classifier.is_word(*c))
23003                .collect::<String>()
23004                .chars()
23005                .rev()
23006                .collect();
23007
23008            if last_word.is_empty() {
23009                return Ok(CompletionResponse {
23010                    completions: vec![],
23011                    display_options: CompletionDisplayOptions::default(),
23012                    is_incomplete: true,
23013                });
23014            }
23015
23016            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
23017            let to_lsp = |point: &text::Anchor| {
23018                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
23019                point_to_lsp(end)
23020            };
23021            let lsp_end = to_lsp(&buffer_position);
23022
23023            let candidates = snippets
23024                .iter()
23025                .enumerate()
23026                .flat_map(|(ix, snippet)| {
23027                    snippet
23028                        .prefix
23029                        .iter()
23030                        .map(move |prefix| StringMatchCandidate::new(ix, prefix))
23031                })
23032                .collect::<Vec<StringMatchCandidate>>();
23033
23034            const MAX_RESULTS: usize = 100;
23035            let mut matches = fuzzy::match_strings(
23036                &candidates,
23037                &last_word,
23038                last_word.chars().any(|c| c.is_uppercase()),
23039                true,
23040                MAX_RESULTS,
23041                &Default::default(),
23042                executor.clone(),
23043            )
23044            .await;
23045
23046            if matches.len() >= MAX_RESULTS {
23047                is_incomplete = true;
23048            }
23049
23050            // Remove all candidates where the query's start does not match the start of any word in the candidate
23051            if let Some(query_start) = last_word.chars().next() {
23052                matches.retain(|string_match| {
23053                    split_words(&string_match.string).any(|word| {
23054                        // Check that the first codepoint of the word as lowercase matches the first
23055                        // codepoint of the query as lowercase
23056                        word.chars()
23057                            .flat_map(|codepoint| codepoint.to_lowercase())
23058                            .zip(query_start.to_lowercase())
23059                            .all(|(word_cp, query_cp)| word_cp == query_cp)
23060                    })
23061                });
23062            }
23063
23064            let matched_strings = matches
23065                .into_iter()
23066                .map(|m| m.string)
23067                .collect::<HashSet<_>>();
23068
23069            completions.extend(snippets.iter().filter_map(|snippet| {
23070                let matching_prefix = snippet
23071                    .prefix
23072                    .iter()
23073                    .find(|prefix| matched_strings.contains(*prefix))?;
23074                let start = as_offset - last_word.len();
23075                let start = snapshot.anchor_before(start);
23076                let range = start..buffer_position;
23077                let lsp_start = to_lsp(&start);
23078                let lsp_range = lsp::Range {
23079                    start: lsp_start,
23080                    end: lsp_end,
23081                };
23082                Some(Completion {
23083                    replace_range: range,
23084                    new_text: snippet.body.clone(),
23085                    source: CompletionSource::Lsp {
23086                        insert_range: None,
23087                        server_id: LanguageServerId(usize::MAX),
23088                        resolved: true,
23089                        lsp_completion: Box::new(lsp::CompletionItem {
23090                            label: snippet.prefix.first().unwrap().clone(),
23091                            kind: Some(CompletionItemKind::SNIPPET),
23092                            label_details: snippet.description.as_ref().map(|description| {
23093                                lsp::CompletionItemLabelDetails {
23094                                    detail: Some(description.clone()),
23095                                    description: None,
23096                                }
23097                            }),
23098                            insert_text_format: Some(InsertTextFormat::SNIPPET),
23099                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
23100                                lsp::InsertReplaceEdit {
23101                                    new_text: snippet.body.clone(),
23102                                    insert: lsp_range,
23103                                    replace: lsp_range,
23104                                },
23105                            )),
23106                            filter_text: Some(snippet.body.clone()),
23107                            sort_text: Some(char::MAX.to_string()),
23108                            ..lsp::CompletionItem::default()
23109                        }),
23110                        lsp_defaults: None,
23111                    },
23112                    label: CodeLabel::plain(matching_prefix.clone(), None),
23113                    icon_path: None,
23114                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
23115                        single_line: snippet.name.clone().into(),
23116                        plain_text: snippet
23117                            .description
23118                            .clone()
23119                            .map(|description| description.into()),
23120                    }),
23121                    insert_text_mode: None,
23122                    confirm: None,
23123                })
23124            }))
23125        }
23126
23127        Ok(CompletionResponse {
23128            completions,
23129            display_options: CompletionDisplayOptions::default(),
23130            is_incomplete,
23131        })
23132    })
23133}
23134
23135impl CompletionProvider for Entity<Project> {
23136    fn completions(
23137        &self,
23138        _excerpt_id: ExcerptId,
23139        buffer: &Entity<Buffer>,
23140        buffer_position: text::Anchor,
23141        options: CompletionContext,
23142        _window: &mut Window,
23143        cx: &mut Context<Editor>,
23144    ) -> Task<Result<Vec<CompletionResponse>>> {
23145        self.update(cx, |project, cx| {
23146            let snippets = snippet_completions(project, buffer, buffer_position, cx);
23147            let project_completions = project.completions(buffer, buffer_position, options, cx);
23148            cx.background_spawn(async move {
23149                let mut responses = project_completions.await?;
23150                let snippets = snippets.await?;
23151                if !snippets.completions.is_empty() {
23152                    responses.push(snippets);
23153                }
23154                Ok(responses)
23155            })
23156        })
23157    }
23158
23159    fn resolve_completions(
23160        &self,
23161        buffer: Entity<Buffer>,
23162        completion_indices: Vec<usize>,
23163        completions: Rc<RefCell<Box<[Completion]>>>,
23164        cx: &mut Context<Editor>,
23165    ) -> Task<Result<bool>> {
23166        self.update(cx, |project, cx| {
23167            project.lsp_store().update(cx, |lsp_store, cx| {
23168                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
23169            })
23170        })
23171    }
23172
23173    fn apply_additional_edits_for_completion(
23174        &self,
23175        buffer: Entity<Buffer>,
23176        completions: Rc<RefCell<Box<[Completion]>>>,
23177        completion_index: usize,
23178        push_to_history: bool,
23179        cx: &mut Context<Editor>,
23180    ) -> Task<Result<Option<language::Transaction>>> {
23181        self.update(cx, |project, cx| {
23182            project.lsp_store().update(cx, |lsp_store, cx| {
23183                lsp_store.apply_additional_edits_for_completion(
23184                    buffer,
23185                    completions,
23186                    completion_index,
23187                    push_to_history,
23188                    cx,
23189                )
23190            })
23191        })
23192    }
23193
23194    fn is_completion_trigger(
23195        &self,
23196        buffer: &Entity<Buffer>,
23197        position: language::Anchor,
23198        text: &str,
23199        trigger_in_words: bool,
23200        menu_is_open: bool,
23201        cx: &mut Context<Editor>,
23202    ) -> bool {
23203        let mut chars = text.chars();
23204        let char = if let Some(char) = chars.next() {
23205            char
23206        } else {
23207            return false;
23208        };
23209        if chars.next().is_some() {
23210            return false;
23211        }
23212
23213        let buffer = buffer.read(cx);
23214        let snapshot = buffer.snapshot();
23215        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
23216            return false;
23217        }
23218        let classifier = snapshot
23219            .char_classifier_at(position)
23220            .scope_context(Some(CharScopeContext::Completion));
23221        if trigger_in_words && classifier.is_word(char) {
23222            return true;
23223        }
23224
23225        buffer.completion_triggers().contains(text)
23226    }
23227}
23228
23229impl SemanticsProvider for Entity<Project> {
23230    fn hover(
23231        &self,
23232        buffer: &Entity<Buffer>,
23233        position: text::Anchor,
23234        cx: &mut App,
23235    ) -> Option<Task<Option<Vec<project::Hover>>>> {
23236        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
23237    }
23238
23239    fn document_highlights(
23240        &self,
23241        buffer: &Entity<Buffer>,
23242        position: text::Anchor,
23243        cx: &mut App,
23244    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
23245        Some(self.update(cx, |project, cx| {
23246            project.document_highlights(buffer, position, cx)
23247        }))
23248    }
23249
23250    fn definitions(
23251        &self,
23252        buffer: &Entity<Buffer>,
23253        position: text::Anchor,
23254        kind: GotoDefinitionKind,
23255        cx: &mut App,
23256    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
23257        Some(self.update(cx, |project, cx| match kind {
23258            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
23259            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
23260            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
23261            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
23262        }))
23263    }
23264
23265    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
23266        self.update(cx, |project, cx| {
23267            if project
23268                .active_debug_session(cx)
23269                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
23270            {
23271                return true;
23272            }
23273
23274            buffer.update(cx, |buffer, cx| {
23275                project.any_language_server_supports_inlay_hints(buffer, cx)
23276            })
23277        })
23278    }
23279
23280    fn inline_values(
23281        &self,
23282        buffer_handle: Entity<Buffer>,
23283        range: Range<text::Anchor>,
23284        cx: &mut App,
23285    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
23286        self.update(cx, |project, cx| {
23287            let (session, active_stack_frame) = project.active_debug_session(cx)?;
23288
23289            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
23290        })
23291    }
23292
23293    fn applicable_inlay_chunks(
23294        &self,
23295        buffer: &Entity<Buffer>,
23296        ranges: &[Range<text::Anchor>],
23297        cx: &mut App,
23298    ) -> Vec<Range<BufferRow>> {
23299        self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
23300            lsp_store.applicable_inlay_chunks(buffer, ranges, cx)
23301        })
23302    }
23303
23304    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App) {
23305        self.read(cx).lsp_store().update(cx, |lsp_store, _| {
23306            lsp_store.invalidate_inlay_hints(for_buffers)
23307        });
23308    }
23309
23310    fn inlay_hints(
23311        &self,
23312        invalidate: InvalidationStrategy,
23313        buffer: Entity<Buffer>,
23314        ranges: Vec<Range<text::Anchor>>,
23315        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
23316        cx: &mut App,
23317    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>> {
23318        Some(self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
23319            lsp_store.inlay_hints(invalidate, buffer, ranges, known_chunks, cx)
23320        }))
23321    }
23322
23323    fn range_for_rename(
23324        &self,
23325        buffer: &Entity<Buffer>,
23326        position: text::Anchor,
23327        cx: &mut App,
23328    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
23329        Some(self.update(cx, |project, cx| {
23330            let buffer = buffer.clone();
23331            let task = project.prepare_rename(buffer.clone(), position, cx);
23332            cx.spawn(async move |_, cx| {
23333                Ok(match task.await? {
23334                    PrepareRenameResponse::Success(range) => Some(range),
23335                    PrepareRenameResponse::InvalidPosition => None,
23336                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
23337                        // Fallback on using TreeSitter info to determine identifier range
23338                        buffer.read_with(cx, |buffer, _| {
23339                            let snapshot = buffer.snapshot();
23340                            let (range, kind) = snapshot.surrounding_word(position, None);
23341                            if kind != Some(CharKind::Word) {
23342                                return None;
23343                            }
23344                            Some(
23345                                snapshot.anchor_before(range.start)
23346                                    ..snapshot.anchor_after(range.end),
23347                            )
23348                        })?
23349                    }
23350                })
23351            })
23352        }))
23353    }
23354
23355    fn perform_rename(
23356        &self,
23357        buffer: &Entity<Buffer>,
23358        position: text::Anchor,
23359        new_name: String,
23360        cx: &mut App,
23361    ) -> Option<Task<Result<ProjectTransaction>>> {
23362        Some(self.update(cx, |project, cx| {
23363            project.perform_rename(buffer.clone(), position, new_name, cx)
23364        }))
23365    }
23366}
23367
23368fn consume_contiguous_rows(
23369    contiguous_row_selections: &mut Vec<Selection<Point>>,
23370    selection: &Selection<Point>,
23371    display_map: &DisplaySnapshot,
23372    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
23373) -> (MultiBufferRow, MultiBufferRow) {
23374    contiguous_row_selections.push(selection.clone());
23375    let start_row = starting_row(selection, display_map);
23376    let mut end_row = ending_row(selection, display_map);
23377
23378    while let Some(next_selection) = selections.peek() {
23379        if next_selection.start.row <= end_row.0 {
23380            end_row = ending_row(next_selection, display_map);
23381            contiguous_row_selections.push(selections.next().unwrap().clone());
23382        } else {
23383            break;
23384        }
23385    }
23386    (start_row, end_row)
23387}
23388
23389fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23390    if selection.start.column > 0 {
23391        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
23392    } else {
23393        MultiBufferRow(selection.start.row)
23394    }
23395}
23396
23397fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23398    if next_selection.end.column > 0 || next_selection.is_empty() {
23399        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
23400    } else {
23401        MultiBufferRow(next_selection.end.row)
23402    }
23403}
23404
23405impl EditorSnapshot {
23406    pub fn remote_selections_in_range<'a>(
23407        &'a self,
23408        range: &'a Range<Anchor>,
23409        collaboration_hub: &dyn CollaborationHub,
23410        cx: &'a App,
23411    ) -> impl 'a + Iterator<Item = RemoteSelection> {
23412        let participant_names = collaboration_hub.user_names(cx);
23413        let participant_indices = collaboration_hub.user_participant_indices(cx);
23414        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
23415        let collaborators_by_replica_id = collaborators_by_peer_id
23416            .values()
23417            .map(|collaborator| (collaborator.replica_id, collaborator))
23418            .collect::<HashMap<_, _>>();
23419        self.buffer_snapshot()
23420            .selections_in_range(range, false)
23421            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
23422                if replica_id == ReplicaId::AGENT {
23423                    Some(RemoteSelection {
23424                        replica_id,
23425                        selection,
23426                        cursor_shape,
23427                        line_mode,
23428                        collaborator_id: CollaboratorId::Agent,
23429                        user_name: Some("Agent".into()),
23430                        color: cx.theme().players().agent(),
23431                    })
23432                } else {
23433                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
23434                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
23435                    let user_name = participant_names.get(&collaborator.user_id).cloned();
23436                    Some(RemoteSelection {
23437                        replica_id,
23438                        selection,
23439                        cursor_shape,
23440                        line_mode,
23441                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
23442                        user_name,
23443                        color: if let Some(index) = participant_index {
23444                            cx.theme().players().color_for_participant(index.0)
23445                        } else {
23446                            cx.theme().players().absent()
23447                        },
23448                    })
23449                }
23450            })
23451    }
23452
23453    pub fn hunks_for_ranges(
23454        &self,
23455        ranges: impl IntoIterator<Item = Range<Point>>,
23456    ) -> Vec<MultiBufferDiffHunk> {
23457        let mut hunks = Vec::new();
23458        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
23459            HashMap::default();
23460        for query_range in ranges {
23461            let query_rows =
23462                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
23463            for hunk in self.buffer_snapshot().diff_hunks_in_range(
23464                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
23465            ) {
23466                // Include deleted hunks that are adjacent to the query range, because
23467                // otherwise they would be missed.
23468                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
23469                if hunk.status().is_deleted() {
23470                    intersects_range |= hunk.row_range.start == query_rows.end;
23471                    intersects_range |= hunk.row_range.end == query_rows.start;
23472                }
23473                if intersects_range {
23474                    if !processed_buffer_rows
23475                        .entry(hunk.buffer_id)
23476                        .or_default()
23477                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
23478                    {
23479                        continue;
23480                    }
23481                    hunks.push(hunk);
23482                }
23483            }
23484        }
23485
23486        hunks
23487    }
23488
23489    fn display_diff_hunks_for_rows<'a>(
23490        &'a self,
23491        display_rows: Range<DisplayRow>,
23492        folded_buffers: &'a HashSet<BufferId>,
23493    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
23494        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
23495        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
23496
23497        self.buffer_snapshot()
23498            .diff_hunks_in_range(buffer_start..buffer_end)
23499            .filter_map(|hunk| {
23500                if folded_buffers.contains(&hunk.buffer_id) {
23501                    return None;
23502                }
23503
23504                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
23505                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
23506
23507                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
23508                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
23509
23510                let display_hunk = if hunk_display_start.column() != 0 {
23511                    DisplayDiffHunk::Folded {
23512                        display_row: hunk_display_start.row(),
23513                    }
23514                } else {
23515                    let mut end_row = hunk_display_end.row();
23516                    if hunk_display_end.column() > 0 {
23517                        end_row.0 += 1;
23518                    }
23519                    let is_created_file = hunk.is_created_file();
23520                    DisplayDiffHunk::Unfolded {
23521                        status: hunk.status(),
23522                        diff_base_byte_range: hunk.diff_base_byte_range,
23523                        display_row_range: hunk_display_start.row()..end_row,
23524                        multi_buffer_range: Anchor::range_in_buffer(
23525                            hunk.excerpt_id,
23526                            hunk.buffer_id,
23527                            hunk.buffer_range,
23528                        ),
23529                        is_created_file,
23530                    }
23531                };
23532
23533                Some(display_hunk)
23534            })
23535    }
23536
23537    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
23538        self.display_snapshot
23539            .buffer_snapshot()
23540            .language_at(position)
23541    }
23542
23543    pub fn is_focused(&self) -> bool {
23544        self.is_focused
23545    }
23546
23547    pub fn placeholder_text(&self) -> Option<String> {
23548        self.placeholder_display_snapshot
23549            .as_ref()
23550            .map(|display_map| display_map.text())
23551    }
23552
23553    pub fn scroll_position(&self) -> gpui::Point<ScrollOffset> {
23554        self.scroll_anchor.scroll_position(&self.display_snapshot)
23555    }
23556
23557    fn gutter_dimensions(
23558        &self,
23559        font_id: FontId,
23560        font_size: Pixels,
23561        max_line_number_width: Pixels,
23562        cx: &App,
23563    ) -> Option<GutterDimensions> {
23564        if !self.show_gutter {
23565            return None;
23566        }
23567
23568        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
23569        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
23570
23571        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
23572            matches!(
23573                ProjectSettings::get_global(cx).git.git_gutter,
23574                GitGutterSetting::TrackedFiles
23575            )
23576        });
23577        let gutter_settings = EditorSettings::get_global(cx).gutter;
23578        let show_line_numbers = self
23579            .show_line_numbers
23580            .unwrap_or(gutter_settings.line_numbers);
23581        let line_gutter_width = if show_line_numbers {
23582            // Avoid flicker-like gutter resizes when the line number gains another digit by
23583            // only resizing the gutter on files with > 10**min_line_number_digits lines.
23584            let min_width_for_number_on_gutter =
23585                ch_advance * gutter_settings.min_line_number_digits as f32;
23586            max_line_number_width.max(min_width_for_number_on_gutter)
23587        } else {
23588            0.0.into()
23589        };
23590
23591        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
23592        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
23593
23594        let git_blame_entries_width =
23595            self.git_blame_gutter_max_author_length
23596                .map(|max_author_length| {
23597                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
23598                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
23599
23600                    /// The number of characters to dedicate to gaps and margins.
23601                    const SPACING_WIDTH: usize = 4;
23602
23603                    let max_char_count = max_author_length.min(renderer.max_author_length())
23604                        + ::git::SHORT_SHA_LENGTH
23605                        + MAX_RELATIVE_TIMESTAMP.len()
23606                        + SPACING_WIDTH;
23607
23608                    ch_advance * max_char_count
23609                });
23610
23611        let is_singleton = self.buffer_snapshot().is_singleton();
23612
23613        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
23614        left_padding += if !is_singleton {
23615            ch_width * 4.0
23616        } else if show_runnables || show_breakpoints {
23617            ch_width * 3.0
23618        } else if show_git_gutter && show_line_numbers {
23619            ch_width * 2.0
23620        } else if show_git_gutter || show_line_numbers {
23621            ch_width
23622        } else {
23623            px(0.)
23624        };
23625
23626        let shows_folds = is_singleton && gutter_settings.folds;
23627
23628        let right_padding = if shows_folds && show_line_numbers {
23629            ch_width * 4.0
23630        } else if shows_folds || (!is_singleton && show_line_numbers) {
23631            ch_width * 3.0
23632        } else if show_line_numbers {
23633            ch_width
23634        } else {
23635            px(0.)
23636        };
23637
23638        Some(GutterDimensions {
23639            left_padding,
23640            right_padding,
23641            width: line_gutter_width + left_padding + right_padding,
23642            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
23643            git_blame_entries_width,
23644        })
23645    }
23646
23647    pub fn render_crease_toggle(
23648        &self,
23649        buffer_row: MultiBufferRow,
23650        row_contains_cursor: bool,
23651        editor: Entity<Editor>,
23652        window: &mut Window,
23653        cx: &mut App,
23654    ) -> Option<AnyElement> {
23655        let folded = self.is_line_folded(buffer_row);
23656        let mut is_foldable = false;
23657
23658        if let Some(crease) = self
23659            .crease_snapshot
23660            .query_row(buffer_row, self.buffer_snapshot())
23661        {
23662            is_foldable = true;
23663            match crease {
23664                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
23665                    if let Some(render_toggle) = render_toggle {
23666                        let toggle_callback =
23667                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
23668                                if folded {
23669                                    editor.update(cx, |editor, cx| {
23670                                        editor.fold_at(buffer_row, window, cx)
23671                                    });
23672                                } else {
23673                                    editor.update(cx, |editor, cx| {
23674                                        editor.unfold_at(buffer_row, window, cx)
23675                                    });
23676                                }
23677                            });
23678                        return Some((render_toggle)(
23679                            buffer_row,
23680                            folded,
23681                            toggle_callback,
23682                            window,
23683                            cx,
23684                        ));
23685                    }
23686                }
23687            }
23688        }
23689
23690        is_foldable |= self.starts_indent(buffer_row);
23691
23692        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
23693            Some(
23694                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
23695                    .toggle_state(folded)
23696                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
23697                        if folded {
23698                            this.unfold_at(buffer_row, window, cx);
23699                        } else {
23700                            this.fold_at(buffer_row, window, cx);
23701                        }
23702                    }))
23703                    .into_any_element(),
23704            )
23705        } else {
23706            None
23707        }
23708    }
23709
23710    pub fn render_crease_trailer(
23711        &self,
23712        buffer_row: MultiBufferRow,
23713        window: &mut Window,
23714        cx: &mut App,
23715    ) -> Option<AnyElement> {
23716        let folded = self.is_line_folded(buffer_row);
23717        if let Crease::Inline { render_trailer, .. } = self
23718            .crease_snapshot
23719            .query_row(buffer_row, self.buffer_snapshot())?
23720        {
23721            let render_trailer = render_trailer.as_ref()?;
23722            Some(render_trailer(buffer_row, folded, window, cx))
23723        } else {
23724            None
23725        }
23726    }
23727}
23728
23729impl Deref for EditorSnapshot {
23730    type Target = DisplaySnapshot;
23731
23732    fn deref(&self) -> &Self::Target {
23733        &self.display_snapshot
23734    }
23735}
23736
23737#[derive(Clone, Debug, PartialEq, Eq)]
23738pub enum EditorEvent {
23739    InputIgnored {
23740        text: Arc<str>,
23741    },
23742    InputHandled {
23743        utf16_range_to_replace: Option<Range<isize>>,
23744        text: Arc<str>,
23745    },
23746    ExcerptsAdded {
23747        buffer: Entity<Buffer>,
23748        predecessor: ExcerptId,
23749        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
23750    },
23751    ExcerptsRemoved {
23752        ids: Vec<ExcerptId>,
23753        removed_buffer_ids: Vec<BufferId>,
23754    },
23755    BufferFoldToggled {
23756        ids: Vec<ExcerptId>,
23757        folded: bool,
23758    },
23759    ExcerptsEdited {
23760        ids: Vec<ExcerptId>,
23761    },
23762    ExcerptsExpanded {
23763        ids: Vec<ExcerptId>,
23764    },
23765    BufferEdited,
23766    Edited {
23767        transaction_id: clock::Lamport,
23768    },
23769    Reparsed(BufferId),
23770    Focused,
23771    FocusedIn,
23772    Blurred,
23773    DirtyChanged,
23774    Saved,
23775    TitleChanged,
23776    SelectionsChanged {
23777        local: bool,
23778    },
23779    ScrollPositionChanged {
23780        local: bool,
23781        autoscroll: bool,
23782    },
23783    TransactionUndone {
23784        transaction_id: clock::Lamport,
23785    },
23786    TransactionBegun {
23787        transaction_id: clock::Lamport,
23788    },
23789    CursorShapeChanged,
23790    BreadcrumbsChanged,
23791    PushedToNavHistory {
23792        anchor: Anchor,
23793        is_deactivate: bool,
23794    },
23795}
23796
23797impl EventEmitter<EditorEvent> for Editor {}
23798
23799impl Focusable for Editor {
23800    fn focus_handle(&self, _cx: &App) -> FocusHandle {
23801        self.focus_handle.clone()
23802    }
23803}
23804
23805impl Render for Editor {
23806    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23807        let settings = ThemeSettings::get_global(cx);
23808
23809        let mut text_style = match self.mode {
23810            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
23811                color: cx.theme().colors().editor_foreground,
23812                font_family: settings.ui_font.family.clone(),
23813                font_features: settings.ui_font.features.clone(),
23814                font_fallbacks: settings.ui_font.fallbacks.clone(),
23815                font_size: rems(0.875).into(),
23816                font_weight: settings.ui_font.weight,
23817                line_height: relative(settings.buffer_line_height.value()),
23818                ..Default::default()
23819            },
23820            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
23821                color: cx.theme().colors().editor_foreground,
23822                font_family: settings.buffer_font.family.clone(),
23823                font_features: settings.buffer_font.features.clone(),
23824                font_fallbacks: settings.buffer_font.fallbacks.clone(),
23825                font_size: settings.buffer_font_size(cx).into(),
23826                font_weight: settings.buffer_font.weight,
23827                line_height: relative(settings.buffer_line_height.value()),
23828                ..Default::default()
23829            },
23830        };
23831        if let Some(text_style_refinement) = &self.text_style_refinement {
23832            text_style.refine(text_style_refinement)
23833        }
23834
23835        let background = match self.mode {
23836            EditorMode::SingleLine => cx.theme().system().transparent,
23837            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
23838            EditorMode::Full { .. } => cx.theme().colors().editor_background,
23839            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
23840        };
23841
23842        EditorElement::new(
23843            &cx.entity(),
23844            EditorStyle {
23845                background,
23846                border: cx.theme().colors().border,
23847                local_player: cx.theme().players().local(),
23848                text: text_style,
23849                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
23850                syntax: cx.theme().syntax().clone(),
23851                status: cx.theme().status().clone(),
23852                inlay_hints_style: make_inlay_hints_style(cx),
23853                edit_prediction_styles: make_suggestion_styles(cx),
23854                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
23855                show_underlines: self.diagnostics_enabled(),
23856            },
23857        )
23858    }
23859}
23860
23861impl EntityInputHandler for Editor {
23862    fn text_for_range(
23863        &mut self,
23864        range_utf16: Range<usize>,
23865        adjusted_range: &mut Option<Range<usize>>,
23866        _: &mut Window,
23867        cx: &mut Context<Self>,
23868    ) -> Option<String> {
23869        let snapshot = self.buffer.read(cx).read(cx);
23870        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
23871        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
23872        if (start.0..end.0) != range_utf16 {
23873            adjusted_range.replace(start.0..end.0);
23874        }
23875        Some(snapshot.text_for_range(start..end).collect())
23876    }
23877
23878    fn selected_text_range(
23879        &mut self,
23880        ignore_disabled_input: bool,
23881        _: &mut Window,
23882        cx: &mut Context<Self>,
23883    ) -> Option<UTF16Selection> {
23884        // Prevent the IME menu from appearing when holding down an alphabetic key
23885        // while input is disabled.
23886        if !ignore_disabled_input && !self.input_enabled {
23887            return None;
23888        }
23889
23890        let selection = self
23891            .selections
23892            .newest::<OffsetUtf16>(&self.display_snapshot(cx));
23893        let range = selection.range();
23894
23895        Some(UTF16Selection {
23896            range: range.start.0..range.end.0,
23897            reversed: selection.reversed,
23898        })
23899    }
23900
23901    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
23902        let snapshot = self.buffer.read(cx).read(cx);
23903        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
23904        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
23905    }
23906
23907    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
23908        self.clear_highlights::<InputComposition>(cx);
23909        self.ime_transaction.take();
23910    }
23911
23912    fn replace_text_in_range(
23913        &mut self,
23914        range_utf16: Option<Range<usize>>,
23915        text: &str,
23916        window: &mut Window,
23917        cx: &mut Context<Self>,
23918    ) {
23919        if !self.input_enabled {
23920            cx.emit(EditorEvent::InputIgnored { text: text.into() });
23921            return;
23922        }
23923
23924        self.transact(window, cx, |this, window, cx| {
23925            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
23926                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23927                Some(this.selection_replacement_ranges(range_utf16, cx))
23928            } else {
23929                this.marked_text_ranges(cx)
23930            };
23931
23932            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
23933                let newest_selection_id = this.selections.newest_anchor().id;
23934                this.selections
23935                    .all::<OffsetUtf16>(&this.display_snapshot(cx))
23936                    .iter()
23937                    .zip(ranges_to_replace.iter())
23938                    .find_map(|(selection, range)| {
23939                        if selection.id == newest_selection_id {
23940                            Some(
23941                                (range.start.0 as isize - selection.head().0 as isize)
23942                                    ..(range.end.0 as isize - selection.head().0 as isize),
23943                            )
23944                        } else {
23945                            None
23946                        }
23947                    })
23948            });
23949
23950            cx.emit(EditorEvent::InputHandled {
23951                utf16_range_to_replace: range_to_replace,
23952                text: text.into(),
23953            });
23954
23955            if let Some(new_selected_ranges) = new_selected_ranges {
23956                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23957                    selections.select_ranges(new_selected_ranges)
23958                });
23959                this.backspace(&Default::default(), window, cx);
23960            }
23961
23962            this.handle_input(text, window, cx);
23963        });
23964
23965        if let Some(transaction) = self.ime_transaction {
23966            self.buffer.update(cx, |buffer, cx| {
23967                buffer.group_until_transaction(transaction, cx);
23968            });
23969        }
23970
23971        self.unmark_text(window, cx);
23972    }
23973
23974    fn replace_and_mark_text_in_range(
23975        &mut self,
23976        range_utf16: Option<Range<usize>>,
23977        text: &str,
23978        new_selected_range_utf16: Option<Range<usize>>,
23979        window: &mut Window,
23980        cx: &mut Context<Self>,
23981    ) {
23982        if !self.input_enabled {
23983            return;
23984        }
23985
23986        let transaction = self.transact(window, cx, |this, window, cx| {
23987            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
23988                let snapshot = this.buffer.read(cx).read(cx);
23989                if let Some(relative_range_utf16) = range_utf16.as_ref() {
23990                    for marked_range in &mut marked_ranges {
23991                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
23992                        marked_range.start.0 += relative_range_utf16.start;
23993                        marked_range.start =
23994                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
23995                        marked_range.end =
23996                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
23997                    }
23998                }
23999                Some(marked_ranges)
24000            } else if let Some(range_utf16) = range_utf16 {
24001                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
24002                Some(this.selection_replacement_ranges(range_utf16, cx))
24003            } else {
24004                None
24005            };
24006
24007            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
24008                let newest_selection_id = this.selections.newest_anchor().id;
24009                this.selections
24010                    .all::<OffsetUtf16>(&this.display_snapshot(cx))
24011                    .iter()
24012                    .zip(ranges_to_replace.iter())
24013                    .find_map(|(selection, range)| {
24014                        if selection.id == newest_selection_id {
24015                            Some(
24016                                (range.start.0 as isize - selection.head().0 as isize)
24017                                    ..(range.end.0 as isize - selection.head().0 as isize),
24018                            )
24019                        } else {
24020                            None
24021                        }
24022                    })
24023            });
24024
24025            cx.emit(EditorEvent::InputHandled {
24026                utf16_range_to_replace: range_to_replace,
24027                text: text.into(),
24028            });
24029
24030            if let Some(ranges) = ranges_to_replace {
24031                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
24032                    s.select_ranges(ranges)
24033                });
24034            }
24035
24036            let marked_ranges = {
24037                let snapshot = this.buffer.read(cx).read(cx);
24038                this.selections
24039                    .disjoint_anchors_arc()
24040                    .iter()
24041                    .map(|selection| {
24042                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
24043                    })
24044                    .collect::<Vec<_>>()
24045            };
24046
24047            if text.is_empty() {
24048                this.unmark_text(window, cx);
24049            } else {
24050                this.highlight_text::<InputComposition>(
24051                    marked_ranges.clone(),
24052                    HighlightStyle {
24053                        underline: Some(UnderlineStyle {
24054                            thickness: px(1.),
24055                            color: None,
24056                            wavy: false,
24057                        }),
24058                        ..Default::default()
24059                    },
24060                    cx,
24061                );
24062            }
24063
24064            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
24065            let use_autoclose = this.use_autoclose;
24066            let use_auto_surround = this.use_auto_surround;
24067            this.set_use_autoclose(false);
24068            this.set_use_auto_surround(false);
24069            this.handle_input(text, window, cx);
24070            this.set_use_autoclose(use_autoclose);
24071            this.set_use_auto_surround(use_auto_surround);
24072
24073            if let Some(new_selected_range) = new_selected_range_utf16 {
24074                let snapshot = this.buffer.read(cx).read(cx);
24075                let new_selected_ranges = marked_ranges
24076                    .into_iter()
24077                    .map(|marked_range| {
24078                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
24079                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
24080                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
24081                        snapshot.clip_offset_utf16(new_start, Bias::Left)
24082                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
24083                    })
24084                    .collect::<Vec<_>>();
24085
24086                drop(snapshot);
24087                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
24088                    selections.select_ranges(new_selected_ranges)
24089                });
24090            }
24091        });
24092
24093        self.ime_transaction = self.ime_transaction.or(transaction);
24094        if let Some(transaction) = self.ime_transaction {
24095            self.buffer.update(cx, |buffer, cx| {
24096                buffer.group_until_transaction(transaction, cx);
24097            });
24098        }
24099
24100        if self.text_highlights::<InputComposition>(cx).is_none() {
24101            self.ime_transaction.take();
24102        }
24103    }
24104
24105    fn bounds_for_range(
24106        &mut self,
24107        range_utf16: Range<usize>,
24108        element_bounds: gpui::Bounds<Pixels>,
24109        window: &mut Window,
24110        cx: &mut Context<Self>,
24111    ) -> Option<gpui::Bounds<Pixels>> {
24112        let text_layout_details = self.text_layout_details(window);
24113        let CharacterDimensions {
24114            em_width,
24115            em_advance,
24116            line_height,
24117        } = self.character_dimensions(window);
24118
24119        let snapshot = self.snapshot(window, cx);
24120        let scroll_position = snapshot.scroll_position();
24121        let scroll_left = scroll_position.x * ScrollOffset::from(em_advance);
24122
24123        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
24124        let x = Pixels::from(
24125            ScrollOffset::from(
24126                snapshot.x_for_display_point(start, &text_layout_details)
24127                    + self.gutter_dimensions.full_width(),
24128            ) - scroll_left,
24129        );
24130        let y = line_height * (start.row().as_f64() - scroll_position.y) as f32;
24131
24132        Some(Bounds {
24133            origin: element_bounds.origin + point(x, y),
24134            size: size(em_width, line_height),
24135        })
24136    }
24137
24138    fn character_index_for_point(
24139        &mut self,
24140        point: gpui::Point<Pixels>,
24141        _window: &mut Window,
24142        _cx: &mut Context<Self>,
24143    ) -> Option<usize> {
24144        let position_map = self.last_position_map.as_ref()?;
24145        if !position_map.text_hitbox.contains(&point) {
24146            return None;
24147        }
24148        let display_point = position_map.point_for_position(point).previous_valid;
24149        let anchor = position_map
24150            .snapshot
24151            .display_point_to_anchor(display_point, Bias::Left);
24152        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot());
24153        Some(utf16_offset.0)
24154    }
24155}
24156
24157trait SelectionExt {
24158    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
24159    fn spanned_rows(
24160        &self,
24161        include_end_if_at_line_start: bool,
24162        map: &DisplaySnapshot,
24163    ) -> Range<MultiBufferRow>;
24164}
24165
24166impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
24167    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
24168        let start = self
24169            .start
24170            .to_point(map.buffer_snapshot())
24171            .to_display_point(map);
24172        let end = self
24173            .end
24174            .to_point(map.buffer_snapshot())
24175            .to_display_point(map);
24176        if self.reversed {
24177            end..start
24178        } else {
24179            start..end
24180        }
24181    }
24182
24183    fn spanned_rows(
24184        &self,
24185        include_end_if_at_line_start: bool,
24186        map: &DisplaySnapshot,
24187    ) -> Range<MultiBufferRow> {
24188        let start = self.start.to_point(map.buffer_snapshot());
24189        let mut end = self.end.to_point(map.buffer_snapshot());
24190        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
24191            end.row -= 1;
24192        }
24193
24194        let buffer_start = map.prev_line_boundary(start).0;
24195        let buffer_end = map.next_line_boundary(end).0;
24196        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
24197    }
24198}
24199
24200impl<T: InvalidationRegion> InvalidationStack<T> {
24201    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
24202    where
24203        S: Clone + ToOffset,
24204    {
24205        while let Some(region) = self.last() {
24206            let all_selections_inside_invalidation_ranges =
24207                if selections.len() == region.ranges().len() {
24208                    selections
24209                        .iter()
24210                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
24211                        .all(|(selection, invalidation_range)| {
24212                            let head = selection.head().to_offset(buffer);
24213                            invalidation_range.start <= head && invalidation_range.end >= head
24214                        })
24215                } else {
24216                    false
24217                };
24218
24219            if all_selections_inside_invalidation_ranges {
24220                break;
24221            } else {
24222                self.pop();
24223            }
24224        }
24225    }
24226}
24227
24228impl<T> Default for InvalidationStack<T> {
24229    fn default() -> Self {
24230        Self(Default::default())
24231    }
24232}
24233
24234impl<T> Deref for InvalidationStack<T> {
24235    type Target = Vec<T>;
24236
24237    fn deref(&self) -> &Self::Target {
24238        &self.0
24239    }
24240}
24241
24242impl<T> DerefMut for InvalidationStack<T> {
24243    fn deref_mut(&mut self) -> &mut Self::Target {
24244        &mut self.0
24245    }
24246}
24247
24248impl InvalidationRegion for SnippetState {
24249    fn ranges(&self) -> &[Range<Anchor>] {
24250        &self.ranges[self.active_index]
24251    }
24252}
24253
24254fn edit_prediction_edit_text(
24255    current_snapshot: &BufferSnapshot,
24256    edits: &[(Range<Anchor>, String)],
24257    edit_preview: &EditPreview,
24258    include_deletions: bool,
24259    cx: &App,
24260) -> HighlightedText {
24261    let edits = edits
24262        .iter()
24263        .map(|(anchor, text)| {
24264            (
24265                anchor.start.text_anchor..anchor.end.text_anchor,
24266                text.clone(),
24267            )
24268        })
24269        .collect::<Vec<_>>();
24270
24271    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
24272}
24273
24274fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, String)], cx: &App) -> HighlightedText {
24275    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
24276    // Just show the raw edit text with basic styling
24277    let mut text = String::new();
24278    let mut highlights = Vec::new();
24279
24280    let insertion_highlight_style = HighlightStyle {
24281        color: Some(cx.theme().colors().text),
24282        ..Default::default()
24283    };
24284
24285    for (_, edit_text) in edits {
24286        let start_offset = text.len();
24287        text.push_str(edit_text);
24288        let end_offset = text.len();
24289
24290        if start_offset < end_offset {
24291            highlights.push((start_offset..end_offset, insertion_highlight_style));
24292        }
24293    }
24294
24295    HighlightedText {
24296        text: text.into(),
24297        highlights,
24298    }
24299}
24300
24301pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
24302    match severity {
24303        lsp::DiagnosticSeverity::ERROR => colors.error,
24304        lsp::DiagnosticSeverity::WARNING => colors.warning,
24305        lsp::DiagnosticSeverity::INFORMATION => colors.info,
24306        lsp::DiagnosticSeverity::HINT => colors.info,
24307        _ => colors.ignored,
24308    }
24309}
24310
24311pub fn styled_runs_for_code_label<'a>(
24312    label: &'a CodeLabel,
24313    syntax_theme: &'a theme::SyntaxTheme,
24314) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
24315    let fade_out = HighlightStyle {
24316        fade_out: Some(0.35),
24317        ..Default::default()
24318    };
24319
24320    let mut prev_end = label.filter_range.end;
24321    label
24322        .runs
24323        .iter()
24324        .enumerate()
24325        .flat_map(move |(ix, (range, highlight_id))| {
24326            let style = if let Some(style) = highlight_id.style(syntax_theme) {
24327                style
24328            } else {
24329                return Default::default();
24330            };
24331            let muted_style = style.highlight(fade_out);
24332
24333            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
24334            if range.start >= label.filter_range.end {
24335                if range.start > prev_end {
24336                    runs.push((prev_end..range.start, fade_out));
24337                }
24338                runs.push((range.clone(), muted_style));
24339            } else if range.end <= label.filter_range.end {
24340                runs.push((range.clone(), style));
24341            } else {
24342                runs.push((range.start..label.filter_range.end, style));
24343                runs.push((label.filter_range.end..range.end, muted_style));
24344            }
24345            prev_end = cmp::max(prev_end, range.end);
24346
24347            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
24348                runs.push((prev_end..label.text.len(), fade_out));
24349            }
24350
24351            runs
24352        })
24353}
24354
24355pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
24356    let mut prev_index = 0;
24357    let mut prev_codepoint: Option<char> = None;
24358    text.char_indices()
24359        .chain([(text.len(), '\0')])
24360        .filter_map(move |(index, codepoint)| {
24361            let prev_codepoint = prev_codepoint.replace(codepoint)?;
24362            let is_boundary = index == text.len()
24363                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
24364                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
24365            if is_boundary {
24366                let chunk = &text[prev_index..index];
24367                prev_index = index;
24368                Some(chunk)
24369            } else {
24370                None
24371            }
24372        })
24373}
24374
24375pub trait RangeToAnchorExt: Sized {
24376    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
24377
24378    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
24379        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot());
24380        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
24381    }
24382}
24383
24384impl<T: ToOffset> RangeToAnchorExt for Range<T> {
24385    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
24386        let start_offset = self.start.to_offset(snapshot);
24387        let end_offset = self.end.to_offset(snapshot);
24388        if start_offset == end_offset {
24389            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
24390        } else {
24391            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
24392        }
24393    }
24394}
24395
24396pub trait RowExt {
24397    fn as_f64(&self) -> f64;
24398
24399    fn next_row(&self) -> Self;
24400
24401    fn previous_row(&self) -> Self;
24402
24403    fn minus(&self, other: Self) -> u32;
24404}
24405
24406impl RowExt for DisplayRow {
24407    fn as_f64(&self) -> f64 {
24408        self.0 as _
24409    }
24410
24411    fn next_row(&self) -> Self {
24412        Self(self.0 + 1)
24413    }
24414
24415    fn previous_row(&self) -> Self {
24416        Self(self.0.saturating_sub(1))
24417    }
24418
24419    fn minus(&self, other: Self) -> u32 {
24420        self.0 - other.0
24421    }
24422}
24423
24424impl RowExt for MultiBufferRow {
24425    fn as_f64(&self) -> f64 {
24426        self.0 as _
24427    }
24428
24429    fn next_row(&self) -> Self {
24430        Self(self.0 + 1)
24431    }
24432
24433    fn previous_row(&self) -> Self {
24434        Self(self.0.saturating_sub(1))
24435    }
24436
24437    fn minus(&self, other: Self) -> u32 {
24438        self.0 - other.0
24439    }
24440}
24441
24442trait RowRangeExt {
24443    type Row;
24444
24445    fn len(&self) -> usize;
24446
24447    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
24448}
24449
24450impl RowRangeExt for Range<MultiBufferRow> {
24451    type Row = MultiBufferRow;
24452
24453    fn len(&self) -> usize {
24454        (self.end.0 - self.start.0) as usize
24455    }
24456
24457    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
24458        (self.start.0..self.end.0).map(MultiBufferRow)
24459    }
24460}
24461
24462impl RowRangeExt for Range<DisplayRow> {
24463    type Row = DisplayRow;
24464
24465    fn len(&self) -> usize {
24466        (self.end.0 - self.start.0) as usize
24467    }
24468
24469    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
24470        (self.start.0..self.end.0).map(DisplayRow)
24471    }
24472}
24473
24474/// If select range has more than one line, we
24475/// just point the cursor to range.start.
24476fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
24477    if range.start.row == range.end.row {
24478        range
24479    } else {
24480        range.start..range.start
24481    }
24482}
24483pub struct KillRing(ClipboardItem);
24484impl Global for KillRing {}
24485
24486const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
24487
24488enum BreakpointPromptEditAction {
24489    Log,
24490    Condition,
24491    HitCondition,
24492}
24493
24494struct BreakpointPromptEditor {
24495    pub(crate) prompt: Entity<Editor>,
24496    editor: WeakEntity<Editor>,
24497    breakpoint_anchor: Anchor,
24498    breakpoint: Breakpoint,
24499    edit_action: BreakpointPromptEditAction,
24500    block_ids: HashSet<CustomBlockId>,
24501    editor_margins: Arc<Mutex<EditorMargins>>,
24502    _subscriptions: Vec<Subscription>,
24503}
24504
24505impl BreakpointPromptEditor {
24506    const MAX_LINES: u8 = 4;
24507
24508    fn new(
24509        editor: WeakEntity<Editor>,
24510        breakpoint_anchor: Anchor,
24511        breakpoint: Breakpoint,
24512        edit_action: BreakpointPromptEditAction,
24513        window: &mut Window,
24514        cx: &mut Context<Self>,
24515    ) -> Self {
24516        let base_text = match edit_action {
24517            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
24518            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
24519            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
24520        }
24521        .map(|msg| msg.to_string())
24522        .unwrap_or_default();
24523
24524        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
24525        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
24526
24527        let prompt = cx.new(|cx| {
24528            let mut prompt = Editor::new(
24529                EditorMode::AutoHeight {
24530                    min_lines: 1,
24531                    max_lines: Some(Self::MAX_LINES as usize),
24532                },
24533                buffer,
24534                None,
24535                window,
24536                cx,
24537            );
24538            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
24539            prompt.set_show_cursor_when_unfocused(false, cx);
24540            prompt.set_placeholder_text(
24541                match edit_action {
24542                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
24543                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
24544                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
24545                },
24546                window,
24547                cx,
24548            );
24549
24550            prompt
24551        });
24552
24553        Self {
24554            prompt,
24555            editor,
24556            breakpoint_anchor,
24557            breakpoint,
24558            edit_action,
24559            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
24560            block_ids: Default::default(),
24561            _subscriptions: vec![],
24562        }
24563    }
24564
24565    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
24566        self.block_ids.extend(block_ids)
24567    }
24568
24569    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
24570        if let Some(editor) = self.editor.upgrade() {
24571            let message = self
24572                .prompt
24573                .read(cx)
24574                .buffer
24575                .read(cx)
24576                .as_singleton()
24577                .expect("A multi buffer in breakpoint prompt isn't possible")
24578                .read(cx)
24579                .as_rope()
24580                .to_string();
24581
24582            editor.update(cx, |editor, cx| {
24583                editor.edit_breakpoint_at_anchor(
24584                    self.breakpoint_anchor,
24585                    self.breakpoint.clone(),
24586                    match self.edit_action {
24587                        BreakpointPromptEditAction::Log => {
24588                            BreakpointEditAction::EditLogMessage(message.into())
24589                        }
24590                        BreakpointPromptEditAction::Condition => {
24591                            BreakpointEditAction::EditCondition(message.into())
24592                        }
24593                        BreakpointPromptEditAction::HitCondition => {
24594                            BreakpointEditAction::EditHitCondition(message.into())
24595                        }
24596                    },
24597                    cx,
24598                );
24599
24600                editor.remove_blocks(self.block_ids.clone(), None, cx);
24601                cx.focus_self(window);
24602            });
24603        }
24604    }
24605
24606    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
24607        self.editor
24608            .update(cx, |editor, cx| {
24609                editor.remove_blocks(self.block_ids.clone(), None, cx);
24610                window.focus(&editor.focus_handle);
24611            })
24612            .log_err();
24613    }
24614
24615    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
24616        let settings = ThemeSettings::get_global(cx);
24617        let text_style = TextStyle {
24618            color: if self.prompt.read(cx).read_only(cx) {
24619                cx.theme().colors().text_disabled
24620            } else {
24621                cx.theme().colors().text
24622            },
24623            font_family: settings.buffer_font.family.clone(),
24624            font_fallbacks: settings.buffer_font.fallbacks.clone(),
24625            font_size: settings.buffer_font_size(cx).into(),
24626            font_weight: settings.buffer_font.weight,
24627            line_height: relative(settings.buffer_line_height.value()),
24628            ..Default::default()
24629        };
24630        EditorElement::new(
24631            &self.prompt,
24632            EditorStyle {
24633                background: cx.theme().colors().editor_background,
24634                local_player: cx.theme().players().local(),
24635                text: text_style,
24636                ..Default::default()
24637            },
24638        )
24639    }
24640}
24641
24642impl Render for BreakpointPromptEditor {
24643    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24644        let editor_margins = *self.editor_margins.lock();
24645        let gutter_dimensions = editor_margins.gutter;
24646        h_flex()
24647            .key_context("Editor")
24648            .bg(cx.theme().colors().editor_background)
24649            .border_y_1()
24650            .border_color(cx.theme().status().info_border)
24651            .size_full()
24652            .py(window.line_height() / 2.5)
24653            .on_action(cx.listener(Self::confirm))
24654            .on_action(cx.listener(Self::cancel))
24655            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
24656            .child(div().flex_1().child(self.render_prompt_editor(cx)))
24657    }
24658}
24659
24660impl Focusable for BreakpointPromptEditor {
24661    fn focus_handle(&self, cx: &App) -> FocusHandle {
24662        self.prompt.focus_handle(cx)
24663    }
24664}
24665
24666fn all_edits_insertions_or_deletions(
24667    edits: &Vec<(Range<Anchor>, String)>,
24668    snapshot: &MultiBufferSnapshot,
24669) -> bool {
24670    let mut all_insertions = true;
24671    let mut all_deletions = true;
24672
24673    for (range, new_text) in edits.iter() {
24674        let range_is_empty = range.to_offset(snapshot).is_empty();
24675        let text_is_empty = new_text.is_empty();
24676
24677        if range_is_empty != text_is_empty {
24678            if range_is_empty {
24679                all_deletions = false;
24680            } else {
24681                all_insertions = false;
24682            }
24683        } else {
24684            return false;
24685        }
24686
24687        if !all_insertions && !all_deletions {
24688            return false;
24689        }
24690    }
24691    all_insertions || all_deletions
24692}
24693
24694struct MissingEditPredictionKeybindingTooltip;
24695
24696impl Render for MissingEditPredictionKeybindingTooltip {
24697    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24698        ui::tooltip_container(cx, |container, cx| {
24699            container
24700                .flex_shrink_0()
24701                .max_w_80()
24702                .min_h(rems_from_px(124.))
24703                .justify_between()
24704                .child(
24705                    v_flex()
24706                        .flex_1()
24707                        .text_ui_sm(cx)
24708                        .child(Label::new("Conflict with Accept Keybinding"))
24709                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
24710                )
24711                .child(
24712                    h_flex()
24713                        .pb_1()
24714                        .gap_1()
24715                        .items_end()
24716                        .w_full()
24717                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
24718                            window.dispatch_action(zed_actions::OpenKeymapFile.boxed_clone(), cx)
24719                        }))
24720                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
24721                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
24722                        })),
24723                )
24724        })
24725    }
24726}
24727
24728#[derive(Debug, Clone, Copy, PartialEq)]
24729pub struct LineHighlight {
24730    pub background: Background,
24731    pub border: Option<gpui::Hsla>,
24732    pub include_gutter: bool,
24733    pub type_id: Option<TypeId>,
24734}
24735
24736struct LineManipulationResult {
24737    pub new_text: String,
24738    pub line_count_before: usize,
24739    pub line_count_after: usize,
24740}
24741
24742fn render_diff_hunk_controls(
24743    row: u32,
24744    status: &DiffHunkStatus,
24745    hunk_range: Range<Anchor>,
24746    is_created_file: bool,
24747    line_height: Pixels,
24748    editor: &Entity<Editor>,
24749    _window: &mut Window,
24750    cx: &mut App,
24751) -> AnyElement {
24752    h_flex()
24753        .h(line_height)
24754        .mr_1()
24755        .gap_1()
24756        .px_0p5()
24757        .pb_1()
24758        .border_x_1()
24759        .border_b_1()
24760        .border_color(cx.theme().colors().border_variant)
24761        .rounded_b_lg()
24762        .bg(cx.theme().colors().editor_background)
24763        .gap_1()
24764        .block_mouse_except_scroll()
24765        .shadow_md()
24766        .child(if status.has_secondary_hunk() {
24767            Button::new(("stage", row as u64), "Stage")
24768                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24769                .tooltip({
24770                    let focus_handle = editor.focus_handle(cx);
24771                    move |_window, cx| {
24772                        Tooltip::for_action_in(
24773                            "Stage Hunk",
24774                            &::git::ToggleStaged,
24775                            &focus_handle,
24776                            cx,
24777                        )
24778                    }
24779                })
24780                .on_click({
24781                    let editor = editor.clone();
24782                    move |_event, _window, cx| {
24783                        editor.update(cx, |editor, cx| {
24784                            editor.stage_or_unstage_diff_hunks(
24785                                true,
24786                                vec![hunk_range.start..hunk_range.start],
24787                                cx,
24788                            );
24789                        });
24790                    }
24791                })
24792        } else {
24793            Button::new(("unstage", row as u64), "Unstage")
24794                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24795                .tooltip({
24796                    let focus_handle = editor.focus_handle(cx);
24797                    move |_window, cx| {
24798                        Tooltip::for_action_in(
24799                            "Unstage Hunk",
24800                            &::git::ToggleStaged,
24801                            &focus_handle,
24802                            cx,
24803                        )
24804                    }
24805                })
24806                .on_click({
24807                    let editor = editor.clone();
24808                    move |_event, _window, cx| {
24809                        editor.update(cx, |editor, cx| {
24810                            editor.stage_or_unstage_diff_hunks(
24811                                false,
24812                                vec![hunk_range.start..hunk_range.start],
24813                                cx,
24814                            );
24815                        });
24816                    }
24817                })
24818        })
24819        .child(
24820            Button::new(("restore", row as u64), "Restore")
24821                .tooltip({
24822                    let focus_handle = editor.focus_handle(cx);
24823                    move |_window, cx| {
24824                        Tooltip::for_action_in("Restore Hunk", &::git::Restore, &focus_handle, cx)
24825                    }
24826                })
24827                .on_click({
24828                    let editor = editor.clone();
24829                    move |_event, window, cx| {
24830                        editor.update(cx, |editor, cx| {
24831                            let snapshot = editor.snapshot(window, cx);
24832                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot());
24833                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
24834                        });
24835                    }
24836                })
24837                .disabled(is_created_file),
24838        )
24839        .when(
24840            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
24841            |el| {
24842                el.child(
24843                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
24844                        .shape(IconButtonShape::Square)
24845                        .icon_size(IconSize::Small)
24846                        // .disabled(!has_multiple_hunks)
24847                        .tooltip({
24848                            let focus_handle = editor.focus_handle(cx);
24849                            move |_window, cx| {
24850                                Tooltip::for_action_in("Next Hunk", &GoToHunk, &focus_handle, cx)
24851                            }
24852                        })
24853                        .on_click({
24854                            let editor = editor.clone();
24855                            move |_event, window, cx| {
24856                                editor.update(cx, |editor, cx| {
24857                                    let snapshot = editor.snapshot(window, cx);
24858                                    let position =
24859                                        hunk_range.end.to_point(&snapshot.buffer_snapshot());
24860                                    editor.go_to_hunk_before_or_after_position(
24861                                        &snapshot,
24862                                        position,
24863                                        Direction::Next,
24864                                        window,
24865                                        cx,
24866                                    );
24867                                    editor.expand_selected_diff_hunks(cx);
24868                                });
24869                            }
24870                        }),
24871                )
24872                .child(
24873                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
24874                        .shape(IconButtonShape::Square)
24875                        .icon_size(IconSize::Small)
24876                        // .disabled(!has_multiple_hunks)
24877                        .tooltip({
24878                            let focus_handle = editor.focus_handle(cx);
24879                            move |_window, cx| {
24880                                Tooltip::for_action_in(
24881                                    "Previous Hunk",
24882                                    &GoToPreviousHunk,
24883                                    &focus_handle,
24884                                    cx,
24885                                )
24886                            }
24887                        })
24888                        .on_click({
24889                            let editor = editor.clone();
24890                            move |_event, window, cx| {
24891                                editor.update(cx, |editor, cx| {
24892                                    let snapshot = editor.snapshot(window, cx);
24893                                    let point =
24894                                        hunk_range.start.to_point(&snapshot.buffer_snapshot());
24895                                    editor.go_to_hunk_before_or_after_position(
24896                                        &snapshot,
24897                                        point,
24898                                        Direction::Prev,
24899                                        window,
24900                                        cx,
24901                                    );
24902                                    editor.expand_selected_diff_hunks(cx);
24903                                });
24904                            }
24905                        }),
24906                )
24907            },
24908        )
24909        .into_any_element()
24910}
24911
24912pub fn multibuffer_context_lines(cx: &App) -> u32 {
24913    EditorSettings::try_get(cx)
24914        .map(|settings| settings.excerpt_context_lines)
24915        .unwrap_or(2)
24916        .min(32)
24917}